From efda2e9baa54945391a7c7c155e67e9ffc67a82e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Sat, 2 Mar 2024 18:34:49 +0900
Subject: [PATCH 001/218] Update README.md
---
README.md | 41 ++++-------------------------------------
1 file changed, 4 insertions(+), 37 deletions(-)
diff --git a/README.md b/README.md
index 6fa804f1fa..24013a7bd8 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,11 @@
-
+
-**🌎 **[Misskey](https://misskey-hub.net/)** is an open source, decentralized social media platform that's free forever! 🚀**
+**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀**
+
+[Learn more](https://misskey-hub.net/)
---
@@ -22,41 +24,6 @@
----
-
-[![codecov](https://codecov.io/gh/misskey-dev/misskey/branch/develop/graph/badge.svg?token=R6IQZ3QJOL)](https://codecov.io/gh/misskey-dev/misskey)
-
-
-
-
-
-
-
-## ✨ Features
-- **ActivityPub support**\
-Not on Misskey? No problem! Not only can Misskey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed!
-- **Reactions**\
-You can add emoji reactions to any post! No longer are you bound by a like button, show everyone exactly how you feel with the tap of a button.
-- **Drive**\
-With Misskey's built in drive, you get cloud storage right in your social media, where you can upload any files, make folders, and find media from posts you've made!
-- **Rich Web UI**\
- Misskey has a rich and easy to use Web UI!
- It is highly customizable, from changing the layout and adding widgets to making custom themes.
- Furthermore, plugins can be created using AiScript, an original programming language.
-- And much more...
-
-
-
-
-
-## Documentation
-
-Misskey Documentation can be found at [Misskey Hub](https://misskey-hub.net/docs/), some of the links and graphics above also lead to specific portions of it.
-
-## Sponsors
-
-
-
## Thanks
From 38837bd388621f5ba49bd7bf0f657a08ec2f19c4 Mon Sep 17 00:00:00 2001
From: zyoshoka <107108195+zyoshoka@users.noreply.github.com>
Date: Sun, 3 Mar 2024 20:15:35 +0900
Subject: [PATCH 002/218] test(backend): refactor tests (#13499)
* test(backend): refactor tests
* fix: failed test
---
packages/backend/test/e2e/2fa.ts | 96 ++--
packages/backend/test/e2e/antennas.ts | 116 +++--
packages/backend/test/e2e/api-visibility.ts | 74 +--
packages/backend/test/e2e/api.ts | 43 +-
packages/backend/test/e2e/block.ts | 19 +-
packages/backend/test/e2e/clips.ts | 298 ++++++-----
packages/backend/test/e2e/drive.ts | 36 +-
packages/backend/test/e2e/endpoints.ts | 261 +++++-----
packages/backend/test/e2e/exports.ts | 38 +-
packages/backend/test/e2e/fetch-resource.ts | 18 +-
packages/backend/test/e2e/ff-visibility.ts | 206 ++++----
packages/backend/test/e2e/move.ts | 186 +++----
packages/backend/test/e2e/mute.ts | 87 ++--
packages/backend/test/e2e/note.ts | 169 +++----
packages/backend/test/e2e/renote-mute.ts | 6 +-
packages/backend/test/e2e/streaming.ts | 6 +-
packages/backend/test/e2e/thread-mute.ts | 18 +-
packages/backend/test/e2e/timelines.ts | 336 ++++++-------
packages/backend/test/e2e/user-notes.ts | 8 +-
packages/backend/test/e2e/users.ts | 461 +++++++++---------
.../backend/test/unit/AnnouncementService.ts | 2 +-
.../test/unit/FetchInstanceMetadataService.ts | 19 +-
packages/backend/test/unit/RoleService.ts | 3 +
packages/backend/test/utils.ts | 61 ++-
24 files changed, 1270 insertions(+), 1297 deletions(-)
diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts
index 87a3c227d6..13c56b88a6 100644
--- a/packages/backend/test/e2e/2fa.ts
+++ b/packages/backend/test/e2e/2fa.ts
@@ -187,7 +187,7 @@ describe('2要素認証', () => {
}, 1000 * 60 * 2);
test('が設定でき、OTPでログインできる。', async () => {
- const registerResponse = await api('/i/2fa/register', {
+ const registerResponse = await api('i/2fa/register', {
password,
}, alice);
assert.strictEqual(registerResponse.status, 200);
@@ -197,18 +197,18 @@ describe('2要素認証', () => {
assert.strictEqual(registerResponse.body.label, username);
assert.strictEqual(registerResponse.body.issuer, config.host);
- const doneResponse = await api('/i/2fa/done', {
+ const doneResponse = await api('i/2fa/done', {
token: otpToken(registerResponse.body.secret),
}, alice);
assert.strictEqual(doneResponse.status, 200);
- const usersShowResponse = await api('/users/show', {
+ const usersShowResponse = await api('users/show', {
username,
}, alice);
assert.strictEqual(usersShowResponse.status, 200);
assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
- const signinResponse = await api('/signin', {
+ const signinResponse = await api('signin', {
...signinParam(),
token: otpToken(registerResponse.body.secret),
});
@@ -216,24 +216,24 @@ describe('2要素認証', () => {
assert.notEqual(signinResponse.body.i, undefined);
// 後片付け
- await api('/i/2fa/unregister', {
+ await api('i/2fa/unregister', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
});
test('が設定でき、セキュリティキーでログインできる。', async () => {
- const registerResponse = await api('/i/2fa/register', {
+ const registerResponse = await api('i/2fa/register', {
password,
}, alice);
assert.strictEqual(registerResponse.status, 200);
- const doneResponse = await api('/i/2fa/done', {
+ const doneResponse = await api('i/2fa/done', {
token: otpToken(registerResponse.body.secret),
}, alice);
assert.strictEqual(doneResponse.status, 200);
- const registerKeyResponse = await api('/i/2fa/register-key', {
+ const registerKeyResponse = await api('i/2fa/register-key', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
@@ -243,23 +243,23 @@ describe('2要素認証', () => {
const keyName = 'example-key';
const credentialId = crypto.randomBytes(0x41);
- const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+ const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
token: otpToken(registerResponse.body.secret),
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }), alice);
+ }) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url'));
assert.strictEqual(keyDoneResponse.body.name, keyName);
- const usersShowResponse = await api('/users/show', {
+ const usersShowResponse = await api('users/show', {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
assert.strictEqual(usersShowResponse.body.securityKeys, true);
- const signinResponse = await api('/signin', {
+ const signinResponse = await api('signin', {
...signinParam(),
});
assert.strictEqual(signinResponse.status, 200);
@@ -268,7 +268,7 @@ describe('2要素認証', () => {
assert.notEqual(signinResponse.body.allowCredentials, undefined);
assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url'));
- const signinResponse2 = await api('/signin', signinWithSecurityKeyParam({
+ const signinResponse2 = await api('signin', signinWithSecurityKeyParam({
keyName,
credentialId,
requestOptions: signinResponse.body,
@@ -277,24 +277,24 @@ describe('2要素認証', () => {
assert.notEqual(signinResponse2.body.i, undefined);
// 後片付け
- await api('/i/2fa/unregister', {
+ await api('i/2fa/unregister', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
});
test('が設定でき、セキュリティキーでパスワードレスログインできる。', async () => {
- const registerResponse = await api('/i/2fa/register', {
+ const registerResponse = await api('i/2fa/register', {
password,
}, alice);
assert.strictEqual(registerResponse.status, 200);
- const doneResponse = await api('/i/2fa/done', {
+ const doneResponse = await api('i/2fa/done', {
token: otpToken(registerResponse.body.secret),
}, alice);
assert.strictEqual(doneResponse.status, 200);
- const registerKeyResponse = await api('/i/2fa/register-key', {
+ const registerKeyResponse = await api('i/2fa/register-key', {
token: otpToken(registerResponse.body.secret),
password,
}, alice);
@@ -302,33 +302,33 @@ describe('2要素認証', () => {
const keyName = 'example-key';
const credentialId = crypto.randomBytes(0x41);
- const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+ const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
token: otpToken(registerResponse.body.secret),
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }), alice);
+ }) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
- const passwordLessResponse = await api('/i/2fa/password-less', {
+ const passwordLessResponse = await api('i/2fa/password-less', {
value: true,
}, alice);
assert.strictEqual(passwordLessResponse.status, 204);
- const usersShowResponse = await api('/users/show', {
+ const usersShowResponse = await api('users/show', {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true);
- const signinResponse = await api('/signin', {
+ const signinResponse = await api('signin', {
...signinParam(),
password: '',
});
assert.strictEqual(signinResponse.status, 200);
assert.strictEqual(signinResponse.body.i, undefined);
- const signinResponse2 = await api('/signin', {
+ const signinResponse2 = await api('signin', {
...signinWithSecurityKeyParam({
keyName,
credentialId,
@@ -340,24 +340,24 @@ describe('2要素認証', () => {
assert.notEqual(signinResponse2.body.i, undefined);
// 後片付け
- await api('/i/2fa/unregister', {
+ await api('i/2fa/unregister', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
});
test('が設定でき、設定したセキュリティキーの名前を変更できる。', async () => {
- const registerResponse = await api('/i/2fa/register', {
+ const registerResponse = await api('i/2fa/register', {
password,
}, alice);
assert.strictEqual(registerResponse.status, 200);
- const doneResponse = await api('/i/2fa/done', {
+ const doneResponse = await api('i/2fa/done', {
token: otpToken(registerResponse.body.secret),
}, alice);
assert.strictEqual(doneResponse.status, 200);
- const registerKeyResponse = await api('/i/2fa/register-key', {
+ const registerKeyResponse = await api('i/2fa/register-key', {
token: otpToken(registerResponse.body.secret),
password,
}, alice);
@@ -365,22 +365,22 @@ describe('2要素認証', () => {
const keyName = 'example-key';
const credentialId = crypto.randomBytes(0x41);
- const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+ const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
token: otpToken(registerResponse.body.secret),
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }), alice);
+ }) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
const renamedKey = 'other-key';
- const updateKeyResponse = await api('/i/2fa/update-key', {
+ const updateKeyResponse = await api('i/2fa/update-key', {
name: renamedKey,
credentialId: credentialId.toString('base64url'),
}, alice);
assert.strictEqual(updateKeyResponse.status, 200);
- const iResponse = await api('/i', {
+ const iResponse = await api('i', {
}, alice);
assert.strictEqual(iResponse.status, 200);
const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url'));
@@ -389,24 +389,24 @@ describe('2要素認証', () => {
assert.notEqual(securityKeys[0].lastUsed, undefined);
// 後片付け
- await api('/i/2fa/unregister', {
+ await api('i/2fa/unregister', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
});
test('が設定でき、設定したセキュリティキーを削除できる。', async () => {
- const registerResponse = await api('/i/2fa/register', {
+ const registerResponse = await api('i/2fa/register', {
password,
}, alice);
assert.strictEqual(registerResponse.status, 200);
- const doneResponse = await api('/i/2fa/done', {
+ const doneResponse = await api('i/2fa/done', {
token: otpToken(registerResponse.body.secret),
}, alice);
assert.strictEqual(doneResponse.status, 200);
- const registerKeyResponse = await api('/i/2fa/register-key', {
+ const registerKeyResponse = await api('i/2fa/register-key', {
token: otpToken(registerResponse.body.secret),
password,
}, alice);
@@ -414,20 +414,20 @@ describe('2要素認証', () => {
const keyName = 'example-key';
const credentialId = crypto.randomBytes(0x41);
- const keyDoneResponse = await api('/i/2fa/key-done', keyDoneParam({
+ const keyDoneResponse = await api('i/2fa/key-done', keyDoneParam({
token: otpToken(registerResponse.body.secret),
keyName,
credentialId,
creationOptions: registerKeyResponse.body,
- }), alice);
+ }) as any, alice);
assert.strictEqual(keyDoneResponse.status, 200);
// テストの実行順によっては複数残ってるので全部消す
- const iResponse = await api('/i', {
+ const iResponse = await api('i', {
}, alice);
assert.strictEqual(iResponse.status, 200);
for (const key of iResponse.body.securityKeysList) {
- const removeKeyResponse = await api('/i/2fa/remove-key', {
+ const removeKeyResponse = await api('i/2fa/remove-key', {
token: otpToken(registerResponse.body.secret),
password,
credentialId: key.id,
@@ -435,13 +435,13 @@ describe('2要素認証', () => {
assert.strictEqual(removeKeyResponse.status, 200);
}
- const usersShowResponse = await api('/users/show', {
+ const usersShowResponse = await api('users/show', {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
assert.strictEqual(usersShowResponse.body.securityKeys, false);
- const signinResponse = await api('/signin', {
+ const signinResponse = await api('signin', {
...signinParam(),
token: otpToken(registerResponse.body.secret),
});
@@ -449,43 +449,43 @@ describe('2要素認証', () => {
assert.notEqual(signinResponse.body.i, undefined);
// 後片付け
- await api('/i/2fa/unregister', {
+ await api('i/2fa/unregister', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
});
test('が設定でき、設定解除できる。(パスワードのみでログインできる。)', async () => {
- const registerResponse = await api('/i/2fa/register', {
+ const registerResponse = await api('i/2fa/register', {
password,
}, alice);
assert.strictEqual(registerResponse.status, 200);
- const doneResponse = await api('/i/2fa/done', {
+ const doneResponse = await api('i/2fa/done', {
token: otpToken(registerResponse.body.secret),
}, alice);
assert.strictEqual(doneResponse.status, 200);
- const usersShowResponse = await api('/users/show', {
+ const usersShowResponse = await api('users/show', {
username,
});
assert.strictEqual(usersShowResponse.status, 200);
assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true);
- const unregisterResponse = await api('/i/2fa/unregister', {
+ const unregisterResponse = await api('i/2fa/unregister', {
token: otpToken(registerResponse.body.secret),
password,
}, alice);
assert.strictEqual(unregisterResponse.status, 204);
- const signinResponse = await api('/signin', {
+ const signinResponse = await api('signin', {
...signinParam(),
});
assert.strictEqual(signinResponse.status, 200);
assert.notEqual(signinResponse.body.i, undefined);
// 後片付け
- await api('/i/2fa/unregister', {
+ await api('i/2fa/unregister', {
password,
token: otpToken(registerResponse.body.secret),
}, alice);
diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts
index 1a9d5bf1f0..7370b1963c 100644
--- a/packages/backend/test/e2e/antennas.ts
+++ b/packages/backend/test/e2e/antennas.ts
@@ -7,7 +7,6 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import type { Packed } from '@/misc/json-schema.js';
import {
api,
failedApiCall,
@@ -29,10 +28,7 @@ describe('アンテナ', () => {
// エンティティとしてのアンテナを主眼においたテストを記述する
// (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからノートを取得するエンドポイントをテストする)
- // BUG misskey-jsとjson-schemaが一致していない。
- // - srcのenumにgroupが残っている
- // - userGroupIdが残っている, isActiveがない
- type Antenna = misskey.entities.Antenna | Packed<'Antenna'>;
+ type Antenna = misskey.entities.Antenna;
type User = misskey.entities.SignupResponse;
type Note = misskey.entities.Note;
@@ -80,7 +76,7 @@ describe('アンテナ', () => {
aliceList = await userList(alice, {});
bob = await signup({ username: 'bob' });
aliceList = await userList(alice, {});
- bobFile = (await uploadFile(bob)).body;
+ bobFile = (await uploadFile(bob)).body!;
bobList = await userList(bob);
carol = await signup({ username: 'carol' });
await api('users/lists/push', { listId: aliceList.id, userId: bob.id }, alice);
@@ -129,9 +125,9 @@ describe('アンテナ', () => {
beforeEach(async () => {
// テスト間で影響し合わないように毎回全部消す。
for (const user of [alice, bob]) {
- const list = await api('/antennas/list', {}, user);
+ const list = await api('antennas/list', {}, user);
for (const antenna of list.body) {
- await api('/antennas/delete', { antennaId: antenna.id }, user);
+ await api('antennas/delete', { antennaId: antenna.id }, user);
}
}
});
@@ -141,11 +137,11 @@ describe('アンテナ', () => {
test('が作成できること、キーが過不足なく入っていること。', async () => {
const response = await successfulApiCall({
endpoint: 'antennas/create',
- parameters: { ...defaultParam },
+ parameters: defaultParam,
user: alice,
});
assert.match(response.id, /[0-9a-z]{10}/);
- const expected = {
+ const expected: Antenna = {
id: response.id,
caseSensitive: false,
createdAt: new Date(response.createdAt).toISOString(),
@@ -161,7 +157,7 @@ describe('アンテナ', () => {
withFile: false,
withReplies: false,
localOnly: false,
- } as Antenna;
+ };
assert.deepStrictEqual(response, expected);
});
@@ -202,27 +198,27 @@ describe('アンテナ', () => {
});
const antennaParamPattern = [
- { parameters: (): object => ({ name: 'x'.repeat(100) }) },
- { parameters: (): object => ({ name: 'x' }) },
- { parameters: (): object => ({ src: 'home' }) },
- { parameters: (): object => ({ src: 'all' }) },
- { parameters: (): object => ({ src: 'users' }) },
- { parameters: (): object => ({ src: 'list' }) },
- { parameters: (): object => ({ userListId: null }) },
- { parameters: (): object => ({ src: 'list', userListId: aliceList.id }) },
- { parameters: (): object => ({ keywords: [['x']] }) },
- { parameters: (): object => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
- { parameters: (): object => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
- { parameters: (): object => ({ users: [alice.username] }) },
- { parameters: (): object => ({ users: [alice.username, bob.username, carol.username] }) },
- { parameters: (): object => ({ caseSensitive: false }) },
- { parameters: (): object => ({ caseSensitive: true }) },
- { parameters: (): object => ({ withReplies: false }) },
- { parameters: (): object => ({ withReplies: true }) },
- { parameters: (): object => ({ withFile: false }) },
- { parameters: (): object => ({ withFile: true }) },
- { parameters: (): object => ({ notify: false }) },
- { parameters: (): object => ({ notify: true }) },
+ { parameters: () => ({ name: 'x'.repeat(100) }) },
+ { parameters: () => ({ name: 'x' }) },
+ { parameters: () => ({ src: 'home' as const }) },
+ { parameters: () => ({ src: 'all' as const }) },
+ { parameters: () => ({ src: 'users' as const }) },
+ { parameters: () => ({ src: 'list' as const }) },
+ { parameters: () => ({ userListId: null }) },
+ { parameters: () => ({ src: 'list' as const, userListId: aliceList.id }) },
+ { parameters: () => ({ keywords: [['x']] }) },
+ { parameters: () => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
+ { parameters: () => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) },
+ { parameters: () => ({ users: [alice.username] }) },
+ { parameters: () => ({ users: [alice.username, bob.username, carol.username] }) },
+ { parameters: () => ({ caseSensitive: false }) },
+ { parameters: () => ({ caseSensitive: true }) },
+ { parameters: () => ({ withReplies: false }) },
+ { parameters: () => ({ withReplies: true }) },
+ { parameters: () => ({ withFile: false }) },
+ { parameters: () => ({ withFile: true }) },
+ { parameters: () => ({ notify: false }) },
+ { parameters: () => ({ notify: true }) },
];
test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
const response = await successfulApiCall({
@@ -335,7 +331,7 @@ describe('アンテナ', () => {
test.each([
{
label: '全体から',
- parameters: (): object => ({ src: 'all' }),
+ parameters: () => ({ src: 'all' }),
posts: [
{ note: (): Promise => post(alice, { text: `${keyword}` }), included: true },
{ note: (): Promise => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
@@ -346,7 +342,7 @@ describe('アンテナ', () => {
{
// BUG e4144a1 以降home指定は壊れている(allと同じ)
label: 'ホーム指定はallと同じ',
- parameters: (): object => ({ src: 'home' }),
+ parameters: () => ({ src: 'home' }),
posts: [
{ note: (): Promise => post(alice, { text: `${keyword}` }), included: true },
{ note: (): Promise => post(userFollowedByAlice, { text: `${keyword}` }), included: true },
@@ -357,7 +353,7 @@ describe('アンテナ', () => {
{
// https://github.com/misskey-dev/misskey/issues/9025
label: 'ただし、フォロワー限定投稿とDM投稿を含まない。フォロワーであっても。',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'public' }), included: true },
{ note: (): Promise => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'home' }), included: true },
@@ -367,56 +363,56 @@ describe('アンテナ', () => {
},
{
label: 'ブロックしているユーザーのノートは含む',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userBlockedByAlice, { text: `${keyword}` }), included: true },
],
},
{
label: 'ブロックされているユーザーのノートは含まない',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userBlockingAlice, { text: `${keyword}` }) },
],
},
{
label: 'ミュートしているユーザーのノートは含まない',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userMutedByAlice, { text: `${keyword}` }) },
],
},
{
label: 'ミュートされているユーザーのノートは含む',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userMutingAlice, { text: `${keyword}` }), included: true },
],
},
{
label: '「見つけやすくする」がOFFのユーザーのノートも含まれる',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userNotExplorable, { text: `${keyword}` }), included: true },
],
},
{
label: '鍵付きユーザーのノートも含まれる',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userLocking, { text: `${keyword}` }), included: true },
],
},
{
label: 'サイレンスのノートも含まれる',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userSilenced, { text: `${keyword}` }), included: true },
],
},
{
label: '削除ユーザーのノートも含まれる',
- parameters: (): object => ({}),
+ parameters: () => ({}),
posts: [
{ note: (): Promise => post(userDeletedBySelf, { text: `${keyword}` }), included: true },
{ note: (): Promise => post(userDeletedByAdmin, { text: `${keyword}` }), included: true },
@@ -424,7 +420,7 @@ describe('アンテナ', () => {
},
{
label: 'ユーザー指定で',
- parameters: (): object => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }),
+ parameters: () => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }),
posts: [
{ note: (): Promise => post(alice, { text: `test ${keyword}` }) },
{ note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true },
@@ -433,7 +429,7 @@ describe('アンテナ', () => {
},
{
label: 'リスト指定で',
- parameters: (): object => ({ src: 'list', userListId: aliceList.id }),
+ parameters: () => ({ src: 'list', userListId: aliceList.id }),
posts: [
{ note: (): Promise => post(alice, { text: `test ${keyword}` }) },
{ note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true },
@@ -442,14 +438,14 @@ describe('アンテナ', () => {
},
{
label: 'CWにもマッチする',
- parameters: (): object => ({ keywords: [[keyword]] }),
+ parameters: () => ({ keywords: [[keyword]] }),
posts: [
{ note: (): Promise => post(bob, { text: 'test', cw: `cw ${keyword}` }), included: true },
],
},
{
label: 'キーワード1つ',
- parameters: (): object => ({ keywords: [[keyword]] }),
+ parameters: () => ({ keywords: [[keyword]] }),
posts: [
{ note: (): Promise => post(alice, { text: 'test' }) },
{ note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true },
@@ -458,7 +454,7 @@ describe('アンテナ', () => {
},
{
label: 'キーワード3つ(AND)',
- parameters: (): object => ({ keywords: [['A', 'B', 'C']] }),
+ parameters: () => ({ keywords: [['A', 'B', 'C']] }),
posts: [
{ note: (): Promise => post(bob, { text: 'test A' }) },
{ note: (): Promise => post(bob, { text: 'test A B' }) },
@@ -469,7 +465,7 @@ describe('アンテナ', () => {
},
{
label: 'キーワード3つ(OR)',
- parameters: (): object => ({ keywords: [['A'], ['B'], ['C']] }),
+ parameters: () => ({ keywords: [['A'], ['B'], ['C']] }),
posts: [
{ note: (): Promise => post(bob, { text: 'test' }) },
{ note: (): Promise => post(bob, { text: 'test A' }), included: true },
@@ -482,7 +478,7 @@ describe('アンテナ', () => {
},
{
label: '除外ワード3つ(AND)',
- parameters: (): object => ({ excludeKeywords: [['A', 'B', 'C']] }),
+ parameters: () => ({ excludeKeywords: [['A', 'B', 'C']] }),
posts: [
{ note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true },
{ note: (): Promise => post(bob, { text: `test ${keyword} A` }), included: true },
@@ -495,7 +491,7 @@ describe('アンテナ', () => {
},
{
label: '除外ワード3つ(OR)',
- parameters: (): object => ({ excludeKeywords: [['A'], ['B'], ['C']] }),
+ parameters: () => ({ excludeKeywords: [['A'], ['B'], ['C']] }),
posts: [
{ note: (): Promise => post(bob, { text: `test ${keyword}` }), included: true },
{ note: (): Promise => post(bob, { text: `test ${keyword} A` }) },
@@ -508,7 +504,7 @@ describe('アンテナ', () => {
},
{
label: 'キーワード1つ(大文字小文字区別する)',
- parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: true }),
+ parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: true }),
posts: [
{ note: (): Promise => post(bob, { text: 'keyword' }) },
{ note: (): Promise => post(bob, { text: 'kEyWoRd' }) },
@@ -517,7 +513,7 @@ describe('アンテナ', () => {
},
{
label: 'キーワード1つ(大文字小文字区別しない)',
- parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: false }),
+ parameters: () => ({ keywords: [['KEYWORD']], caseSensitive: false }),
posts: [
{ note: (): Promise => post(bob, { text: 'keyword' }), included: true },
{ note: (): Promise => post(bob, { text: 'kEyWoRd' }), included: true },
@@ -526,7 +522,7 @@ describe('アンテナ', () => {
},
{
label: '除外ワード1つ(大文字小文字区別する)',
- parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }),
+ parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }),
posts: [
{ note: (): Promise => post(bob, { text: `${keyword}` }), included: true },
{ note: (): Promise => post(bob, { text: `${keyword} keyword` }), included: true },
@@ -536,7 +532,7 @@ describe('アンテナ', () => {
},
{
label: '除外ワード1つ(大文字小文字区別しない)',
- parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }),
+ parameters: () => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }),
posts: [
{ note: (): Promise => post(bob, { text: `${keyword}` }), included: true },
{ note: (): Promise => post(bob, { text: `${keyword} keyword` }) },
@@ -546,7 +542,7 @@ describe('アンテナ', () => {
},
{
label: '添付ファイルを問わない',
- parameters: (): object => ({ withFile: false }),
+ parameters: () => ({ withFile: false }),
posts: [
{ note: (): Promise => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
{ note: (): Promise => post(bob, { text: `${keyword}` }), included: true },
@@ -554,7 +550,7 @@ describe('アンテナ', () => {
},
{
label: '添付ファイル付きのみ',
- parameters: (): object => ({ withFile: true }),
+ parameters: () => ({ withFile: true }),
posts: [
{ note: (): Promise => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true },
{ note: (): Promise => post(bob, { text: `${keyword}` }) },
@@ -562,7 +558,7 @@ describe('アンテナ', () => {
},
{
label: 'リプライ以外',
- parameters: (): object => ({ withReplies: false }),
+ parameters: () => ({ withReplies: false }),
posts: [
{ note: (): Promise => post(bob, { text: `${keyword}`, replyId: alicePost.id }) },
{ note: (): Promise => post(bob, { text: `${keyword}` }), included: true },
@@ -570,7 +566,7 @@ describe('アンテナ', () => {
},
{
label: 'リプライも含む',
- parameters: (): object => ({ withReplies: true }),
+ parameters: () => ({ withReplies: true }),
posts: [
{ note: (): Promise => post(bob, { text: `${keyword}`, replyId: alicePost.id }), included: true },
{ note: (): Promise => post(bob, { text: `${keyword}` }), included: true },
@@ -633,7 +629,7 @@ describe('アンテナ', () => {
endpoint: 'antennas/notes',
parameters: { antennaId: antenna.id, ...paginationParam },
user: alice,
- }) as any as Note[];
+ });
}, offsetBy, 'desc');
});
diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts
index f92384525c..c61b0c2a86 100644
--- a/packages/backend/test/e2e/api-visibility.ts
+++ b/packages/backend/test/e2e/api-visibility.ts
@@ -6,7 +6,7 @@
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
-import { api, post, signup } from '../utils.js';
+import { UserToken, api, post, signup } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('API visibility', () => {
@@ -24,38 +24,38 @@ describe('API visibility', () => {
let target2: misskey.entities.SignupResponse;
/** public-post */
- let pub: any;
+ let pub: misskey.entities.Note;
/** home-post */
- let home: any;
+ let home: misskey.entities.Note;
/** followers-post */
- let fol: any;
+ let fol: misskey.entities.Note;
/** specified-post */
- let spe: any;
+ let spe: misskey.entities.Note;
/** public-reply to target's post */
- let pubR: any;
+ let pubR: misskey.entities.Note;
/** home-reply to target's post */
- let homeR: any;
+ let homeR: misskey.entities.Note;
/** followers-reply to target's post */
- let folR: any;
+ let folR: misskey.entities.Note;
/** specified-reply to target's post */
- let speR: any;
+ let speR: misskey.entities.Note;
/** public-mention to target */
- let pubM: any;
+ let pubM: misskey.entities.Note;
/** home-mention to target */
- let homeM: any;
+ let homeM: misskey.entities.Note;
/** followers-mention to target */
- let folM: any;
+ let folM: misskey.entities.Note;
/** specified-mention to target */
- let speM: any;
+ let speM: misskey.entities.Note;
/** reply target post */
- let tgt: any;
+ let tgt: misskey.entities.Note;
//#endregion
- const show = async (noteId: any, by: any) => {
- return await api('/notes/show', {
+ const show = async (noteId: misskey.entities.Note['id'], by?: UserToken) => {
+ return await api('notes/show', {
noteId,
}, by);
};
@@ -70,7 +70,7 @@ describe('API visibility', () => {
target2 = await signup({ username: 'target2' });
// follow alice <= follower
- await api('/following/create', { userId: alice.id }, follower);
+ await api('following/create', { userId: alice.id }, follower);
// normal posts
pub = await post(alice, { text: 'x', visibility: 'public' });
@@ -111,7 +111,7 @@ describe('API visibility', () => {
});
test('[show] public-postを未認証が見れる', async () => {
- const res = await show(pub.id, null);
+ const res = await show(pub.id);
assert.strictEqual(res.body.text, 'x');
});
@@ -132,7 +132,7 @@ describe('API visibility', () => {
});
test('[show] home-postを未認証が見れる', async () => {
- const res = await show(home.id, null);
+ const res = await show(home.id);
assert.strictEqual(res.body.text, 'x');
});
@@ -153,7 +153,7 @@ describe('API visibility', () => {
});
test('[show] followers-postを未認証が見れない', async () => {
- const res = await show(fol.id, null);
+ const res = await show(fol.id);
assert.strictEqual(res.body.isHidden, true);
});
@@ -179,7 +179,7 @@ describe('API visibility', () => {
});
test('[show] specified-postを未認証が見れない', async () => {
- const res = await show(spe.id, null);
+ const res = await show(spe.id);
assert.strictEqual(res.body.isHidden, true);
});
//#endregion
@@ -207,7 +207,7 @@ describe('API visibility', () => {
});
test('[show] public-replyを未認証が見れる', async () => {
- const res = await show(pubR.id, null);
+ const res = await show(pubR.id);
assert.strictEqual(res.body.text, 'x');
});
@@ -233,7 +233,7 @@ describe('API visibility', () => {
});
test('[show] home-replyを未認証が見れる', async () => {
- const res = await show(homeR.id, null);
+ const res = await show(homeR.id);
assert.strictEqual(res.body.text, 'x');
});
@@ -259,7 +259,7 @@ describe('API visibility', () => {
});
test('[show] followers-replyを未認証が見れない', async () => {
- const res = await show(folR.id, null);
+ const res = await show(folR.id);
assert.strictEqual(res.body.isHidden, true);
});
@@ -290,7 +290,7 @@ describe('API visibility', () => {
});
test('[show] specified-replyを未認証が見れない', async () => {
- const res = await show(speR.id, null);
+ const res = await show(speR.id);
assert.strictEqual(res.body.isHidden, true);
});
//#endregion
@@ -318,7 +318,7 @@ describe('API visibility', () => {
});
test('[show] public-mentionを未認証が見れる', async () => {
- const res = await show(pubM.id, null);
+ const res = await show(pubM.id);
assert.strictEqual(res.body.text, '@target x');
});
@@ -344,7 +344,7 @@ describe('API visibility', () => {
});
test('[show] home-mentionを未認証が見れる', async () => {
- const res = await show(homeM.id, null);
+ const res = await show(homeM.id);
assert.strictEqual(res.body.text, '@target x');
});
@@ -370,7 +370,7 @@ describe('API visibility', () => {
});
test('[show] followers-mentionを未認証が見れない', async () => {
- const res = await show(folM.id, null);
+ const res = await show(folM.id);
assert.strictEqual(res.body.isHidden, true);
});
@@ -401,28 +401,28 @@ describe('API visibility', () => {
});
test('[show] specified-mentionを未認証が見れない', async () => {
- const res = await show(speM.id, null);
+ const res = await show(speM.id);
assert.strictEqual(res.body.isHidden, true);
});
//#endregion
//#region HTL
test('[HTL] public-post が 自分が見れる', async () => {
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === pub.id);
assert.strictEqual(notes[0].text, 'x');
});
test('[HTL] public-post が 非フォロワーから見れない', async () => {
- const res = await api('/notes/timeline', { limit: 100 }, other);
+ const res = await api('notes/timeline', { limit: 100 }, other);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === pub.id);
assert.strictEqual(notes.length, 0);
});
test('[HTL] followers-post が フォロワーから見れる', async () => {
- const res = await api('/notes/timeline', { limit: 100 }, follower);
+ const res = await api('notes/timeline', { limit: 100 }, follower);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === fol.id);
assert.strictEqual(notes[0].text, 'x');
@@ -431,21 +431,21 @@ describe('API visibility', () => {
//#region RTL
test('[replies] followers-reply が フォロワーから見れる', async () => {
- const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, follower);
+ const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, follower);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === folR.id);
assert.strictEqual(notes[0].text, 'x');
});
test('[replies] followers-reply が 非フォロワー (リプライ先ではない) から見れない', async () => {
- const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, other);
+ const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, other);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === folR.id);
assert.strictEqual(notes.length, 0);
});
test('[replies] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
- const res = await api('/notes/replies', { noteId: tgt.id, limit: 100 }, target);
+ const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, target);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === folR.id);
assert.strictEqual(notes[0].text, 'x');
@@ -454,14 +454,14 @@ describe('API visibility', () => {
//#region MTL
test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
- const res = await api('/notes/mentions', { limit: 100 }, target);
+ const res = await api('notes/mentions', { limit: 100 }, target);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === folR.id);
assert.strictEqual(notes[0].text, 'x');
});
test('[mentions] followers-mention が 非フォロワー (メンション先である) から見れる', async () => {
- const res = await api('/notes/mentions', { limit: 100 }, target);
+ const res = await api('notes/mentions', { limit: 100 }, target);
assert.strictEqual(res.status, 200);
const notes = res.body.filter((n: any) => n.id === folM.id);
assert.strictEqual(notes[0].text, '@target x');
diff --git a/packages/backend/test/e2e/api.ts b/packages/backend/test/e2e/api.ts
index b6eeec99d7..49c6a0636b 100644
--- a/packages/backend/test/e2e/api.ts
+++ b/packages/backend/test/e2e/api.ts
@@ -23,32 +23,32 @@ import type * as misskey from 'misskey-js';
describe('API', () => {
let alice: misskey.entities.SignupResponse;
let bob: misskey.entities.SignupResponse;
- let carol: misskey.entities.SignupResponse;
beforeAll(async () => {
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });
- carol = await signup({ username: 'carol' });
}, 1000 * 60 * 2);
describe('General validation', () => {
test('wrong type', async () => {
- const res = await api('/test', {
+ const res = await api('test', {
required: true,
+ // @ts-expect-error string must be string
string: 42,
});
assert.strictEqual(res.status, 400);
});
test('missing require param', async () => {
- const res = await api('/test', {
+ // @ts-expect-error required is required
+ const res = await api('test', {
string: 'a',
});
assert.strictEqual(res.status, 400);
});
test('invalid misskey:id (empty string)', async () => {
- const res = await api('/test', {
+ const res = await api('test', {
required: true,
id: '',
});
@@ -56,7 +56,7 @@ describe('API', () => {
});
test('valid misskey:id', async () => {
- const res = await api('/test', {
+ const res = await api('test', {
required: true,
id: '8wvhjghbxu',
});
@@ -64,7 +64,7 @@ describe('API', () => {
});
test('default value', async () => {
- const res = await api('/test', {
+ const res = await api('test', {
required: true,
string: 'a',
});
@@ -73,7 +73,7 @@ describe('API', () => {
});
test('can set null even if it has default value', async () => {
- const res = await api('/test', {
+ const res = await api('test', {
required: true,
nullableDefault: null,
});
@@ -82,7 +82,7 @@ describe('API', () => {
});
test('cannot set undefined if it has default value', async () => {
- const res = await api('/test', {
+ const res = await api('test', {
required: true,
nullableDefault: undefined,
});
@@ -99,14 +99,14 @@ describe('API', () => {
// aliceは管理者、APIを使える
await successfulApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: alice,
});
// bobは一般ユーザーだからダメ
await failedApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: bob,
}, {
@@ -117,7 +117,7 @@ describe('API', () => {
// publicアクセスももちろんダメ
await failedApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: undefined,
}, {
@@ -128,7 +128,7 @@ describe('API', () => {
// ごまがしもダメ
await failedApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: { token: 'tsukawasete' },
}, {
@@ -138,13 +138,13 @@ describe('API', () => {
});
await successfulApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: { token: application2 },
});
await failedApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: { token: application },
}, {
@@ -154,7 +154,7 @@ describe('API', () => {
});
await failedApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: { token: application3 },
}, {
@@ -164,7 +164,7 @@ describe('API', () => {
});
await failedApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: { token: application4 },
}, {
@@ -177,7 +177,7 @@ describe('API', () => {
describe('Authentication header', () => {
test('一般リクエスト', async () => {
await successfulApiCall({
- endpoint: '/admin/get-index-stats',
+ endpoint: 'admin/get-index-stats',
parameters: {},
user: {
token: alice.token,
@@ -211,7 +211,7 @@ describe('API', () => {
describe('tokenエラー応答でWWW-Authenticate headerを送る', () => {
describe('invalid_token', () => {
test('一般リクエスト', async () => {
- const result = await api('/admin/get-index-stats', {}, {
+ const result = await api('admin/get-index-stats', {}, {
token: 'syuilo',
bearer: true,
});
@@ -246,7 +246,7 @@ describe('API', () => {
describe('tokenがないとrealmだけおくる', () => {
test('一般リクエスト', async () => {
- const result = await api('/admin/get-index-stats', {});
+ const result = await api('admin/get-index-stats', {});
assert.strictEqual(result.status, 401);
assert.strictEqual(result.headers.get('WWW-Authenticate'), 'Bearer realm="Misskey"');
});
@@ -259,7 +259,8 @@ describe('API', () => {
});
test('invalid_request', async () => {
- const result = await api('/notes/create', { text: true }, {
+ // @ts-expect-error text must be string
+ const result = await api('notes/create', { text: true }, {
token: alice.token,
bearer: true,
});
diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts
index cbd91e6e42..e4f798498f 100644
--- a/packages/backend/test/e2e/block.ts
+++ b/packages/backend/test/e2e/block.ts
@@ -22,7 +22,7 @@ describe('Block', () => {
}, 1000 * 60 * 2);
test('Block作成', async () => {
- const res = await api('/blocking/create', {
+ const res = await api('blocking/create', {
userId: bob.id,
}, alice);
@@ -30,7 +30,7 @@ describe('Block', () => {
});
test('ブロックされているユーザーをフォローできない', async () => {
- const res = await api('/following/create', { userId: alice.id }, bob);
+ const res = await api('following/create', { userId: alice.id }, bob);
assert.strictEqual(res.status, 400);
assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0');
@@ -39,7 +39,7 @@ describe('Block', () => {
test('ブロックされているユーザーにリアクションできない', async () => {
const note = await post(alice, { text: 'hello' });
- const res = await api('/notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob);
+ const res = await api('notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob);
assert.strictEqual(res.status, 400);
assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec');
@@ -48,7 +48,7 @@ describe('Block', () => {
test('ブロックされているユーザーに返信できない', async () => {
const note = await post(alice, { text: 'hello' });
- const res = await api('/notes/create', { replyId: note.id, text: 'yo' }, bob);
+ const res = await api('notes/create', { replyId: note.id, text: 'yo' }, bob);
assert.strictEqual(res.status, 400);
assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
@@ -57,7 +57,7 @@ describe('Block', () => {
test('ブロックされているユーザーのノートをRenoteできない', async () => {
const note = await post(alice, { text: 'hello' });
- const res = await api('/notes/create', { renoteId: note.id, text: 'yo' }, bob);
+ const res = await api('notes/create', { renoteId: note.id, text: 'yo' }, bob);
assert.strictEqual(res.status, 400);
assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3');
@@ -72,12 +72,13 @@ describe('Block', () => {
const bobNote = await post(bob, { text: 'hi' });
const carolNote = await post(carol, { text: 'hi' });
- const res = await api('/notes/local-timeline', {}, bob);
+ const res = await api('notes/local-timeline', {}, bob);
+ const body = res.body as misskey.entities.Note[];
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
- assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), false);
- assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
- assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
+ assert.strictEqual(body.some(note => note.id === aliceNote.id), false);
+ assert.strictEqual(body.some(note => note.id === bobNote.id), true);
+ assert.strictEqual(body.some(note => note.id === carolNote.id), true);
});
});
diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts
index 2cf397e22d..ba6f9d6a65 100644
--- a/packages/backend/test/e2e/clips.ts
+++ b/packages/backend/test/e2e/clips.ts
@@ -6,47 +6,34 @@
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
-import { JTDDataType } from 'ajv/dist/jtd';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import type { Packed } from '@/misc/json-schema.js';
-import { paramDef as CreateParamDef } from '@/server/api/endpoints/clips/create.js';
-import { paramDef as UpdateParamDef } from '@/server/api/endpoints/clips/update.js';
-import { paramDef as DeleteParamDef } from '@/server/api/endpoints/clips/delete.js';
-import { paramDef as ShowParamDef } from '@/server/api/endpoints/clips/show.js';
-import { paramDef as FavoriteParamDef } from '@/server/api/endpoints/clips/favorite.js';
-import { paramDef as UnfavoriteParamDef } from '@/server/api/endpoints/clips/unfavorite.js';
-import { paramDef as AddNoteParamDef } from '@/server/api/endpoints/clips/add-note.js';
-import { paramDef as RemoveNoteParamDef } from '@/server/api/endpoints/clips/remove-note.js';
-import { paramDef as NotesParamDef } from '@/server/api/endpoints/clips/notes.js';
import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js';
+import type * as Misskey from 'misskey-js';
+
+type Optional = Pick, K> & Omit;
describe('クリップ', () => {
- type User = Packed<'User'>;
- type Note = Packed<'Note'>;
- type Clip = Packed<'Clip'>;
-
- let alice: User;
- let bob: User;
- let aliceNote: Note;
- let aliceHomeNote: Note;
- let aliceFollowersNote: Note;
- let aliceSpecifiedNote: Note;
- let bobNote: Note;
- let bobHomeNote: Note;
- let bobFollowersNote: Note;
- let bobSpecifiedNote: Note;
+ let alice: Misskey.entities.SignupResponse;
+ let bob: Misskey.entities.SignupResponse;
+ let aliceNote: Misskey.entities.Note;
+ let aliceHomeNote: Misskey.entities.Note;
+ let aliceFollowersNote: Misskey.entities.Note;
+ let aliceSpecifiedNote: Misskey.entities.Note;
+ let bobNote: Misskey.entities.Note;
+ let bobHomeNote: Misskey.entities.Note;
+ let bobFollowersNote: Misskey.entities.Note;
+ let bobSpecifiedNote: Misskey.entities.Note;
const compareBy = (selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => {
return selector(a).localeCompare(selector(b));
};
- type CreateParam = JTDDataType;
- const defaultCreate = (): Partial => ({
+ const defaultCreate = (): Pick => ({
name: 'test',
});
- const create = async (parameters: Partial = {}, request: Partial = {}): Promise => {
- const clip = await successfulApiCall({
- endpoint: '/clips/create',
+ const create = async (parameters: Partial = {}, request: Partial> = {}): Promise => {
+ const clip = await successfulApiCall({
+ endpoint: 'clips/create',
parameters: {
...defaultCreate(),
...parameters,
@@ -64,17 +51,16 @@ describe('クリップ', () => {
return clip;
};
- const createMany = async (parameters: Partial, count = 10, user = alice): Promise => {
+ const createMany = async (parameters: Partial, count = 10, user = alice): Promise => {
return await Promise.all([...Array(count)].map((_, i) => create({
name: `test${i}`,
...parameters,
}, { user })));
};
- type UpdateParam = JTDDataType;
- const update = async (parameters: Partial, request: Partial = {}): Promise => {
- const clip = await successfulApiCall({
- endpoint: '/clips/update',
+ const update = async (parameters: Optional, request: Partial> = {}): Promise => {
+ const clip = await successfulApiCall({
+ endpoint: 'clips/update',
parameters: {
name: 'updated',
...parameters,
@@ -92,41 +78,39 @@ describe('クリップ', () => {
return clip;
};
- type DeleteParam = JTDDataType;
- const deleteClip = async (parameters: DeleteParam, request: Partial = {}): Promise => {
- return await successfulApiCall({
- endpoint: '/clips/delete',
+ const deleteClip = async (parameters: Misskey.entities.ClipsDeleteRequest, request: Partial> = {}): Promise => {
+ return await successfulApiCall({
+ endpoint: 'clips/delete',
parameters,
user: alice,
...request,
}, {
status: 204,
- });
+ }) as any as void;
};
- type ShowParam = JTDDataType;
- const show = async (parameters: ShowParam, request: Partial = {}): Promise => {
- return await successfulApiCall({
- endpoint: '/clips/show',
+ const show = async (parameters: Misskey.entities.ClipsShowRequest, request: Partial> = {}): Promise => {
+ return await successfulApiCall({
+ endpoint: 'clips/show',
parameters,
user: alice,
...request,
});
};
- const list = async (request: Partial): Promise => {
- return successfulApiCall({
- endpoint: '/clips/list',
+ const list = async (request: Partial>): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/list',
parameters: {},
user: alice,
...request,
});
};
- const usersClips = async (request: Partial): Promise => {
- return await successfulApiCall({
- endpoint: '/users/clips',
- parameters: {},
+ const usersClips = async (parameters: Misskey.entities.UsersClipsRequest, request: Partial> = {}): Promise => {
+ return await successfulApiCall({
+ endpoint: 'users/clips',
+ parameters,
user: alice,
...request,
});
@@ -136,23 +120,22 @@ describe('クリップ', () => {
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });
- // FIXME: misskey-jsのNoteはoutdatedなので直接変換できない
- aliceNote = await post(alice, { text: 'test' }) as any;
- aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' }) as any;
- aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' }) as any;
- aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' }) as any;
- bobNote = await post(bob, { text: 'test' }) as any;
- bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' }) as any;
- bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' }) as any;
- bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }) as any;
+ aliceNote = await post(alice, { text: 'test' });
+ aliceHomeNote = await post(alice, { text: 'home only', visibility: 'home' });
+ aliceFollowersNote = await post(alice, { text: 'followers only', visibility: 'followers' });
+ aliceSpecifiedNote = await post(alice, { text: 'specified only', visibility: 'specified' });
+ bobNote = await post(bob, { text: 'test' });
+ bobHomeNote = await post(bob, { text: 'home only', visibility: 'home' });
+ bobFollowersNote = await post(bob, { text: 'followers only', visibility: 'followers' });
+ bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' });
}, 1000 * 60 * 2);
afterEach(async () => {
// テスト間で影響し合わないように毎回全部消す。
for (const user of [alice, bob]) {
- const list = await api('/clips/list', { limit: 11 }, user);
+ const list = await api('clips/list', { limit: 11 }, user);
for (const clip of list.body) {
- await api('/clips/delete', { clipId: clip.id }, user);
+ await api('clips/delete', { clipId: clip.id }, user);
}
}
});
@@ -177,7 +160,7 @@ describe('クリップ', () => {
}
await failedApiCall({
- endpoint: '/clips/create',
+ endpoint: 'clips/create',
parameters: defaultCreate(),
user: alice,
}, {
@@ -204,7 +187,8 @@ describe('クリップ', () => {
{ label: 'descriptionが最大長+1', parameters: { description: 'a'.repeat(2049) } },
];
test.each(createClipDenyPattern)('の作成は$labelならできない', async ({ parameters }) => failedApiCall({
- endpoint: '/clips/create',
+ endpoint: 'clips/create',
+ // @ts-expect-error invalid params
parameters: {
...defaultCreate(),
...parameters,
@@ -246,15 +230,15 @@ describe('クリップ', () => {
code: 'NO_SUCH_CLIP',
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
} },
- { label: '他人のクリップ', user: (): User => bob, assertion: {
+ { label: '他人のクリップ', user: () => bob, assertion: {
code: 'NO_SUCH_CLIP',
id: 'b4d92d70-b216-46fa-9a3f-a8c811699257',
} },
...createClipDenyPattern as any,
])('の更新は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
- endpoint: '/clips/update',
+ endpoint: 'clips/update',
parameters: {
- clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+ clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
name: 'updated',
...parameters,
},
@@ -279,14 +263,15 @@ describe('クリップ', () => {
code: 'NO_SUCH_CLIP',
id: '70ca08ba-6865-4630-b6fb-8494759aa754',
} },
- { label: '他人のクリップ', user: (): User => bob, assertion: {
+ { label: '他人のクリップ', user: () => bob, assertion: {
code: 'NO_SUCH_CLIP',
id: '70ca08ba-6865-4630-b6fb-8494759aa754',
} },
])('の削除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
- endpoint: '/clips/delete',
+ endpoint: 'clips/delete',
parameters: {
- clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+ // @ts-expect-error clipId must not be null
+ clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
...parameters,
},
user: alice,
@@ -306,7 +291,7 @@ describe('クリップ', () => {
test('のID指定取得は他人のPrivateなクリップは取得できない', async () => {
const clip = await create({ isPublic: false }, { user: bob } );
failedApiCall({
- endpoint: '/clips/show',
+ endpoint: 'clips/show',
parameters: { clipId: clip.id },
user: alice,
}, {
@@ -323,7 +308,8 @@ describe('クリップ', () => {
id: 'c3c5fe33-d62c-44d2-9ea5-d997703f5c20',
} },
])('のID指定取得は$labelならできない', async ({ parameters, assetion }) => failedApiCall({
- endpoint: '/clips/show',
+ endpoint: 'clips/show',
+ // @ts-expect-error clipId must not be undefined
parameters: {
...parameters,
},
@@ -356,27 +342,23 @@ describe('クリップ', () => {
test('の一覧が取得できる(空)', async () => {
const res = await usersClips({
- parameters: {
- userId: alice.id,
- },
+ userId: alice.id,
});
assert.deepStrictEqual(res, []);
});
test.each([
{ label: '' },
- { label: '他人アカウントから', user: (): User => bob },
+ { label: '他人アカウントから', user: () => bob },
])('の一覧が$label取得できる', async () => {
const clips = await createMany({ isPublic: true });
const res = await usersClips({
- parameters: {
- userId: alice.id,
- },
+ userId: alice.id,
});
// 返ってくる配列には順序保障がないのでidでソートして厳密比較
assert.deepStrictEqual(
- res.sort(compareBy(s => s.id)),
+ res.sort(compareBy(s => s.id)),
clips.sort(compareBy(s => s.id)));
// 認証状態で見たときだけisFavoritedが入っている
@@ -386,17 +368,16 @@ describe('クリップ', () => {
});
test.each([
- { label: '未認証', user: (): undefined => undefined },
+ { label: '未認証', user: () => undefined },
{ label: '存在しないユーザーのもの', parameters: { userId: 'xxxxxxx' } },
])('の一覧は$labelでも取得できる', async ({ parameters, user }) => {
const clips = await createMany({ isPublic: true });
const res = await usersClips({
- parameters: {
- userId: alice.id,
- limit: clips.length,
- ...parameters,
- },
- user: (user ?? ((): User => alice))(),
+ userId: alice.id,
+ limit: clips.length,
+ ...parameters,
+ }, {
+ user: (user ?? (() => alice))(),
});
// 未認証で見たときはisFavoritedは入らない
@@ -409,10 +390,8 @@ describe('クリップ', () => {
await create({ isPublic: false });
const aliceClip = await create({ isPublic: true });
const res = await usersClips({
- parameters: {
- userId: alice.id,
- limit: 2,
- },
+ userId: alice.id,
+ limit: 2,
});
assert.deepStrictEqual(res, [aliceClip]);
});
@@ -421,17 +400,15 @@ describe('クリップ', () => {
const clips = await createMany({ isPublic: true }, 7);
clips.sort(compareBy(s => s.id));
const res = await usersClips({
- parameters: {
- userId: alice.id,
- sinceId: clips[1].id,
- untilId: clips[5].id,
- limit: 4,
- },
+ userId: alice.id,
+ sinceId: clips[1].id,
+ untilId: clips[5].id,
+ limit: 4,
});
// Promise.allで返ってくる配列には順序保障がないのでidでソートして厳密比較
assert.deepStrictEqual(
- res.sort(compareBy(s => s.id)),
+ res.sort(compareBy(s => s.id)),
[clips[2], clips[3], clips[4]], // sinceIdとuntilId自体は結果に含まれない
clips[1].id + ' ... ' + clips[3].id + ' with ' + clips.map(s => s.id) + ' vs. ' + res.map(s => s.id));
});
@@ -441,8 +418,9 @@ describe('クリップ', () => {
{ label: 'limitゼロ', parameters: { limit: 0 } },
{ label: 'limit最大+1', parameters: { limit: 101 } },
])('の一覧は$labelだと取得できない', async ({ parameters }) => failedApiCall({
- endpoint: '/users/clips',
+ endpoint: 'users/clips',
parameters: {
+ // @ts-expect-error userId must not be undefined
userId: alice.id,
...parameters,
},
@@ -454,15 +432,15 @@ describe('クリップ', () => {
}));
test.each([
- { label: '作成', endpoint: '/clips/create' },
- { label: '更新', endpoint: '/clips/update' },
- { label: '削除', endpoint: '/clips/delete' },
- { label: '取得', endpoint: '/clips/list' },
- { label: 'お気に入り設定', endpoint: '/clips/favorite' },
- { label: 'お気に入り解除', endpoint: '/clips/unfavorite' },
- { label: 'お気に入り取得', endpoint: '/clips/my-favorites' },
- { label: 'ノート追加', endpoint: '/clips/add-note' },
- { label: 'ノート削除', endpoint: '/clips/remove-note' },
+ { label: '作成', endpoint: 'clips/create' as const },
+ { label: '更新', endpoint: 'clips/update' as const },
+ { label: '削除', endpoint: 'clips/delete' as const },
+ { label: '取得', endpoint: 'clips/list' as const },
+ { label: 'お気に入り設定', endpoint: 'clips/favorite' as const },
+ { label: 'お気に入り解除', endpoint: 'clips/unfavorite' as const },
+ { label: 'お気に入り取得', endpoint: 'clips/my-favorites' as const },
+ { label: 'ノート追加', endpoint: 'clips/add-note' as const },
+ { label: 'ノート削除', endpoint: 'clips/remove-note' as const },
])('の$labelは未認証ではできない', async ({ endpoint }) => await failedApiCall({
endpoint: endpoint,
parameters: {},
@@ -474,35 +452,33 @@ describe('クリップ', () => {
}));
describe('のお気に入り', () => {
- let aliceClip: Clip;
+ let aliceClip: Misskey.entities.Clip;
- type FavoriteParam = JTDDataType;
- const favorite = async (parameters: FavoriteParam, request: Partial = {}): Promise => {
- return successfulApiCall({
- endpoint: '/clips/favorite',
+ const favorite = async (parameters: Misskey.entities.ClipsFavoriteRequest, request: Partial> = {}): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/favorite',
parameters,
user: alice,
...request,
}, {
status: 204,
- });
+ }) as any as void;
};
- type UnfavoriteParam = JTDDataType;
- const unfavorite = async (parameters: UnfavoriteParam, request: Partial = {}): Promise => {
- return successfulApiCall({
- endpoint: '/clips/unfavorite',
+ const unfavorite = async (parameters: Misskey.entities.ClipsUnfavoriteRequest, request: Partial> = {}): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/unfavorite',
parameters,
user: alice,
...request,
}, {
status: 204,
- });
+ }) as any as void;
};
- const myFavorites = async (request: Partial = {}): Promise => {
- return successfulApiCall({
- endpoint: '/clips/my-favorites',
+ const myFavorites = async (request: Partial> = {}): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/my-favorites',
parameters: {},
user: alice,
...request,
@@ -568,7 +544,7 @@ describe('クリップ', () => {
test('は同じクリップに対して二回設定できない。', async () => {
await favorite({ clipId: aliceClip.id });
await failedApiCall({
- endpoint: '/clips/favorite',
+ endpoint: 'clips/favorite',
parameters: {
clipId: aliceClip.id,
},
@@ -586,14 +562,15 @@ describe('クリップ', () => {
code: 'NO_SUCH_CLIP',
id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
} },
- { label: '他人のクリップ', user: (): User => bob, assertion: {
+ { label: '他人のクリップ', user: () => bob, assertion: {
code: 'NO_SUCH_CLIP',
id: '4c2aaeae-80d8-4250-9606-26cb1fdb77a5',
} },
])('の設定は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
- endpoint: '/clips/favorite',
+ endpoint: 'clips/favorite',
parameters: {
- clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+ // @ts-expect-error clipId must not be null
+ clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
...parameters,
},
user: alice,
@@ -619,7 +596,7 @@ describe('クリップ', () => {
code: 'NO_SUCH_CLIP',
id: '2603966e-b865-426c-94a7-af4a01241dc1',
} },
- { label: '他人のクリップ', user: (): User => bob, assertion: {
+ { label: '他人のクリップ', user: () => bob, assertion: {
code: 'NOT_FAVORITED',
id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
} },
@@ -628,9 +605,10 @@ describe('クリップ', () => {
id: '90c3a9e8-b321-4dae-bf57-2bf79bbcc187',
} },
])('の設定解除は$labelならできない', async ({ parameters, user, assertion }) => failedApiCall({
- endpoint: '/clips/unfavorite',
+ endpoint: 'clips/unfavorite',
parameters: {
- clipId: (await create({}, { user: (user ?? ((): User => alice))() })).id,
+ // @ts-expect-error clipId must not be null
+ clipId: (await create({}, { user: (user ?? (() => alice))() })).id,
...parameters,
},
user: alice,
@@ -655,41 +633,38 @@ describe('クリップ', () => {
});
describe('に紐づくノート', () => {
- let aliceClip: Clip;
+ let aliceClip: Misskey.entities.Clip;
- const sampleNotes = (): Note[] => [
+ const sampleNotes = (): Misskey.entities.Note[] => [
aliceNote, aliceHomeNote, aliceFollowersNote, aliceSpecifiedNote,
bobNote, bobHomeNote, bobFollowersNote, bobSpecifiedNote,
];
- type AddNoteParam = JTDDataType;
- const addNote = async (parameters: AddNoteParam, request: Partial = {}): Promise => {
- return successfulApiCall({
- endpoint: '/clips/add-note',
+ const addNote = async (parameters: Misskey.entities.ClipsAddNoteRequest, request: Partial> = {}): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/add-note',
parameters,
user: alice,
...request,
}, {
status: 204,
- });
+ }) as any as void;
};
- type RemoveNoteParam = JTDDataType;
- const removeNote = async (parameters: RemoveNoteParam, request: Partial = {}): Promise => {
- return successfulApiCall({
- endpoint: '/clips/remove-note',
+ const removeNote = async (parameters: Misskey.entities.ClipsRemoveNoteRequest, request: Partial> = {}): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/remove-note',
parameters,
user: alice,
...request,
}, {
status: 204,
- });
+ }) as any as void;
};
- type NotesParam = JTDDataType;
- const notes = async (parameters: Partial, request: Partial = {}): Promise => {
- return successfulApiCall({
- endpoint: '/clips/notes',
+ const notes = async (parameters: Misskey.entities.ClipsNotesRequest, request: Partial> = {}): Promise => {
+ return successfulApiCall({
+ endpoint: 'clips/notes',
parameters,
user: alice,
...request,
@@ -715,7 +690,7 @@ describe('クリップ', () => {
test('として同じノートを二回紐づけることはできない', async () => {
await addNote({ clipId: aliceClip.id, noteId: aliceNote.id });
await failedApiCall({
- endpoint: '/clips/add-note',
+ endpoint: 'clips/add-note',
parameters: {
clipId: aliceClip.id,
noteId: aliceNote.id,
@@ -733,11 +708,11 @@ describe('クリップ', () => {
const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1;
const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, {
text: `test ${i}`,
- }) as unknown)) as Note[];
+ }) as unknown)) as Misskey.entities.Note[];
await Promise.all(noteList.map(s => addNote({ clipId: aliceClip.id, noteId: s.id })));
await failedApiCall({
- endpoint: '/clips/add-note',
+ endpoint: 'clips/add-note',
parameters: {
clipId: aliceClip.id,
noteId: aliceNote.id,
@@ -751,7 +726,7 @@ describe('クリップ', () => {
});
test('は他人のクリップへ追加できない。', async () => await failedApiCall({
- endpoint: '/clips/add-note',
+ endpoint: 'clips/add-note',
parameters: {
clipId: aliceClip.id,
noteId: aliceNote.id,
@@ -774,18 +749,20 @@ describe('クリップ', () => {
code: 'NO_SUCH_NOTE',
id: 'fc8c0b49-c7a3-4664-a0a6-b418d386bb8b',
} },
- { label: '他人のクリップ', user: (): object => bob, assetion: {
+ { label: '他人のクリップ', user: () => bob, assetion: {
code: 'NO_SUCH_CLIP',
id: 'd6e76cc0-a1b5-4c7c-a287-73fa9c716dcf',
} },
])('の追加は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
- endpoint: '/clips/add-note',
+ endpoint: 'clips/add-note',
parameters: {
+ // @ts-expect-error clipId must not be undefined
clipId: aliceClip.id,
+ // @ts-expect-error noteId must not be undefined
noteId: aliceNote.id,
...parameters,
},
- user: (user ?? ((): User => alice))(),
+ user: (user ?? (() => alice))(),
}, {
status: 400,
code: 'INVALID_PARAM',
@@ -810,18 +787,20 @@ describe('クリップ', () => {
code: 'NO_SUCH_NOTE',
id: 'aff017de-190e-434b-893e-33a9ff5049d8', // add-noteと異なる
} },
- { label: '他人のクリップ', user: (): object => bob, assetion: {
+ { label: '他人のクリップ', user: () => bob, assetion: {
code: 'NO_SUCH_CLIP',
id: 'b80525c6-97f7-49d7-a42d-ebccd49cfd52', // add-noteと異なる
} },
])('の削除は$labelだとできない', async ({ parameters, user, assetion }) => failedApiCall({
- endpoint: '/clips/remove-note',
+ endpoint: 'clips/remove-note',
parameters: {
+ // @ts-expect-error clipId must not be undefined
clipId: aliceClip.id,
+ // @ts-expect-error noteId must not be undefined
noteId: aliceNote.id,
...parameters,
},
- user: (user ?? ((): User => alice))(),
+ user: (user ?? (() => alice))(),
}, {
status: 400,
code: 'INVALID_PARAM',
@@ -925,21 +904,22 @@ describe('クリップ', () => {
code: 'NO_SUCH_CLIP',
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
} },
- { label: '他人のPrivateなクリップから', user: (): object => bob, assertion: {
+ { label: '他人のPrivateなクリップから', user: () => bob, assertion: {
code: 'NO_SUCH_CLIP',
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
} },
- { label: '未認証でPrivateなクリップから', user: (): undefined => undefined, assertion: {
+ { label: '未認証でPrivateなクリップから', user: () => undefined, assertion: {
code: 'NO_SUCH_CLIP',
id: '1d7645e6-2b6d-4635-b0fe-fe22b0e72e00',
} },
])('は$labelだと取得できない', async ({ parameters, user, assertion }) => failedApiCall({
- endpoint: '/clips/notes',
+ endpoint: 'clips/notes',
parameters: {
+ // @ts-expect-error clipId must not be undefined
clipId: aliceClip.id,
...parameters,
},
- user: (user ?? ((): User => alice))(),
+ user: (user ?? (() => alice))(),
}, {
status: 400,
code: 'INVALID_PARAM',
diff --git a/packages/backend/test/e2e/drive.ts b/packages/backend/test/e2e/drive.ts
index 22ec66e2af..828c5200ef 100644
--- a/packages/backend/test/e2e/drive.ts
+++ b/packages/backend/test/e2e/drive.ts
@@ -6,22 +6,14 @@
process.env.NODE_ENV = 'test';
import * as assert from 'assert';
-import { MiNote } from '@/models/Note.js';
-import { api, initTestDb, makeStreamCatcher, post, signup, uploadFile } from '../utils.js';
+import { api, makeStreamCatcher, post, signup, uploadFile } from '../utils.js';
import type * as misskey from 'misskey-js';
-import type{ Repository } from 'typeorm'
-import type { Packed } from '@/misc/json-schema.js';
-
describe('Drive', () => {
- let Notes: Repository;
-
let alice: misskey.entities.SignupResponse;
let bob: misskey.entities.SignupResponse;
beforeAll(async () => {
- const connection = await initTestDb(true);
- Notes = connection.getRepository(MiNote);
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });
}, 1000 * 60 * 2);
@@ -31,13 +23,13 @@ describe('Drive', () => {
const marker = Math.random().toString();
- const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'
+ const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg';
const catcher = makeStreamCatcher(
alice,
'main',
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
- (msg) => msg.body.file as Packed<'DriveFile'>,
+ (msg) => msg.body.file,
10 * 1000);
const res = await api('drive/files/upload-from-url', {
@@ -51,7 +43,7 @@ describe('Drive', () => {
assert.strictEqual(res.status, 204);
assert.strictEqual(file.name, 'Lenna.jpg');
assert.strictEqual(file.type, 'image/jpeg');
- })
+ });
test('ローカルからアップロードできる', async () => {
// APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする
@@ -59,27 +51,27 @@ describe('Drive', () => {
const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' });
assert.strictEqual(res.body?.name, 'テスト画像.jpg');
- assert.strictEqual(res.body?.type, 'image/jpeg');
- })
+ assert.strictEqual(res.body.type, 'image/jpeg');
+ });
test('添付ノート一覧を取得できる', async () => {
- const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id)
+ const ids = (await Promise.all([uploadFile(alice), uploadFile(alice), uploadFile(alice)])).map(elm => elm.body!.id);
const note0 = await post(alice, { fileIds: [ids[0]] });
const note1 = await post(alice, { fileIds: [ids[0], ids[1]] });
const attached0 = await api('drive/files/attached-notes', { fileId: ids[0] }, alice);
assert.strictEqual(attached0.body.length, 2);
- assert.strictEqual(attached0.body[0].id, note1.id)
- assert.strictEqual(attached0.body[1].id, note0.id)
+ assert.strictEqual(attached0.body[0].id, note1.id);
+ assert.strictEqual(attached0.body[1].id, note0.id);
const attached1 = await api('drive/files/attached-notes', { fileId: ids[1] }, alice);
assert.strictEqual(attached1.body.length, 1);
- assert.strictEqual(attached1.body[0].id, note1.id)
+ assert.strictEqual(attached1.body[0].id, note1.id);
const attached2 = await api('drive/files/attached-notes', { fileId: ids[2] }, alice);
- assert.strictEqual(attached2.body.length, 0)
- })
+ assert.strictEqual(attached2.body.length, 0);
+ });
test('添付ノート一覧は他の人から見えない', async () => {
const file = await uploadFile(alice);
@@ -89,7 +81,5 @@ describe('Drive', () => {
const res = await api('drive/files/attached-notes', { fileId: file.body!.id }, bob);
assert.strictEqual(res.status, 400);
assert.strictEqual('error' in res.body, true);
-
- })
+ });
});
-
diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts
index d469597805..bc89dc37f4 100644
--- a/packages/backend/test/e2e/endpoints.ts
+++ b/packages/backend/test/e2e/endpoints.ts
@@ -79,6 +79,7 @@ describe('Endpoints', () => {
test('クエリをインジェクションできない', async () => {
const res = await api('signin', {
username: 'test1',
+ // @ts-expect-error password must be string
password: {
$gt: '',
},
@@ -103,7 +104,7 @@ describe('Endpoints', () => {
const myLocation = '七森中';
const myBirthday = '2000-09-07';
- const res = await api('/i/update', {
+ const res = await api('i/update', {
name: myName,
location: myLocation,
birthday: myBirthday,
@@ -117,7 +118,7 @@ describe('Endpoints', () => {
});
test('名前を空白にできる', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
name: ' ',
}, alice);
assert.strictEqual(res.status, 200);
@@ -125,11 +126,11 @@ describe('Endpoints', () => {
});
test('誕生日の設定を削除できる', async () => {
- await api('/i/update', {
+ await api('i/update', {
birthday: '2000-09-07',
}, alice);
- const res = await api('/i/update', {
+ const res = await api('i/update', {
birthday: null,
}, alice);
@@ -139,7 +140,7 @@ describe('Endpoints', () => {
});
test('不正な誕生日の形式で怒られる', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
birthday: '2000/09/07',
}, alice);
assert.strictEqual(res.status, 400);
@@ -148,7 +149,7 @@ describe('Endpoints', () => {
describe('users/show', () => {
test('ユーザーが取得できる', async () => {
- const res = await api('/users/show', {
+ const res = await api('users/show', {
userId: alice.id,
}, alice);
@@ -158,14 +159,14 @@ describe('Endpoints', () => {
});
test('ユーザーが存在しなかったら怒る', async () => {
- const res = await api('/users/show', {
+ const res = await api('users/show', {
userId: '000000000000000000000000',
});
assert.strictEqual(res.status, 404);
});
test('間違ったIDで怒られる', async () => {
- const res = await api('/users/show', {
+ const res = await api('users/show', {
userId: 'kyoppie',
});
assert.strictEqual(res.status, 404);
@@ -178,7 +179,7 @@ describe('Endpoints', () => {
text: 'test',
});
- const res = await api('/notes/show', {
+ const res = await api('notes/show', {
noteId: myPost.id,
}, alice);
@@ -189,14 +190,14 @@ describe('Endpoints', () => {
});
test('投稿が存在しなかったら怒る', async () => {
- const res = await api('/notes/show', {
+ const res = await api('notes/show', {
noteId: '000000000000000000000000',
});
assert.strictEqual(res.status, 400);
});
test('間違ったIDで怒られる', async () => {
- const res = await api('/notes/show', {
+ const res = await api('notes/show', {
noteId: 'kyoppie',
});
assert.strictEqual(res.status, 400);
@@ -207,14 +208,14 @@ describe('Endpoints', () => {
test('リアクションできる', async () => {
const bobPost = await post(bob, { text: 'hi' });
- const res = await api('/notes/reactions/create', {
+ const res = await api('notes/reactions/create', {
noteId: bobPost.id,
reaction: '🚀',
}, alice);
assert.strictEqual(res.status, 204);
- const resNote = await api('/notes/show', {
+ const resNote = await api('notes/show', {
noteId: bobPost.id,
}, alice);
@@ -225,7 +226,7 @@ describe('Endpoints', () => {
test('自分の投稿にもリアクションできる', async () => {
const myPost = await post(alice, { text: 'hi' });
- const res = await api('/notes/reactions/create', {
+ const res = await api('notes/reactions/create', {
noteId: myPost.id,
reaction: '🚀',
}, alice);
@@ -236,19 +237,19 @@ describe('Endpoints', () => {
test('二重にリアクションすると上書きされる', async () => {
const bobPost = await post(bob, { text: 'hi' });
- await api('/notes/reactions/create', {
+ await api('notes/reactions/create', {
noteId: bobPost.id,
reaction: '🥰',
}, alice);
- const res = await api('/notes/reactions/create', {
+ const res = await api('notes/reactions/create', {
noteId: bobPost.id,
reaction: '🚀',
}, alice);
assert.strictEqual(res.status, 204);
- const resNote = await api('/notes/show', {
+ const resNote = await api('notes/show', {
noteId: bobPost.id,
}, alice);
@@ -257,7 +258,7 @@ describe('Endpoints', () => {
});
test('存在しない投稿にはリアクションできない', async () => {
- const res = await api('/notes/reactions/create', {
+ const res = await api('notes/reactions/create', {
noteId: '000000000000000000000000',
reaction: '🚀',
}, alice);
@@ -266,13 +267,14 @@ describe('Endpoints', () => {
});
test('空のパラメータで怒られる', async () => {
- const res = await api('/notes/reactions/create', {}, alice);
+ // @ts-expect-error param must not be empty
+ const res = await api('notes/reactions/create', {}, alice);
assert.strictEqual(res.status, 400);
});
test('間違ったIDで怒られる', async () => {
- const res = await api('/notes/reactions/create', {
+ const res = await api('notes/reactions/create', {
noteId: 'kyoppie',
reaction: '🚀',
}, alice);
@@ -283,7 +285,7 @@ describe('Endpoints', () => {
describe('following/create', () => {
test('フォローできる', async () => {
- const res = await api('/following/create', {
+ const res = await api('following/create', {
userId: alice.id,
}, bob);
@@ -301,7 +303,7 @@ describe('Endpoints', () => {
});
test('既にフォローしている場合は怒る', async () => {
- const res = await api('/following/create', {
+ const res = await api('following/create', {
userId: alice.id,
}, bob);
@@ -309,7 +311,7 @@ describe('Endpoints', () => {
});
test('存在しないユーザーはフォローできない', async () => {
- const res = await api('/following/create', {
+ const res = await api('following/create', {
userId: '000000000000000000000000',
}, alice);
@@ -317,7 +319,7 @@ describe('Endpoints', () => {
});
test('自分自身はフォローできない', async () => {
- const res = await api('/following/create', {
+ const res = await api('following/create', {
userId: alice.id,
}, alice);
@@ -325,13 +327,14 @@ describe('Endpoints', () => {
});
test('空のパラメータで怒られる', async () => {
- const res = await api('/following/create', {}, alice);
+ // @ts-expect-error params must not be empty
+ const res = await api('following/create', {}, alice);
assert.strictEqual(res.status, 400);
});
test('間違ったIDで怒られる', async () => {
- const res = await api('/following/create', {
+ const res = await api('following/create', {
userId: 'foo',
}, alice);
@@ -341,11 +344,11 @@ describe('Endpoints', () => {
describe('following/delete', () => {
test('フォロー解除できる', async () => {
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const res = await api('/following/delete', {
+ const res = await api('following/delete', {
userId: alice.id,
}, bob);
@@ -363,7 +366,7 @@ describe('Endpoints', () => {
});
test('フォローしていない場合は怒る', async () => {
- const res = await api('/following/delete', {
+ const res = await api('following/delete', {
userId: alice.id,
}, bob);
@@ -371,7 +374,7 @@ describe('Endpoints', () => {
});
test('存在しないユーザーはフォロー解除できない', async () => {
- const res = await api('/following/delete', {
+ const res = await api('following/delete', {
userId: '000000000000000000000000',
}, alice);
@@ -379,7 +382,7 @@ describe('Endpoints', () => {
});
test('自分自身はフォロー解除できない', async () => {
- const res = await api('/following/delete', {
+ const res = await api('following/delete', {
userId: alice.id,
}, alice);
@@ -387,13 +390,14 @@ describe('Endpoints', () => {
});
test('空のパラメータで怒られる', async () => {
- const res = await api('/following/delete', {}, alice);
+ // @ts-expect-error params must not be empty
+ const res = await api('following/delete', {}, alice);
assert.strictEqual(res.status, 400);
});
test('間違ったIDで怒られる', async () => {
- const res = await api('/following/delete', {
+ const res = await api('following/delete', {
userId: 'kyoppie',
}, alice);
@@ -403,20 +407,20 @@ describe('Endpoints', () => {
describe('channels/search', () => {
test('空白検索で一覧を取得できる', async () => {
- await api('/channels/create', {
+ await api('channels/create', {
name: 'aaa',
description: 'bbb',
}, bob);
- await api('/channels/create', {
+ await api('channels/create', {
name: 'ccc1',
description: 'ddd1',
}, bob);
- await api('/channels/create', {
+ await api('channels/create', {
name: 'ccc2',
description: 'ddd2',
}, bob);
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: '',
}, bob);
@@ -425,7 +429,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body.length, 3);
});
test('名前のみの検索で名前を検索できる', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'aaa',
type: 'nameOnly',
}, bob);
@@ -436,7 +440,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body[0].name, 'aaa');
});
test('名前のみの検索で名前を複数検索できる', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'ccc',
type: 'nameOnly',
}, bob);
@@ -446,7 +450,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body.length, 2);
});
test('名前のみの検索で説明は検索できない', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'bbb',
type: 'nameOnly',
}, bob);
@@ -456,7 +460,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body.length, 0);
});
test('名前と説明の検索で名前を検索できる', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'ccc1',
}, bob);
@@ -466,7 +470,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body[0].name, 'ccc1');
});
test('名前と説明での検索で説明を検索できる', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'ddd1',
}, bob);
@@ -476,7 +480,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body[0].name, 'ccc1');
});
test('名前と説明の検索で名前を複数検索できる', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'ccc',
}, bob);
@@ -485,7 +489,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.body.length, 2);
});
test('名前と説明での検索で説明を複数検索できる', async () => {
- const res = await api('/channels/search', {
+ const res = await api('channels/search', {
query: 'ddd',
}, bob);
@@ -506,7 +510,7 @@ describe('Endpoints', () => {
await uploadFile(alice, {
blob: new Blob([new Uint8Array(1024)]),
});
- const res = await api('/drive', {}, alice);
+ const res = await api('drive', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
expect(res.body).toHaveProperty('usage', 1792);
@@ -519,7 +523,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
- assert.strictEqual(res.body.name, 'Lenna.jpg');
+ assert.strictEqual(res.body!.name, 'Lenna.jpg');
});
test('ファイルに名前を付けられる', async () => {
@@ -527,7 +531,7 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
- assert.strictEqual(res.body.name, 'Belmond.jpg');
+ assert.strictEqual(res.body!.name, 'Belmond.jpg');
});
test('ファイルに名前を付けられるが、拡張子は正しいものになる', async () => {
@@ -535,11 +539,12 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
- assert.strictEqual(res.body.name, 'Belmond.png.jpg');
+ assert.strictEqual(res.body!.name, 'Belmond.png.jpg');
});
test('ファイル無しで怒られる', async () => {
- const res = await api('/drive/files/create', {}, alice);
+ // @ts-expect-error params must not be empty
+ const res = await api('drive/files/create', {}, alice);
assert.strictEqual(res.status, 400);
});
@@ -549,14 +554,14 @@ describe('Endpoints', () => {
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
- assert.strictEqual(res.body.name, 'image.svg');
- assert.strictEqual(res.body.type, 'image/svg+xml');
+ assert.strictEqual(res.body!.name, 'image.svg');
+ assert.strictEqual(res.body!.type, 'image/svg+xml');
});
for (const type of ['webp', 'avif']) {
const mediaType = `image/${type}`;
- const getWebpublicType = async (user: any, fileId: string): Promise => {
+ const getWebpublicType = async (user: misskey.entities.SignupResponse, fileId: string): Promise => {
// drive/files/create does not expose webpublicType directly, so get it by posting it
const res = await post(user, {
text: mediaType,
@@ -573,10 +578,10 @@ describe('Endpoints', () => {
const res = await uploadFile(alice, { path });
assert.strictEqual(res.status, 200);
- assert.strictEqual(res.body.name, path);
- assert.strictEqual(res.body.type, mediaType);
+ assert.strictEqual(res.body!.name, path);
+ assert.strictEqual(res.body!.type, mediaType);
- const webpublicType = await getWebpublicType(alice, res.body.id);
+ const webpublicType = await getWebpublicType(alice, res.body!.id);
assert.strictEqual(webpublicType, 'image/webp');
});
@@ -584,10 +589,10 @@ describe('Endpoints', () => {
const path = `without-alpha.${type}`;
const res = await uploadFile(alice, { path });
assert.strictEqual(res.status, 200);
- assert.strictEqual(res.body.name, path);
- assert.strictEqual(res.body.type, mediaType);
+ assert.strictEqual(res.body!.name, path);
+ assert.strictEqual(res.body!.type, mediaType);
- const webpublicType = await getWebpublicType(alice, res.body.id);
+ const webpublicType = await getWebpublicType(alice, res.body!.id);
assert.strictEqual(webpublicType, 'image/webp');
});
}
@@ -598,8 +603,8 @@ describe('Endpoints', () => {
const file = (await uploadFile(alice)).body;
const newName = 'いちごパスタ.png';
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
name: newName,
}, alice);
@@ -611,8 +616,8 @@ describe('Endpoints', () => {
test('他人のファイルは更新できない', async () => {
const file = (await uploadFile(alice)).body;
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
name: 'いちごパスタ.png',
}, bob);
@@ -621,12 +626,12 @@ describe('Endpoints', () => {
test('親フォルダを更新できる', async () => {
const file = (await uploadFile(alice)).body;
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
folderId: folder.id,
}, alice);
@@ -638,17 +643,17 @@ describe('Endpoints', () => {
test('親フォルダを無しにできる', async () => {
const file = (await uploadFile(alice)).body;
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- await api('/drive/files/update', {
- fileId: file.id,
+ await api('drive/files/update', {
+ fileId: file!.id,
folderId: folder.id,
}, alice);
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
folderId: null,
}, alice);
@@ -659,12 +664,12 @@ describe('Endpoints', () => {
test('他人のフォルダには入れられない', async () => {
const file = (await uploadFile(alice)).body;
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, bob)).body;
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
folderId: folder.id,
}, alice);
@@ -674,8 +679,8 @@ describe('Endpoints', () => {
test('存在しないフォルダで怒られる', async () => {
const file = (await uploadFile(alice)).body;
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
folderId: '000000000000000000000000',
}, alice);
@@ -685,8 +690,8 @@ describe('Endpoints', () => {
test('不正なフォルダIDで怒られる', async () => {
const file = (await uploadFile(alice)).body;
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
folderId: 'foo',
}, alice);
@@ -694,7 +699,7 @@ describe('Endpoints', () => {
});
test('ファイルが存在しなかったら怒る', async () => {
- const res = await api('/drive/files/update', {
+ const res = await api('drive/files/update', {
fileId: '000000000000000000000000',
name: 'いちごパスタ.png',
}, alice);
@@ -706,8 +711,8 @@ describe('Endpoints', () => {
const file = (await uploadFile(alice)).body;
const newName = '';
- const res = await api('/drive/files/update', {
- fileId: file.id,
+ const res = await api('drive/files/update', {
+ fileId: file!.id,
name: newName,
}, alice);
@@ -715,7 +720,7 @@ describe('Endpoints', () => {
});
test('間違ったIDで怒られる', async () => {
- const res = await api('/drive/files/update', {
+ const res = await api('drive/files/update', {
fileId: 'kyoppie',
name: 'いちごパスタ.png',
}, alice);
@@ -726,7 +731,7 @@ describe('Endpoints', () => {
describe('drive/folders/create', () => {
test('フォルダを作成できる', async () => {
- const res = await api('/drive/folders/create', {
+ const res = await api('drive/folders/create', {
name: 'test',
}, alice);
@@ -738,11 +743,11 @@ describe('Endpoints', () => {
describe('drive/folders/update', () => {
test('名前を更新できる', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
name: 'new name',
}, alice);
@@ -753,11 +758,11 @@ describe('Endpoints', () => {
});
test('他人のフォルダを更新できない', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, bob)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
name: 'new name',
}, alice);
@@ -766,14 +771,14 @@ describe('Endpoints', () => {
});
test('親フォルダを更新できる', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const parentFolder = (await api('/drive/folders/create', {
+ const parentFolder = (await api('drive/folders/create', {
name: 'parent',
}, alice)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
parentId: parentFolder.id,
}, alice);
@@ -784,18 +789,18 @@ describe('Endpoints', () => {
});
test('親フォルダを無しに更新できる', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const parentFolder = (await api('/drive/folders/create', {
+ const parentFolder = (await api('drive/folders/create', {
name: 'parent',
}, alice)).body;
- await api('/drive/folders/update', {
+ await api('drive/folders/update', {
folderId: folder.id,
parentId: parentFolder.id,
}, alice);
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
parentId: null,
}, alice);
@@ -806,14 +811,14 @@ describe('Endpoints', () => {
});
test('他人のフォルダを親フォルダに設定できない', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const parentFolder = (await api('/drive/folders/create', {
+ const parentFolder = (await api('drive/folders/create', {
name: 'parent',
}, bob)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
parentId: parentFolder.id,
}, alice);
@@ -822,18 +827,18 @@ describe('Endpoints', () => {
});
test('フォルダが循環するような構造にできない', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const parentFolder = (await api('/drive/folders/create', {
+ const parentFolder = (await api('drive/folders/create', {
name: 'parent',
}, alice)).body;
- await api('/drive/folders/update', {
+ await api('drive/folders/update', {
folderId: parentFolder.id,
parentId: folder.id,
}, alice);
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
parentId: parentFolder.id,
}, alice);
@@ -842,25 +847,25 @@ describe('Endpoints', () => {
});
test('フォルダが循環するような構造にできない(再帰的)', async () => {
- const folderA = (await api('/drive/folders/create', {
+ const folderA = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const folderB = (await api('/drive/folders/create', {
+ const folderB = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const folderC = (await api('/drive/folders/create', {
+ const folderC = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- await api('/drive/folders/update', {
+ await api('drive/folders/update', {
folderId: folderB.id,
parentId: folderA.id,
}, alice);
- await api('/drive/folders/update', {
+ await api('drive/folders/update', {
folderId: folderC.id,
parentId: folderB.id,
}, alice);
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folderA.id,
parentId: folderC.id,
}, alice);
@@ -869,11 +874,11 @@ describe('Endpoints', () => {
});
test('フォルダが循環するような構造にできない(自身)', async () => {
- const folderA = (await api('/drive/folders/create', {
+ const folderA = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folderA.id,
parentId: folderA.id,
}, alice);
@@ -882,11 +887,11 @@ describe('Endpoints', () => {
});
test('存在しない親フォルダを設定できない', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
parentId: '000000000000000000000000',
}, alice);
@@ -895,11 +900,11 @@ describe('Endpoints', () => {
});
test('不正な親フォルダIDで怒られる', async () => {
- const folder = (await api('/drive/folders/create', {
+ const folder = (await api('drive/folders/create', {
name: 'test',
}, alice)).body;
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: folder.id,
parentId: 'foo',
}, alice);
@@ -908,7 +913,7 @@ describe('Endpoints', () => {
});
test('存在しないフォルダを更新できない', async () => {
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: '000000000000000000000000',
}, alice);
@@ -916,7 +921,7 @@ describe('Endpoints', () => {
});
test('不正なフォルダIDで怒られる', async () => {
- const res = await api('/drive/folders/update', {
+ const res = await api('drive/folders/update', {
folderId: 'foo',
}, alice);
@@ -937,7 +942,7 @@ describe('Endpoints', () => {
visibleUserIds: [alice.id],
});
- const res = await api('/notes/replies', {
+ const res = await api('notes/replies', {
noteId: alicePost.id,
}, carol);
@@ -949,7 +954,7 @@ describe('Endpoints', () => {
describe('notes/timeline', () => {
test('フォロワー限定投稿が含まれる', async () => {
- await api('/following/create', {
+ await api('following/create', {
userId: carol.id,
}, dave);
@@ -958,7 +963,7 @@ describe('Endpoints', () => {
visibility: 'followers',
});
- const res = await api('/notes/timeline', {}, dave);
+ const res = await api('notes/timeline', {}, dave);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -979,12 +984,12 @@ describe('Endpoints', () => {
test('他者に関するメモを更新できる', async () => {
const memo = '10月まで低浮上とのこと。';
- const res1 = await api('/users/update-memo', {
+ const res1 = await api('users/update-memo', {
memo,
userId: bob.id,
}, alice);
- const res2 = await api('/users/show', {
+ const res2 = await api('users/show', {
userId: bob.id,
}, alice);
assert.strictEqual(res1.status, 204);
@@ -994,12 +999,12 @@ describe('Endpoints', () => {
test('自分に関するメモを更新できる', async () => {
const memo = 'チケットを月末までに買う。';
- const res1 = await api('/users/update-memo', {
+ const res1 = await api('users/update-memo', {
memo,
userId: alice.id,
}, alice);
- const res2 = await api('/users/show', {
+ const res2 = await api('users/show', {
userId: alice.id,
}, alice);
assert.strictEqual(res1.status, 204);
@@ -1009,17 +1014,17 @@ describe('Endpoints', () => {
test('メモを削除できる', async () => {
const memo = '10月まで低浮上とのこと。';
- await api('/users/update-memo', {
+ await api('users/update-memo', {
memo,
userId: bob.id,
}, alice);
- await api('/users/update-memo', {
+ await api('users/update-memo', {
memo: '',
userId: bob.id,
}, alice);
- const res = await api('/users/show', {
+ const res = await api('users/show', {
userId: bob.id,
}, alice);
@@ -1032,21 +1037,21 @@ describe('Endpoints', () => {
const memoCarolToBob = '例の件について今度問いただす。';
await Promise.all([
- api('/users/update-memo', {
+ api('users/update-memo', {
memo: memoAliceToBob,
userId: bob.id,
}, alice),
- api('/users/update-memo', {
+ api('users/update-memo', {
memo: memoCarolToBob,
userId: bob.id,
}, carol),
]);
const [resAlice, resCarol] = await Promise.all([
- api('/users/show', {
+ api('users/show', {
userId: bob.id,
}, alice),
- api('/users/show', {
+ api('users/show', {
userId: bob.id,
}, carol),
]);
diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts
index eb03935a2a..80a5331a6d 100644
--- a/packages/backend/test/e2e/exports.ts
+++ b/packages/backend/test/e2e/exports.ts
@@ -18,7 +18,7 @@ describe('export-clips', () => {
// XXX: Any better way to get the result?
async function pollFirstDriveFile() {
while (true) {
- const files = (await api('/drive/files', {}, alice)).body;
+ const files = (await api('drive/files', {}, alice)).body;
if (!files.length) {
await new Promise(r => setTimeout(r, 100));
continue;
@@ -26,7 +26,7 @@ describe('export-clips', () => {
if (files.length > 1) {
throw new Error('Too many files?');
}
- const file = (await api('/drive/files/show', { fileId: files[0].id }, alice)).body;
+ const file = (await api('drive/files/show', { fileId: files[0].id }, alice)).body;
const res = await fetch(new URL(new URL(file.url).pathname, `http://127.0.0.1:${port}`));
return await res.json();
}
@@ -44,16 +44,16 @@ describe('export-clips', () => {
beforeEach(async () => {
// Clean all clips and files of alice
- const clips = (await api('/clips/list', {}, alice)).body;
+ const clips = (await api('clips/list', {}, alice)).body;
for (const clip of clips) {
- const res = await api('/clips/delete', { clipId: clip.id }, alice);
+ const res = await api('clips/delete', { clipId: clip.id }, alice);
if (res.status !== 204) {
throw new Error('Failed to delete clip');
}
}
- const files = (await api('/drive/files', {}, alice)).body;
+ const files = (await api('drive/files', {}, alice)).body;
for (const file of files) {
- const res = await api('/drive/files/delete', { fileId: file.id }, alice);
+ const res = await api('drive/files/delete', { fileId: file.id }, alice);
if (res.status !== 204) {
throw new Error('Failed to delete file');
}
@@ -61,13 +61,13 @@ describe('export-clips', () => {
});
test('basic export', async () => {
- let res = await api('/clips/create', {
+ let res = await api('clips/create', {
name: 'foo',
description: 'bar',
}, alice);
assert.strictEqual(res.status, 200);
- res = await api('/i/export-clips', {}, alice);
+ res = await api('i/export-clips', {}, alice);
assert.strictEqual(res.status, 204);
const exported = await pollFirstDriveFile();
@@ -77,7 +77,7 @@ describe('export-clips', () => {
});
test('export with notes', async () => {
- let res = await api('/clips/create', {
+ let res = await api('clips/create', {
name: 'foo',
description: 'bar',
}, alice);
@@ -96,14 +96,14 @@ describe('export-clips', () => {
});
for (const note of [note1, note2]) {
- res = await api('/clips/add-note', {
+ res = await api('clips/add-note', {
clipId: clip.id,
noteId: note.id,
}, alice);
assert.strictEqual(res.status, 204);
}
- res = await api('/i/export-clips', {}, alice);
+ res = await api('i/export-clips', {}, alice);
assert.strictEqual(res.status, 204);
const exported = await pollFirstDriveFile();
@@ -116,14 +116,14 @@ describe('export-clips', () => {
});
test('multiple clips', async () => {
- let res = await api('/clips/create', {
+ let res = await api('clips/create', {
name: 'kawaii',
description: 'kawaii',
}, alice);
assert.strictEqual(res.status, 200);
const clip1 = res.body;
- res = await api('/clips/create', {
+ res = await api('clips/create', {
name: 'yuri',
description: 'yuri',
}, alice);
@@ -138,19 +138,19 @@ describe('export-clips', () => {
text: 'baz2',
});
- res = await api('/clips/add-note', {
+ res = await api('clips/add-note', {
clipId: clip1.id,
noteId: note1.id,
}, alice);
assert.strictEqual(res.status, 204);
- res = await api('/clips/add-note', {
+ res = await api('clips/add-note', {
clipId: clip2.id,
noteId: note2.id,
}, alice);
assert.strictEqual(res.status, 204);
- res = await api('/i/export-clips', {}, alice);
+ res = await api('i/export-clips', {}, alice);
assert.strictEqual(res.status, 204);
const exported = await pollFirstDriveFile();
@@ -163,7 +163,7 @@ describe('export-clips', () => {
});
test('Clipping other user\'s note', async () => {
- let res = await api('/clips/create', {
+ let res = await api('clips/create', {
name: 'kawaii',
description: 'kawaii',
}, alice);
@@ -175,13 +175,13 @@ describe('export-clips', () => {
visibility: 'followers',
});
- res = await api('/clips/add-note', {
+ res = await api('clips/add-note', {
clipId: clip.id,
noteId: note.id,
}, alice);
assert.strictEqual(res.status, 204);
- res = await api('/i/export-clips', {}, alice);
+ res = await api('i/export-clips', {}, alice);
assert.strictEqual(res.status, 204);
const exported = await pollFirstDriveFile();
diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts
index 74033b7dff..4851ed14be 100644
--- a/packages/backend/test/e2e/fetch-resource.ts
+++ b/packages/backend/test/e2e/fetch-resource.ts
@@ -23,13 +23,13 @@ const JSON_UTF8 = 'application/json; charset=utf-8';
describe('Webリソース', () => {
let alice: misskey.entities.SignupResponse;
- let aliceUploadedFile: any;
- let alicesPost: any;
- let alicePage: any;
- let alicePlay: any;
- let aliceClip: any;
- let aliceGalleryPost: any;
- let aliceChannel: any;
+ let aliceUploadedFile: misskey.entities.DriveFile | null;
+ let alicesPost: misskey.entities.Note;
+ let alicePage: misskey.entities.Page;
+ let alicePlay: misskey.entities.Flash;
+ let aliceClip: misskey.entities.Clip;
+ let aliceGalleryPost: misskey.entities.GalleryPost;
+ let aliceChannel: misskey.entities.Channel;
let bob: misskey.entities.SignupResponse;
@@ -77,7 +77,7 @@ describe('Webリソース', () => {
beforeAll(async () => {
alice = await signup({ username: 'alice' });
- aliceUploadedFile = await uploadFile(alice);
+ aliceUploadedFile = (await uploadFile(alice)).body;
alicesPost = await post(alice, {
text: 'test',
});
@@ -85,7 +85,7 @@ describe('Webリソース', () => {
alicePlay = await play(alice, {});
aliceClip = await clip(alice, {});
aliceGalleryPost = await galleryPost(alice, {
- fileIds: [aliceUploadedFile.body.id],
+ fileIds: [aliceUploadedFile!.id],
});
aliceChannel = await channel(alice, {});
diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts
index b59dd8824a..5d0c70a3c2 100644
--- a/packages/backend/test/e2e/ff-visibility.ts
+++ b/packages/backend/test/e2e/ff-visibility.ts
@@ -19,15 +19,15 @@ describe('FF visibility', () => {
}, 1000 * 60 * 2);
test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'public',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
@@ -39,36 +39,36 @@ describe('FF visibility', () => {
test('followingVisibility が public であれば followersVisibility の設定に関わらずユーザーのフォローを誰でも見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'public',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 200);
@@ -78,36 +78,36 @@ describe('FF visibility', () => {
test('followersVisibility が public であれば followingVisibility の設定に関わらずユーザーのフォロワーを誰でも見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'public',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'public',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'public',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 200);
@@ -116,15 +116,15 @@ describe('FF visibility', () => {
});
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
@@ -136,36 +136,36 @@ describe('FF visibility', () => {
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'public',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(followingRes.status, 200);
@@ -175,36 +175,36 @@ describe('FF visibility', () => {
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'followers',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'followers',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
assert.strictEqual(followersRes.status, 200);
@@ -213,15 +213,15 @@ describe('FF visibility', () => {
});
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
@@ -231,34 +231,34 @@ describe('FF visibility', () => {
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらず非フォロワーが見れない', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'public',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 400);
@@ -267,34 +267,34 @@ describe('FF visibility', () => {
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらず非フォロワーが見れない', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'followers',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'followers',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 400);
@@ -302,19 +302,19 @@ describe('FF visibility', () => {
});
test('followingVisibility, followersVisibility がともに followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
@@ -326,45 +326,45 @@ describe('FF visibility', () => {
test('followingVisibility が followers なユーザーのフォローを followersVisibility の設定に関わらずフォロワーが見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'public',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'private',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 200);
@@ -374,45 +374,45 @@ describe('FF visibility', () => {
test('followersVisibility が followers なユーザーのフォロワーを followingVisibility の設定に関わらずフォロワーが見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'followers',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'followers',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'followers',
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 200);
@@ -421,15 +421,15 @@ describe('FF visibility', () => {
});
test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
@@ -441,36 +441,36 @@ describe('FF visibility', () => {
test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず自分で見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'public',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(followingRes.status, 200);
assert.strictEqual(Array.isArray(followingRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(followingRes.status, 200);
@@ -480,36 +480,36 @@ describe('FF visibility', () => {
test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず自分で見れる', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'private',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'private',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
assert.strictEqual(followersRes.status, 200);
assert.strictEqual(Array.isArray(followersRes.body), true);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'private',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, alice);
assert.strictEqual(followersRes.status, 200);
@@ -518,15 +518,15 @@ describe('FF visibility', () => {
});
test('followingVisibility, followersVisibility がともに private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
@@ -536,34 +536,34 @@ describe('FF visibility', () => {
test('followingVisibility が private なユーザーのフォローを followersVisibility の設定に関わらず他人が見れない', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'public',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'followers',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'private',
}, alice);
- const followingRes = await api('/users/following', {
+ const followingRes = await api('users/following', {
userId: alice.id,
}, bob);
assert.strictEqual(followingRes.status, 400);
@@ -572,34 +572,34 @@ describe('FF visibility', () => {
test('followersVisibility が private なユーザーのフォロワーを followingVisibility の設定に関わらず他人が見れない', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
followersVisibility: 'private',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
followersVisibility: 'private',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 400);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
followersVisibility: 'private',
}, alice);
- const followersRes = await api('/users/followers', {
+ const followersRes = await api('users/followers', {
userId: alice.id,
}, bob);
assert.strictEqual(followersRes.status, 400);
@@ -609,7 +609,7 @@ describe('FF visibility', () => {
describe('AP', () => {
test('followingVisibility が public 以外ならばAPからはフォローを取得できない', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'public',
}, alice);
@@ -617,7 +617,7 @@ describe('FF visibility', () => {
assert.strictEqual(followingRes.status, 200);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'followers',
}, alice);
@@ -625,7 +625,7 @@ describe('FF visibility', () => {
assert.strictEqual(followingRes.status, 403);
}
{
- await api('/i/update', {
+ await api('i/update', {
followingVisibility: 'private',
}, alice);
@@ -636,7 +636,7 @@ describe('FF visibility', () => {
test('followersVisibility が public 以外ならばAPからはフォロワーを取得できない', async () => {
{
- await api('/i/update', {
+ await api('i/update', {
followersVisibility: 'public',
}, alice);
@@ -644,7 +644,7 @@ describe('FF visibility', () => {
assert.strictEqual(followersRes.status, 200);
}
{
- await api('/i/update', {
+ await api('i/update', {
followersVisibility: 'followers',
}, alice);
@@ -652,7 +652,7 @@ describe('FF visibility', () => {
assert.strictEqual(followersRes.status, 403);
}
{
- await api('/i/update', {
+ await api('i/update', {
followersVisibility: 'private',
}, alice);
diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts
index f6417e39b5..4e5306da97 100644
--- a/packages/backend/test/e2e/move.ts
+++ b/packages/backend/test/e2e/move.ts
@@ -55,7 +55,7 @@ describe('Account Move', () => {
}, 1000 * 10);
test('Able to create an alias', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
alsoKnownAs: [`@alice@${url.hostname}`],
}, bob);
@@ -67,7 +67,7 @@ describe('Account Move', () => {
});
test('Able to create a local alias without hostname', async () => {
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: ['@alice'],
}, bob);
@@ -77,7 +77,7 @@ describe('Account Move', () => {
});
test('Able to create a local alias without @', async () => {
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: ['alice'],
}, bob);
@@ -87,7 +87,7 @@ describe('Account Move', () => {
});
test('Able to set remote user (but may fail)', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
alsoKnownAs: ['@syuilo@example.com'],
}, bob);
@@ -97,7 +97,7 @@ describe('Account Move', () => {
});
test('Unable to add duplicated aliases to alsoKnownAs', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
alsoKnownAs: [`@alice@${url.hostname}`, `@alice@${url.hostname}`],
}, bob);
@@ -107,7 +107,7 @@ describe('Account Move', () => {
});
test('Unable to add itself', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
alsoKnownAs: [`@bob@${url.hostname}`],
}, bob);
@@ -117,7 +117,7 @@ describe('Account Move', () => {
});
test('Unable to add a nonexisting local account to alsoKnownAs', async () => {
- const res1 = await api('/i/update', {
+ const res1 = await api('i/update', {
alsoKnownAs: [`@nonexist@${url.hostname}`],
}, bob);
@@ -125,7 +125,7 @@ describe('Account Move', () => {
assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER');
assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5');
- const res2 = await api('/i/update', {
+ const res2 = await api('i/update', {
alsoKnownAs: ['@alice', 'nonexist'],
}, bob);
@@ -135,7 +135,7 @@ describe('Account Move', () => {
});
test('Able to add two existing local account to alsoKnownAs', async () => {
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: [`@alice@${url.hostname}`, `@carol@${url.hostname}`],
}, bob);
@@ -146,10 +146,10 @@ describe('Account Move', () => {
});
test('Able to properly overwrite alsoKnownAs', async () => {
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: [`@alice@${url.hostname}`],
}, bob);
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: [`@carol@${url.hostname}`, `@dave@${url.hostname}`],
}, bob);
@@ -164,27 +164,27 @@ describe('Account Move', () => {
let antennaId = '';
beforeAll(async () => {
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: [`@alice@${url.hostname}`],
}, root);
- const listRoot = await api('/users/lists/create', {
+ const listRoot = await api('users/lists/create', {
name: secureRndstr(8),
}, root);
- await api('/users/lists/push', {
+ await api('users/lists/push', {
listId: listRoot.body.id,
userId: alice.id,
}, root);
- await api('/following/create', {
+ await api('following/create', {
userId: root.id,
}, alice);
- await api('/following/create', {
+ await api('following/create', {
userId: eve.id,
}, alice);
- const antenna = await api('/antennas/create', {
+ const antenna = await api('antennas/create', {
name: secureRndstr(8),
src: 'home',
- keywords: [secureRndstr(8)],
+ keywords: [[secureRndstr(8)]],
excludeKeywords: [],
users: [],
caseSensitive: false,
@@ -195,48 +195,48 @@ describe('Account Move', () => {
}, alice);
antennaId = antenna.body.id;
- await api('/i/update', {
+ await api('i/update', {
alsoKnownAs: [`@alice@${url.hostname}`],
}, bob);
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, carol);
- await api('/mute/create', {
+ await api('mute/create', {
userId: alice.id,
}, dave);
- await api('/blocking/create', {
+ await api('blocking/create', {
userId: alice.id,
}, dave);
- await api('/following/create', {
+ await api('following/create', {
userId: eve.id,
}, dave);
- await api('/following/create', {
+ await api('following/create', {
userId: dave.id,
}, eve);
- const listEve = await api('/users/lists/create', {
+ const listEve = await api('users/lists/create', {
name: secureRndstr(8),
}, eve);
- await api('/users/lists/push', {
+ await api('users/lists/push', {
listId: listEve.body.id,
userId: bob.id,
}, eve);
- await api('/i/update', {
+ await api('i/update', {
isLocked: true,
}, frank);
- await api('/following/create', {
+ await api('following/create', {
userId: frank.id,
}, alice);
- await api('/following/requests/accept', {
+ await api('following/requests/accept', {
userId: alice.id,
}, frank);
}, 1000 * 10);
test('Prohibit the root account from moving', async () => {
- const res = await api('/i/move', {
+ const res = await api('i/move', {
moveToAccount: `@bob@${url.hostname}`,
}, root);
@@ -246,7 +246,7 @@ describe('Account Move', () => {
});
test('Unable to move to a nonexisting local account', async () => {
- const res = await api('/i/move', {
+ const res = await api('i/move', {
moveToAccount: `@nonexist@${url.hostname}`,
}, alice);
@@ -256,7 +256,7 @@ describe('Account Move', () => {
});
test('Unable to move if alsoKnownAs is invalid', async () => {
- const res = await api('/i/move', {
+ const res = await api('i/move', {
moveToAccount: `@carol@${url.hostname}`,
}, alice);
@@ -266,7 +266,7 @@ describe('Account Move', () => {
});
test('Relationships have been properly migrated', async () => {
- const move = await api('/i/move', {
+ const move = await api('i/move', {
moveToAccount: `@bob@${url.hostname}`,
}, alice);
@@ -275,13 +275,13 @@ describe('Account Move', () => {
await sleep(1000 * 3); // wait for jobs to finish
// Unfollow delayed?
- const aliceFollowings = await api('/users/following', {
+ const aliceFollowings = await api('users/following', {
userId: alice.id,
}, alice);
assert.strictEqual(aliceFollowings.status, 200);
assert.strictEqual(aliceFollowings.body.length, 3);
- const carolFollowings = await api('/users/following', {
+ const carolFollowings = await api('users/following', {
userId: carol.id,
}, carol);
assert.strictEqual(carolFollowings.status, 200);
@@ -289,25 +289,25 @@ describe('Account Move', () => {
assert.strictEqual(carolFollowings.body[0].followeeId, bob.id);
assert.strictEqual(carolFollowings.body[1].followeeId, alice.id);
- const blockings = await api('/blocking/list', {}, dave);
+ const blockings = await api('blocking/list', {}, dave);
assert.strictEqual(blockings.status, 200);
assert.strictEqual(blockings.body.length, 2);
assert.strictEqual(blockings.body[0].blockeeId, bob.id);
assert.strictEqual(blockings.body[1].blockeeId, alice.id);
- const mutings = await api('/mute/list', {}, dave);
+ const mutings = await api('mute/list', {}, dave);
assert.strictEqual(mutings.status, 200);
assert.strictEqual(mutings.body.length, 2);
assert.strictEqual(mutings.body[0].muteeId, bob.id);
assert.strictEqual(mutings.body[1].muteeId, alice.id);
- const rootLists = await api('/users/lists/list', {}, root);
+ const rootLists = await api('users/lists/list', {}, root);
assert.strictEqual(rootLists.status, 200);
assert.strictEqual(rootLists.body[0].userIds.length, 2);
assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id));
assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id));
- const eveLists = await api('/users/lists/list', {}, eve);
+ const eveLists = await api('users/lists/list', {}, eve);
assert.strictEqual(eveLists.status, 200);
assert.strictEqual(eveLists.body[0].userIds.length, 1);
assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id));
@@ -315,13 +315,13 @@ describe('Account Move', () => {
test('A locked account automatically accept the follow request if it had already accepted the old account.', async () => {
await successfulApiCall({
- endpoint: '/following/create',
+ endpoint: 'following/create',
parameters: {
userId: frank.id,
},
user: bob,
});
- const followers = await api('/users/followers', {
+ const followers = await api('users/followers', {
userId: frank.id,
}, frank);
@@ -333,7 +333,7 @@ describe('Account Move', () => {
test('Unfollowed after 10 sec (24 hours in production).', async () => {
await sleep(1000 * 8);
- const following = await api('/users/following', {
+ const following = await api('users/following', {
userId: alice.id,
}, alice);
@@ -342,7 +342,7 @@ describe('Account Move', () => {
});
test('Unable to move if the destination account has already moved.', async () => {
- const res = await api('/i/move', {
+ const res = await api('i/move', {
moveToAccount: `@alice@${url.hostname}`,
}, bob);
@@ -352,7 +352,7 @@ describe('Account Move', () => {
});
test('Follow and follower counts are properly adjusted', async () => {
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, eve);
const newAlice = await Users.findOneByOrFail({ id: alice.id });
@@ -365,7 +365,7 @@ describe('Account Move', () => {
assert.strictEqual(newEve.followingCount, 1);
assert.strictEqual(newEve.followersCount, 1);
- await api('/following/delete', {
+ await api('following/delete', {
userId: alice.id,
}, eve);
newEve = await Users.findOneByOrFail({ id: eve.id });
@@ -374,49 +374,49 @@ describe('Account Move', () => {
});
test.each([
- '/antennas/create',
- '/channels/create',
- '/channels/favorite',
- '/channels/follow',
- '/channels/unfavorite',
- '/channels/unfollow',
- '/clips/add-note',
- '/clips/create',
- '/clips/favorite',
- '/clips/remove-note',
- '/clips/unfavorite',
- '/clips/update',
- '/drive/files/upload-from-url',
- '/flash/create',
- '/flash/like',
- '/flash/unlike',
- '/flash/update',
- '/following/create',
- '/gallery/posts/create',
- '/gallery/posts/like',
- '/gallery/posts/unlike',
- '/gallery/posts/update',
- '/i/claim-achievement',
- '/i/move',
- '/i/import-blocking',
- '/i/import-following',
- '/i/import-muting',
- '/i/import-user-lists',
- '/i/pin',
- '/mute/create',
- '/notes/create',
- '/notes/favorites/create',
- '/notes/polls/vote',
- '/notes/reactions/create',
- '/pages/create',
- '/pages/like',
- '/pages/unlike',
- '/pages/update',
- '/renote-mute/create',
- '/users/lists/create',
- '/users/lists/pull',
- '/users/lists/push',
- ])('Prohibit access after moving: %s', async (endpoint) => {
+ 'antennas/create',
+ 'channels/create',
+ 'channels/favorite',
+ 'channels/follow',
+ 'channels/unfavorite',
+ 'channels/unfollow',
+ 'clips/add-note',
+ 'clips/create',
+ 'clips/favorite',
+ 'clips/remove-note',
+ 'clips/unfavorite',
+ 'clips/update',
+ 'drive/files/upload-from-url',
+ 'flash/create',
+ 'flash/like',
+ 'flash/unlike',
+ 'flash/update',
+ 'following/create',
+ 'gallery/posts/create',
+ 'gallery/posts/like',
+ 'gallery/posts/unlike',
+ 'gallery/posts/update',
+ 'i/claim-achievement',
+ 'i/move',
+ 'i/import-blocking',
+ 'i/import-following',
+ 'i/import-muting',
+ 'i/import-user-lists',
+ 'i/pin',
+ 'mute/create',
+ 'notes/create',
+ 'notes/favorites/create',
+ 'notes/polls/vote',
+ 'notes/reactions/create',
+ 'pages/create',
+ 'pages/like',
+ 'pages/unlike',
+ 'pages/update',
+ 'renote-mute/create',
+ 'users/lists/create',
+ 'users/lists/pull',
+ 'users/lists/push',
+ ] as const)('Prohibit access after moving: %s', async (endpoint) => {
const res = await api(endpoint, {}, alice);
assert.strictEqual(res.status, 403);
assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
@@ -424,11 +424,11 @@ describe('Account Move', () => {
});
test('Prohibit access after moving: /antennas/update', async () => {
- const res = await api('/antennas/update', {
+ const res = await api('antennas/update', {
antennaId,
name: secureRndstr(8),
src: 'users',
- keywords: [secureRndstr(8)],
+ keywords: [[secureRndstr(8)]],
excludeKeywords: [],
users: [eve.id],
caseSensitive: false,
@@ -447,12 +447,12 @@ describe('Account Move', () => {
const res = await uploadFile(alice);
assert.strictEqual(res.status, 403);
- assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED');
- assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
+ assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.code, 'YOUR_ACCOUNT_MOVED');
+ assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31');
});
test('Prohibit updating alsoKnownAs after moving', async () => {
- const res = await api('/i/update', {
+ const res = await api('i/update', {
alsoKnownAs: [`@eve@${url.hostname}`],
}, alice);
diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts
index 1d28e07b7d..0e52c5decc 100644
--- a/packages/backend/test/e2e/mute.ts
+++ b/packages/backend/test/e2e/mute.ts
@@ -19,21 +19,31 @@ describe('Mute', () => {
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });
carol = await signup({ username: 'carol' });
+
+ // Mute: alice ==> carol
+ await api('mute/create', {
+ userId: carol.id,
+ }, alice);
}, 1000 * 60 * 2);
test('ミュート作成', async () => {
- const res = await api('/mute/create', {
- userId: carol.id,
+ const res = await api('mute/create', {
+ userId: bob.id,
}, alice);
assert.strictEqual(res.status, 204);
+
+ // 単体でも走らせられるように副作用消す
+ await api('mute/delete', {
+ userId: bob.id,
+ }, alice);
});
test('「自分宛ての投稿」にミュートしているユーザーの投稿が含まれない', async () => {
const bobNote = await post(bob, { text: '@alice hi' });
const carolNote = await post(carol, { text: '@alice hi' });
- const res = await api('/notes/mentions', {}, alice);
+ const res = await api('notes/mentions', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -43,11 +53,11 @@ describe('Mute', () => {
test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => {
// 状態リセット
- await api('/i/read-all-unread-notes', {}, alice);
+ await api('i/read-all-unread-notes', {}, alice);
await post(carol, { text: '@alice hi' });
- const res = await api('/i', {}, alice);
+ const res = await api('i', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(res.body.hasUnreadMentions, false);
@@ -55,7 +65,7 @@ describe('Mute', () => {
test('ミュートしているユーザーからメンションされても、ストリームに unreadMention イベントが流れてこない', async () => {
// 状態リセット
- await api('/i/read-all-unread-notes', {}, alice);
+ await api('i/read-all-unread-notes', {}, alice);
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadMention');
@@ -64,8 +74,8 @@ describe('Mute', () => {
test('ミュートしているユーザーからメンションされても、ストリームに unreadNotification イベントが流れてこない', async () => {
// 状態リセット
- await api('/i/read-all-unread-notes', {}, alice);
- await api('/notifications/mark-all-as-read', {}, alice);
+ await api('i/read-all-unread-notes', {}, alice);
+ await api('notifications/mark-all-as-read', {}, alice);
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadNotification');
@@ -78,7 +88,7 @@ describe('Mute', () => {
const bobNote = await post(bob, { text: 'hi' });
const carolNote = await post(carol, { text: 'hi' });
- const res = await api('/notes/local-timeline', {}, alice);
+ const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -94,7 +104,7 @@ describe('Mute', () => {
renoteId: carolNote.id,
});
- const res = await api('/notes/local-timeline', {}, alice);
+ const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -110,7 +120,7 @@ describe('Mute', () => {
await react(bob, aliceNote, 'like');
await react(carol, aliceNote, 'like');
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -123,7 +133,7 @@ describe('Mute', () => {
await post(bob, { text: '@alice hi', replyId: aliceNote.id });
await post(carol, { text: '@alice hi', replyId: aliceNote.id });
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -137,7 +147,7 @@ describe('Mute', () => {
await post(bob, { text: '@alice hi' });
await post(carol, { text: '@alice hi' });
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -151,7 +161,7 @@ describe('Mute', () => {
await post(bob, { text: 'hi', renoteId: aliceNote.id });
await post(carol, { text: 'hi', renoteId: aliceNote.id });
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -165,7 +175,7 @@ describe('Mute', () => {
await post(bob, { renoteId: aliceNote.id });
await post(carol, { renoteId: aliceNote.id });
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -175,30 +185,36 @@ describe('Mute', () => {
});
test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
- await api('/i/follow', { userId: alice.id }, bob);
- await api('/i/follow', { userId: alice.id }, carol);
+ await api('following/create', { userId: alice.id }, bob);
+ await api('following/create', { userId: alice.id }, carol);
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+
+ await api('following/delete', { userId: alice.id }, bob);
+ await api('following/delete', { userId: alice.id }, carol);
});
test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
- await api('/i/update/', { isLocked: true }, alice);
- await api('/following/create', { userId: alice.id }, bob);
- await api('/following/create', { userId: alice.id }, carol);
+ await api('i/update', { isLocked: true }, alice);
+ await api('following/create', { userId: alice.id }, bob);
+ await api('following/create', { userId: alice.id }, carol);
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+
+ await api('following/delete', { userId: alice.id }, bob);
+ await api('following/delete', { userId: alice.id }, carol);
});
});
@@ -208,7 +224,7 @@ describe('Mute', () => {
await react(bob, aliceNote, 'like');
await react(carol, aliceNote, 'like');
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -220,7 +236,7 @@ describe('Mute', () => {
await post(bob, { text: '@alice hi', replyId: aliceNote.id });
await post(carol, { text: '@alice hi', replyId: aliceNote.id });
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -234,7 +250,7 @@ describe('Mute', () => {
await post(bob, { text: '@alice hi' });
await post(carol, { text: '@alice hi' });
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -248,7 +264,7 @@ describe('Mute', () => {
await post(bob, { text: 'hi', renoteId: aliceNote.id });
await post(carol, { text: 'hi', renoteId: aliceNote.id });
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -262,7 +278,7 @@ describe('Mute', () => {
await post(bob, { renoteId: aliceNote.id });
await post(carol, { renoteId: aliceNote.id });
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -272,24 +288,27 @@ describe('Mute', () => {
});
test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => {
- await api('/i/follow', { userId: alice.id }, bob);
- await api('/i/follow', { userId: alice.id }, carol);
+ await api('following/create', { userId: alice.id }, bob);
+ await api('following/create', { userId: alice.id }, carol);
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true);
assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false);
+
+ await api('following/delete', { userId: alice.id }, bob);
+ await api('following/delete', { userId: alice.id }, carol);
});
test('通知にミュートしているユーザーからのフォローリクエストが含まれない', async () => {
- await api('/i/update/', { isLocked: true }, alice);
- await api('/following/create', { userId: alice.id }, bob);
- await api('/following/create', { userId: alice.id }, carol);
+ await api('i/update', { isLocked: true }, alice);
+ await api('following/create', { userId: alice.id }, bob);
+ await api('following/create', { userId: alice.id }, carol);
- const res = await api('/i/notifications-grouped', {}, alice);
+ const res = await api('i/notifications-grouped', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts
index 2406204f41..973bcbd750 100644
--- a/packages/backend/test/e2e/note.ts
+++ b/packages/backend/test/e2e/note.ts
@@ -31,7 +31,7 @@ describe('Note', () => {
text: 'test',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -41,7 +41,7 @@ describe('Note', () => {
test('ファイルを添付できる', async () => {
const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
fileIds: [file.id],
}, alice);
@@ -53,7 +53,7 @@ describe('Note', () => {
test('他人のファイルで怒られる', async () => {
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
text: 'test',
fileIds: [file.id],
}, alice);
@@ -64,7 +64,7 @@ describe('Note', () => {
}, 1000 * 10);
test('存在しないファイルで怒られる', async () => {
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
text: 'test',
fileIds: ['000000000000000000000000'],
}, alice);
@@ -75,7 +75,7 @@ describe('Note', () => {
});
test('不正なファイルIDで怒られる', async () => {
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
fileIds: ['kyoppie'],
}, alice);
assert.strictEqual(res.status, 400);
@@ -93,7 +93,7 @@ describe('Note', () => {
replyId: bobPost.id,
};
- const res = await api('/notes/create', alicePost, alice);
+ const res = await api('notes/create', alicePost, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -111,7 +111,7 @@ describe('Note', () => {
renoteId: bobPost.id,
};
- const res = await api('/notes/create', alicePost, alice);
+ const res = await api('notes/create', alicePost, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -129,7 +129,7 @@ describe('Note', () => {
renoteId: bobPost.id,
};
- const res = await api('/notes/create', alicePost, alice);
+ const res = await api('notes/create', alicePost, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -142,7 +142,7 @@ describe('Note', () => {
const bobPost = await post(bob, {
text: 'test',
});
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
text: ' ',
renoteId: bobPost.id,
}, alice);
@@ -152,7 +152,7 @@ describe('Note', () => {
});
test('visibility: followersでrenoteできる', async () => {
- const createRes = await api('/notes/create', {
+ const createRes = await api('notes/create', {
text: 'test',
visibility: 'followers',
}, alice);
@@ -160,7 +160,7 @@ describe('Note', () => {
assert.strictEqual(createRes.status, 200);
const renoteId = createRes.body.createdNote.id;
- const renoteRes = await api('/notes/create', {
+ const renoteRes = await api('notes/create', {
visibility: 'followers',
renoteId,
}, alice);
@@ -169,7 +169,7 @@ describe('Note', () => {
assert.strictEqual(renoteRes.body.createdNote.renoteId, renoteId);
assert.strictEqual(renoteRes.body.createdNote.visibility, 'followers');
- const deleteRes = await api('/notes/delete', {
+ const deleteRes = await api('notes/delete', {
noteId: renoteRes.body.createdNote.id,
}, alice);
@@ -177,11 +177,11 @@ describe('Note', () => {
});
test('visibility: followersなノートに対してフォロワーはリプライできる', async () => {
- await api('/following/create', {
+ await api('following/create', {
userId: alice.id,
}, bob);
- const aliceNote = await api('/notes/create', {
+ const aliceNote = await api('notes/create', {
text: 'direct note to bob',
visibility: 'followers',
}, alice);
@@ -189,7 +189,7 @@ describe('Note', () => {
assert.strictEqual(aliceNote.status, 200);
const replyId = aliceNote.body.createdNote.id;
- const bobReply = await api('/notes/create', {
+ const bobReply = await api('notes/create', {
text: 'reply to alice note',
replyId,
}, bob);
@@ -197,20 +197,20 @@ describe('Note', () => {
assert.strictEqual(bobReply.status, 200);
assert.strictEqual(bobReply.body.createdNote.replyId, replyId);
- await api('/following/delete', {
+ await api('following/delete', {
userId: alice.id,
}, bob);
});
test('visibility: followersなノートに対してフォロワーでないユーザーがリプライしようとすると怒られる', async () => {
- const aliceNote = await api('/notes/create', {
+ const aliceNote = await api('notes/create', {
text: 'direct note to bob',
visibility: 'followers',
}, alice);
assert.strictEqual(aliceNote.status, 200);
- const bobReply = await api('/notes/create', {
+ const bobReply = await api('notes/create', {
text: 'reply to alice note',
replyId: aliceNote.body.createdNote.id,
}, bob);
@@ -220,7 +220,7 @@ describe('Note', () => {
});
test('visibility: specifiedなノートに対してvisibility: specifiedで返信できる', async () => {
- const aliceNote = await api('/notes/create', {
+ const aliceNote = await api('notes/create', {
text: 'direct note to bob',
visibility: 'specified',
visibleUserIds: [bob.id],
@@ -228,7 +228,7 @@ describe('Note', () => {
assert.strictEqual(aliceNote.status, 200);
- const bobReply = await api('/notes/create', {
+ const bobReply = await api('notes/create', {
text: 'reply to alice note',
replyId: aliceNote.body.createdNote.id,
visibility: 'specified',
@@ -239,7 +239,7 @@ describe('Note', () => {
});
test('visibility: specifiedなノートに対してvisibility: follwersで返信しようとすると怒られる', async () => {
- const aliceNote = await api('/notes/create', {
+ const aliceNote = await api('notes/create', {
text: 'direct note to bob',
visibility: 'specified',
visibleUserIds: [bob.id],
@@ -247,7 +247,7 @@ describe('Note', () => {
assert.strictEqual(aliceNote.status, 200);
- const bobReply = await api('/notes/create', {
+ const bobReply = await api('notes/create', {
text: 'reply to alice note with visibility: followers',
replyId: aliceNote.body.createdNote.id,
visibility: 'followers',
@@ -261,7 +261,7 @@ describe('Note', () => {
const post = {
text: '!'.repeat(MAX_NOTE_TEXT_LENGTH), // 3000文字
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 200);
});
@@ -269,7 +269,7 @@ describe('Note', () => {
const post = {
text: '!'.repeat(MAX_NOTE_TEXT_LENGTH + 1), // 3001文字
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 400);
});
@@ -278,7 +278,7 @@ describe('Note', () => {
text: 'test',
replyId: '000000000000000000000000',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 400);
});
@@ -286,7 +286,7 @@ describe('Note', () => {
const post = {
renoteId: '000000000000000000000000',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 400);
});
@@ -295,7 +295,7 @@ describe('Note', () => {
text: 'test',
replyId: 'foo',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 400);
});
@@ -303,7 +303,7 @@ describe('Note', () => {
const post = {
renoteId: 'foo',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 400);
});
@@ -312,7 +312,7 @@ describe('Note', () => {
text: '@ghost yo',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -324,7 +324,7 @@ describe('Note', () => {
text: '@bob @bob @bob yo',
};
- const res = await api('/notes/create', post, alice);
+ const res = await api('notes/create', post, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
@@ -337,25 +337,25 @@ describe('Note', () => {
describe('添付ファイル情報', () => {
test('ファイルを添付した場合、投稿成功時にファイル情報入りのレスポンスが帰ってくる', async () => {
const file = await uploadFile(alice);
- const res = await api('/notes/create', {
- fileIds: [file.body.id],
+ const res = await api('notes/create', {
+ fileIds: [file.body!.id],
}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
assert.strictEqual(res.body.createdNote.files.length, 1);
- assert.strictEqual(res.body.createdNote.files[0].id, file.body.id);
+ assert.strictEqual(res.body.createdNote.files[0].id, file.body!.id);
});
test('ファイルを添付した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
const file = await uploadFile(alice);
- const createdNote = await api('/notes/create', {
- fileIds: [file.body.id],
+ const createdNote = await api('notes/create', {
+ fileIds: [file.body!.id],
}, alice);
assert.strictEqual(createdNote.status, 200);
- const res = await api('/notes', {
+ const res = await api('notes', {
withFiles: true,
}, alice);
@@ -364,23 +364,23 @@ describe('Note', () => {
const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id);
assert.notEqual(myNote, null);
assert.strictEqual(myNote.files.length, 1);
- assert.strictEqual(myNote.files[0].id, file.body.id);
+ assert.strictEqual(myNote.files[0].id, file.body!.id);
});
test('ファイルが添付されたノートをリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
const file = await uploadFile(alice);
- const createdNote = await api('/notes/create', {
- fileIds: [file.body.id],
+ const createdNote = await api('notes/create', {
+ fileIds: [file.body!.id],
}, alice);
assert.strictEqual(createdNote.status, 200);
- const renoted = await api('/notes/create', {
+ const renoted = await api('notes/create', {
renoteId: createdNote.body.createdNote.id,
}, alice);
assert.strictEqual(renoted.status, 200);
- const res = await api('/notes', {
+ const res = await api('notes', {
renote: true,
}, alice);
@@ -389,24 +389,24 @@ describe('Note', () => {
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
assert.notEqual(myNote, null);
assert.strictEqual(myNote.renote.files.length, 1);
- assert.strictEqual(myNote.renote.files[0].id, file.body.id);
+ assert.strictEqual(myNote.renote.files[0].id, file.body!.id);
});
test('ファイルが添付されたノートに返信した場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
const file = await uploadFile(alice);
- const createdNote = await api('/notes/create', {
- fileIds: [file.body.id],
+ const createdNote = await api('notes/create', {
+ fileIds: [file.body!.id],
}, alice);
assert.strictEqual(createdNote.status, 200);
- const reply = await api('/notes/create', {
+ const reply = await api('notes/create', {
replyId: createdNote.body.createdNote.id,
text: 'this is reply',
}, alice);
assert.strictEqual(reply.status, 200);
- const res = await api('/notes', {
+ const res = await api('notes', {
reply: true,
}, alice);
@@ -415,29 +415,29 @@ describe('Note', () => {
const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id);
assert.notEqual(myNote, null);
assert.strictEqual(myNote.reply.files.length, 1);
- assert.strictEqual(myNote.reply.files[0].id, file.body.id);
+ assert.strictEqual(myNote.reply.files[0].id, file.body!.id);
});
test('ファイルが添付されたノートへの返信をリノートした場合、タイムラインでファイル情報入りのレスポンスが帰ってくる', async () => {
const file = await uploadFile(alice);
- const createdNote = await api('/notes/create', {
- fileIds: [file.body.id],
+ const createdNote = await api('notes/create', {
+ fileIds: [file.body!.id],
}, alice);
assert.strictEqual(createdNote.status, 200);
- const reply = await api('/notes/create', {
+ const reply = await api('notes/create', {
replyId: createdNote.body.createdNote.id,
text: 'this is reply',
}, alice);
assert.strictEqual(reply.status, 200);
- const renoted = await api('/notes/create', {
+ const renoted = await api('notes/create', {
renoteId: reply.body.createdNote.id,
}, alice);
assert.strictEqual(renoted.status, 200);
- const res = await api('/notes', {
+ const res = await api('notes', {
renote: true,
}, alice);
@@ -446,7 +446,7 @@ describe('Note', () => {
const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id);
assert.notEqual(myNote, null);
assert.strictEqual(myNote.renote.reply.files.length, 1);
- assert.strictEqual(myNote.renote.reply.files[0].id, file.body.id);
+ assert.strictEqual(myNote.renote.reply.files[0].id, file.body!.id);
});
test('NSFWが強制されている場合変更できない', async () => {
@@ -483,15 +483,15 @@ describe('Note', () => {
}, alice);
assert.strictEqual(assign.status, 204);
- assert.strictEqual(file.body.isSensitive, false);
+ assert.strictEqual(file.body!.isSensitive, false);
const nsfwfile = await uploadFile(alice);
assert.strictEqual(nsfwfile.status, 200);
- assert.strictEqual(nsfwfile.body.isSensitive, true);
+ assert.strictEqual(nsfwfile.body!.isSensitive, true);
const liftnsfw = await api('drive/files/update', {
- fileId: nsfwfile.body.id,
+ fileId: nsfwfile.body!.id,
isSensitive: false,
}, alice);
@@ -499,7 +499,7 @@ describe('Note', () => {
assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE');
const oldaddnsfw = await api('drive/files/update', {
- fileId: file.body.id,
+ fileId: file.body!.id,
isSensitive: true,
}, alice);
@@ -518,7 +518,7 @@ describe('Note', () => {
describe('notes/create', () => {
test('投票を添付できる', async () => {
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
text: 'test',
poll: {
choices: ['foo', 'bar'],
@@ -531,14 +531,15 @@ describe('Note', () => {
});
test('投票の選択肢が無くて怒られる', async () => {
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
+ // @ts-expect-error poll must not be empty
poll: {},
}, alice);
assert.strictEqual(res.status, 400);
});
test('投票の選択肢が無くて怒られる (空の配列)', async () => {
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
poll: {
choices: [],
},
@@ -547,7 +548,7 @@ describe('Note', () => {
});
test('投票の選択肢が1つで怒られる', async () => {
- const res = await api('/notes/create', {
+ const res = await api('notes/create', {
poll: {
choices: ['Strawberry Pasta'],
},
@@ -556,14 +557,14 @@ describe('Note', () => {
});
test('投票できる', async () => {
- const { body } = await api('/notes/create', {
+ const { body } = await api('notes/create', {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako'],
},
}, alice);
- const res = await api('/notes/polls/vote', {
+ const res = await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 1,
}, alice);
@@ -572,19 +573,19 @@ describe('Note', () => {
});
test('複数投票できない', async () => {
- const { body } = await api('/notes/create', {
+ const { body } = await api('notes/create', {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako'],
},
}, alice);
- await api('/notes/polls/vote', {
+ await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 0,
}, alice);
- const res = await api('/notes/polls/vote', {
+ const res = await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 2,
}, alice);
@@ -593,7 +594,7 @@ describe('Note', () => {
});
test('許可されている場合は複数投票できる', async () => {
- const { body } = await api('/notes/create', {
+ const { body } = await api('notes/create', {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako'],
@@ -601,17 +602,17 @@ describe('Note', () => {
},
}, alice);
- await api('/notes/polls/vote', {
+ await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 0,
}, alice);
- await api('/notes/polls/vote', {
+ await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 1,
}, alice);
- const res = await api('/notes/polls/vote', {
+ const res = await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 2,
}, alice);
@@ -620,7 +621,7 @@ describe('Note', () => {
});
test('締め切られている場合は投票できない', async () => {
- const { body } = await api('/notes/create', {
+ const { body } = await api('notes/create', {
text: 'test',
poll: {
choices: ['sakura', 'izumi', 'ako'],
@@ -630,7 +631,7 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const res = await api('/notes/polls/vote', {
+ const res = await api('notes/polls/vote', {
noteId: body.createdNote.id,
choice: 1,
}, alice);
@@ -649,7 +650,7 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const note1 = await api('/notes/create', {
+ const note1 = await api('notes/create', {
text: 'hogetesthuge',
}, alice);
@@ -666,7 +667,7 @@ describe('Note', () => {
assert.strictEqual(sensitive.status, 204);
- const note2 = await api('/notes/create', {
+ const note2 = await api('notes/create', {
text: 'hogetesthuge',
}, alice);
@@ -683,7 +684,7 @@ describe('Note', () => {
assert.strictEqual(sensitive.status, 204);
- const note2 = await api('/notes/create', {
+ const note2 = await api('notes/create', {
text: 'hogeTesthuge',
}, alice);
@@ -702,7 +703,7 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const note1 = await api('/notes/create', {
+ const note1 = await api('notes/create', {
text: 'hogetesthuge',
}, alice);
@@ -719,7 +720,7 @@ describe('Note', () => {
assert.strictEqual(prohibited.status, 204);
- const note2 = await api('/notes/create', {
+ const note2 = await api('notes/create', {
text: 'hogetesthuge',
}, alice);
@@ -736,7 +737,7 @@ describe('Note', () => {
assert.strictEqual(prohibited.status, 204);
- const note2 = await api('/notes/create', {
+ const note2 = await api('notes/create', {
text: 'hogeTesthuge',
}, alice);
@@ -755,7 +756,7 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const note1 = await api('/notes/create', {
+ const note1 = await api('notes/create', {
text: 'hogetesthuge',
}, tom);
@@ -799,7 +800,7 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const note = await api('/notes/create', {
+ const note = await api('notes/create', {
text: '@bob potentially annoying text',
}, alice);
@@ -853,10 +854,10 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const note = await api('/notes/create', {
+ const note = await api('notes/create', {
text: 'potentially annoying text',
visibility: 'specified',
- visibleUserIds: [ bob.id ],
+ visibleUserIds: [bob.id],
}, alice);
assert.strictEqual(note.status, 400);
@@ -909,10 +910,10 @@ describe('Note', () => {
await new Promise(x => setTimeout(x, 2));
- const note = await api('/notes/create', {
+ const note = await api('notes/create', {
text: '@bob potentially annoying text',
visibility: 'specified',
- visibleUserIds: [ bob.id ],
+ visibleUserIds: [bob.id],
}, alice);
assert.strictEqual(note.status, 200);
diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts
index 403de0cb8d..9826068e48 100644
--- a/packages/backend/test/e2e/renote-mute.ts
+++ b/packages/backend/test/e2e/renote-mute.ts
@@ -22,7 +22,7 @@ describe('Renote Mute', () => {
}, 1000 * 60 * 2);
test('ミュート作成', async () => {
- const res = await api('/renote-mute/create', {
+ const res = await api('renote-mute/create', {
userId: carol.id,
}, alice);
@@ -37,7 +37,7 @@ describe('Renote Mute', () => {
// redisに追加されるのを待つ
await sleep(100);
- const res = await api('/notes/local-timeline', {}, alice);
+ const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -54,7 +54,7 @@ describe('Renote Mute', () => {
// redisに追加されるのを待つ
await sleep(100);
- const res = await api('/notes/local-timeline', {}, alice);
+ const res = await api('notes/local-timeline', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts
index 57ce73ba60..edb930617f 100644
--- a/packages/backend/test/e2e/streaming.ts
+++ b/packages/backend/test/e2e/streaming.ts
@@ -601,7 +601,7 @@ describe('Streaming', () => {
// #10443
test('ミュートしているサーバのノートがリストTLに流れない', async () => {
- await api('/i/update', {
+ await api('i/update', {
mutedInstances: ['example.com'],
}, chitose);
@@ -618,7 +618,7 @@ describe('Streaming', () => {
// #10443
test('ミュートしているサーバのノートに対するリプライがリストTLに流れない', async () => {
- await api('/i/update', {
+ await api('i/update', {
mutedInstances: ['example.com'],
}, chitose);
@@ -635,7 +635,7 @@ describe('Streaming', () => {
// #10443
test('ミュートしているサーバのノートに対するリノートがリストTLに流れない', async () => {
- await api('/i/update', {
+ await api('i/update', {
mutedInstances: ['example.com'],
}, chitose);
diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts
index b4570cdef1..53bb6eb765 100644
--- a/packages/backend/test/e2e/thread-mute.ts
+++ b/packages/backend/test/e2e/thread-mute.ts
@@ -24,12 +24,12 @@ describe('Note thread mute', () => {
const bobNote = await post(bob, { text: '@alice @carol root note' });
const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
- await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+ await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
- const res = await api('/notes/mentions', {}, alice);
+ const res = await api('notes/mentions', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
@@ -40,15 +40,15 @@ describe('Note thread mute', () => {
test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => {
// 状態リセット
- await api('/i/read-all-unread-notes', {}, alice);
+ await api('i/read-all-unread-notes', {}, alice);
const bobNote = await post(bob, { text: '@alice @carol root note' });
- await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+ await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
- const res = await api('/i', {}, alice);
+ const res = await api('i', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(res.body.hasUnreadMentions, false);
@@ -56,11 +56,11 @@ describe('Note thread mute', () => {
test('ミュートしているスレッドからメンションされても、ストリームに unreadMention イベントが流れてこない', () => new Promise(async done => {
// 状態リセット
- await api('/i/read-all-unread-notes', {}, alice);
+ await api('i/read-all-unread-notes', {}, alice);
const bobNote = await post(bob, { text: '@alice @carol root note' });
- await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+ await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
let fired = false;
@@ -84,12 +84,12 @@ describe('Note thread mute', () => {
const bobNote = await post(bob, { text: '@alice @carol root note' });
const aliceReply = await post(alice, { replyId: bobNote.id, text: '@bob @carol child note' });
- await api('/notes/thread-muting/create', { noteId: bobNote.id }, alice);
+ await api('notes/thread-muting/create', { noteId: bobNote.id }, alice);
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
const carolReplyWithoutMention = await post(carol, { replyId: aliceReply.id, text: 'child note' });
- const res = await api('/i/notifications', {}, alice);
+ const res = await api('i/notifications', {}, alice);
assert.strictEqual(res.status, 200);
assert.strictEqual(Array.isArray(res.body), true);
diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts
index 0e71d707dd..d413703ede 100644
--- a/packages/backend/test/e2e/timelines.ts
+++ b/packages/backend/test/e2e/timelines.ts
@@ -26,7 +26,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -35,14 +35,14 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーのノートが含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi' });
const carolNote = await post(carol, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -51,14 +51,14 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
const carolNote = await post(carol, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -68,14 +68,14 @@ describe('Timelines', () => {
test.concurrent('withReplies: false でフォローしているユーザーの他人への返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -84,15 +84,15 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーの他人への返信が含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -101,15 +101,15 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーの他人へのDM返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -118,15 +118,15 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーの他人の visibility: followers な投稿への返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -135,17 +135,17 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの visibility: followers な投稿への返信が含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/create', { userId: carol.id }, alice);
- await api('/following/create', { userId: carol.id }, bob);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: carol.id }, bob);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi', visibility: 'followers' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -155,16 +155,16 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの投稿への visibility: specified な返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/create', { userId: carol.id }, alice);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: carol.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -173,14 +173,14 @@ describe('Timelines', () => {
test.concurrent('withReplies: false でフォローしているユーザーのそのユーザー自身への返信が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -189,14 +189,14 @@ describe('Timelines', () => {
test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
@@ -210,7 +210,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
@@ -219,14 +219,14 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの他人の投稿のリノートが含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { renoteId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -235,14 +235,14 @@ describe('Timelines', () => {
test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿のリノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { renoteId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', {
+ const res = await api('notes/timeline', {
withRenotes: false,
}, alice);
@@ -253,14 +253,14 @@ describe('Timelines', () => {
test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿の引用が含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', {
+ const res = await api('notes/timeline', {
withRenotes: false,
}, alice);
@@ -271,13 +271,13 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの他人への visibility: specified なノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -285,15 +285,15 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/mute/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('mute/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -302,16 +302,16 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
- await api('/mute/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('mute/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -321,13 +321,13 @@ describe('Timelines', () => {
const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
const bobNote = await post(bob, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -336,13 +336,13 @@ describe('Timelines', () => {
const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -350,7 +350,7 @@ describe('Timelines', () => {
test.concurrent('[withFiles: true] フォローしているユーザーのファイル付きノートのみ含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const [bobFile, carolFile] = await Promise.all([
uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'),
@@ -363,7 +363,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100, withFiles: true }, alice);
+ const res = await api('notes/timeline', { limit: 100, withFiles: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -374,14 +374,14 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーのチャンネル投稿が含まれない', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
- await api('/following/create', { userId: bob.id }, alice);
+ const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -393,7 +393,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -402,13 +402,13 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定した visibility: specified なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -421,7 +421,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -429,13 +429,13 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定していない visibility: specified なノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -448,7 +448,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'ok');
@@ -463,7 +463,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'ok');
@@ -479,7 +479,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/timeline', { limit: 100 }, alice);
+ const res = await api('notes/timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -494,7 +494,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -508,7 +508,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -522,7 +522,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -531,12 +531,12 @@ describe('Timelines', () => {
test.concurrent('チャンネル投稿が含まれない', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
+ const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -548,7 +548,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -557,14 +557,14 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの visibility: home なノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi', visibility: 'home' });
const bobNote = await post(bob, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -573,14 +573,14 @@ describe('Timelines', () => {
test.concurrent('ミュートしているユーザーのノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/mute/create', { userId: carol.id }, alice);
+ await api('mute/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -589,15 +589,15 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/mute/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('mute/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -606,16 +606,16 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- await api('/following/update', { userId: bob.id, withReplies: true }, alice);
- await api('/mute/create', { userId: carol.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ await api('following/update', { userId: bob.id, withReplies: true }, alice);
+ await api('mute/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
@@ -624,14 +624,14 @@ describe('Timelines', () => {
test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
@@ -645,7 +645,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100, withReplies: true }, alice);
+ const res = await api('notes/local-timeline', { limit: 100, withReplies: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -659,7 +659,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100, withFiles: true }, alice);
+ const res = await api('notes/local-timeline', { limit: 100, withFiles: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -674,7 +674,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -686,7 +686,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -694,13 +694,13 @@ describe('Timelines', () => {
test.concurrent('フォローしているローカルユーザーの visibility: home なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -708,14 +708,14 @@ describe('Timelines', () => {
test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
@@ -729,7 +729,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true);
@@ -742,7 +742,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/local-timeline', { limit: 100 }, alice);
+ const res = await api('notes/local-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -751,13 +751,13 @@ describe('Timelines', () => {
const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
const bobNote = await post(bob, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -766,13 +766,13 @@ describe('Timelines', () => {
const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]);
await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' });
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100 }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100 }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -785,7 +785,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100, withReplies: true }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100, withReplies: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -799,7 +799,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/notes/hybrid-timeline', { limit: 100, withFiles: true }, alice);
+ const res = await api('notes/hybrid-timeline', { limit: 100, withFiles: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -810,14 +810,14 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしていないユーザーのノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi' });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -825,14 +825,14 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしていないユーザーの visibility: home なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -840,14 +840,14 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしていないユーザーの visibility: followers なノートが含まれない', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -855,15 +855,15 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしていないユーザーの他人への返信が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -871,15 +871,15 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしていないユーザーのユーザー自身への返信が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -888,15 +888,15 @@ describe('Timelines', () => {
test.concurrent('withReplies: false でリスインしているフォローしていないユーザーからの自分への返信が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const aliceNote = await post(alice, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id, withReplies: false }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id, withReplies: false }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -904,16 +904,16 @@ describe('Timelines', () => {
test.concurrent('withReplies: true でリスインしているフォローしていないユーザーの他人への返信が含まれる', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await api('/users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -921,15 +921,15 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしているユーザーの visibility: home なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'home' });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -937,15 +937,15 @@ describe('Timelines', () => {
test.concurrent('リスインしているフォローしているユーザーの visibility: followers なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -954,14 +954,14 @@ describe('Timelines', () => {
test.concurrent('リスインしている自分の visibility: followers なノートが含まれる', async () => {
const [alice] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: alice.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: alice.id }, alice);
await sleep(1000);
const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -970,15 +970,15 @@ describe('Timelines', () => {
test.concurrent('リスインしているユーザーのチャンネルノートが含まれない', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -986,15 +986,15 @@ describe('Timelines', () => {
test.concurrent('[withFiles: true] リスインしているユーザーのファイル付きノートのみ含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png');
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { fileIds: [file.id] });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id, withFiles: true }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id, withFiles: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1003,14 +1003,14 @@ describe('Timelines', () => {
test.concurrent('リスインしているユーザーの自身宛ての visibility: specified なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -1019,15 +1019,15 @@ describe('Timelines', () => {
test.concurrent('リスインしているユーザーの自身宛てではない visibility: specified なノートが含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body);
- await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice);
- await api('/users/lists/push', { listId: list.id, userId: carol.id }, alice);
+ const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body);
+ await api('users/lists/push', { listId: list.id, userId: bob.id }, alice);
+ await api('users/lists/push', { listId: list.id, userId: carol.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] });
await waitForPushToTl();
- const res = await api('/notes/user-list-timeline', { listId: list.id }, alice);
+ const res = await api('notes/user-list-timeline', { listId: list.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -1041,7 +1041,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -1053,7 +1053,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -1061,13 +1061,13 @@ describe('Timelines', () => {
test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/following/create', { userId: bob.id }, alice);
+ await api('following/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote = await post(bob, { text: 'hi', visibility: 'followers' });
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi');
@@ -1080,7 +1080,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: alice.id }, alice);
+ const res = await api('users/notes', { userId: alice.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi');
@@ -1089,12 +1089,12 @@ describe('Timelines', () => {
test.concurrent('チャンネル投稿が含まれない', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
+ const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -1108,7 +1108,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false);
@@ -1123,7 +1123,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice);
+ const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1138,7 +1138,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice);
+ const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false);
@@ -1153,7 +1153,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withFiles: true }, alice);
+ const res = await api('users/notes', { userId: bob.id, withFiles: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1162,12 +1162,12 @@ describe('Timelines', () => {
test.concurrent('[withChannelNotes: true] チャンネル投稿が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const channel = await api('/channels/create', { name: 'channel' }, bob).then(x => x.body);
+ const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, alice);
+ const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -1175,12 +1175,12 @@ describe('Timelines', () => {
test.concurrent('[withChannelNotes: true] 他人が取得した場合センシティブチャンネル投稿が含まれない', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- const channel = await api('/channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
+ const channel = await api('channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, alice);
+ const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -1188,12 +1188,12 @@ describe('Timelines', () => {
test.concurrent('[withChannelNotes: true] 自分が取得した場合センシティブチャンネル投稿が含まれる', async () => {
const [bob] = await Promise.all([signup()]);
- const channel = await api('/channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
+ const channel = await api('channels/create', { name: 'channel', isSensitive: true }, bob).then(x => x.body);
const bobNote = await post(bob, { text: 'hi', channelId: channel.id });
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withChannelNotes: true }, bob);
+ const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, bob);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
});
@@ -1201,14 +1201,14 @@ describe('Timelines', () => {
test.concurrent('ミュートしているユーザーに関連する投稿が含まれない', async () => {
const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]);
- await api('/mute/create', { userId: carol.id }, alice);
+ await api('mute/create', { userId: carol.id }, alice);
await sleep(1000);
const carolNote = await post(carol, { text: 'hi' });
const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id });
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
@@ -1216,7 +1216,7 @@ describe('Timelines', () => {
test.concurrent('ミュートしていても userId に指定したユーザーの投稿が含まれる', async () => {
const [alice, bob] = await Promise.all([signup(), signup()]);
- await api('/mute/create', { userId: bob.id }, alice);
+ await api('mute/create', { userId: bob.id }, alice);
await sleep(1000);
const bobNote1 = await post(bob, { text: 'hi' });
const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id });
@@ -1224,7 +1224,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id }, alice);
+ const res = await api('users/notes', { userId: bob.id }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true);
@@ -1238,7 +1238,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: alice.id, withReplies: true }, alice);
+ const res = await api('users/notes', { userId: alice.id, withReplies: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
});
@@ -1250,7 +1250,7 @@ describe('Timelines', () => {
await waitForPushToTl();
- const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice);
+ const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice);
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
});
diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts
index 6897cf08c6..331e053935 100644
--- a/packages/backend/test/e2e/user-notes.ts
+++ b/packages/backend/test/e2e/user-notes.ts
@@ -11,9 +11,9 @@ import type * as misskey from 'misskey-js';
describe('users/notes', () => {
let alice: misskey.entities.SignupResponse;
- let jpgNote: any;
- let pngNote: any;
- let jpgPngNote: any;
+ let jpgNote: misskey.entities.Note;
+ let pngNote: misskey.entities.Note;
+ let jpgPngNote: misskey.entities.Note;
beforeAll(async () => {
alice = await signup({ username: 'alice' });
@@ -31,7 +31,7 @@ describe('users/notes', () => {
}, 1000 * 60 * 2);
test('withFiles', async () => {
- const res = await api('/users/notes', {
+ const res = await api('users/notes', {
userId: alice.id,
withFiles: true,
}, alice);
diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts
index 3cf2a5dee1..3458e06384 100644
--- a/packages/backend/test/e2e/users.ts
+++ b/packages/backend/test/e2e/users.ts
@@ -8,7 +8,7 @@ process.env.NODE_ENV = 'test';
import * as assert from 'assert';
import { inspect } from 'node:util';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import { api, page, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
+import { api, post, role, signup, successfulApiCall, uploadFile } from '../utils.js';
import type * as misskey from 'misskey-js';
describe('ユーザー', () => {
@@ -24,31 +24,12 @@ describe('ユーザー', () => {
}, {});
};
- // BUG misskey-jsとjson-schemaと実際に返ってくるデータが全部違う
- type UserLite = misskey.entities.UserLite & {
- badgeRoles: any[],
- };
-
- type UserDetailedNotMe = UserLite &
- misskey.entities.UserDetailed & {
- roles: any[],
- };
-
- type MeDetailed = UserDetailedNotMe &
- misskey.entities.MeDetailed & {
- achievements: object[],
- loggedInDays: number,
- policies: object,
- };
-
- type User = MeDetailed & { token: string };
-
- const show = async (id: string, me = root): Promise => {
- return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me }) as any;
+ const show = async (id: string, me = root): Promise => {
+ return successfulApiCall({ endpoint: 'users/show', parameters: { userId: id }, user: me });
};
// UserLiteのキーが過不足なく入っている?
- const userLite = (user: User): Partial => {
+ const userLite = (user: misskey.entities.UserLite): Partial => {
return stripUndefined({
id: user.id,
name: user.name,
@@ -71,7 +52,7 @@ describe('ユーザー', () => {
};
// UserDetailedNotMeのキーが過不足なく入っている?
- const userDetailedNotMe = (user: User): Partial => {
+ const userDetailedNotMe = (user: misskey.entities.SignupResponse): Partial => {
return stripUndefined({
...userLite(user),
url: user.url,
@@ -111,7 +92,7 @@ describe('ユーザー', () => {
};
// Relations関連のキーが過不足なく入っている?
- const userDetailedNotMeWithRelations = (user: User): Partial => {
+ const userDetailedNotMeWithRelations = (user: misskey.entities.SignupResponse): Partial => {
return stripUndefined({
...userDetailedNotMe(user),
isFollowing: user.isFollowing ?? false,
@@ -128,7 +109,7 @@ describe('ユーザー', () => {
};
// MeDetailedのキーが過不足なく入っている?
- const meDetailed = (user: User, security = false): Partial => {
+ const meDetailed = (user: misskey.entities.SignupResponse, security = false): Partial => {
return stripUndefined({
...userDetailedNotMe(user),
avatarId: user.avatarId,
@@ -159,6 +140,7 @@ describe('ユーザー', () => {
mutedWords: user.mutedWords,
hardMutedWords: user.hardMutedWords,
mutedInstances: user.mutedInstances,
+ // @ts-expect-error 後方互換性
mutingNotificationTypes: user.mutingNotificationTypes,
notificationRecieveConfig: user.notificationRecieveConfig,
emailNotificationTypes: user.emailNotificationTypes,
@@ -173,61 +155,53 @@ describe('ユーザー', () => {
});
};
- let root: User;
- let alice: User;
+ let root: misskey.entities.SignupResponse;
+ let alice: misskey.entities.SignupResponse;
let aliceNote: misskey.entities.Note;
- let alicePage: misskey.entities.Page;
- let aliceList: misskey.entities.UserList;
- let bob: User;
- let bobNote: misskey.entities.Note;
+ let bob: misskey.entities.SignupResponse;
- let carol: User;
- let dave: User;
- let ellen: User;
- let frank: User;
+ // NOTE: これがないと落ちる(bob の updatedAt が null になってしまうため?)
+ let bobNote: misskey.entities.Note; // eslint-disable-line @typescript-eslint/no-unused-vars
- let usersReplying: User[];
+ let carol: misskey.entities.SignupResponse;
- let userNoNote: User;
- let userNotExplorable: User;
- let userLocking: User;
- let userAdmin: User;
- let roleAdmin: any;
- let userModerator: User;
- let roleModerator: any;
- let userRolePublic: User;
- let rolePublic: any;
- let userRoleBadge: User;
- let roleBadge: any;
- let userSilenced: User;
- let roleSilenced: any;
- let userSuspended: User;
- let userDeletedBySelf: User;
- let userDeletedByAdmin: User;
- let userFollowingAlice: User;
- let userFollowedByAlice: User;
- let userBlockingAlice: User;
- let userBlockedByAlice: User;
- let userMutingAlice: User;
- let userMutedByAlice: User;
- let userRnMutingAlice: User;
- let userRnMutedByAlice: User;
- let userFollowRequesting: User;
- let userFollowRequested: User;
+ let usersReplying: misskey.entities.SignupResponse[];
+
+ let userNoNote: misskey.entities.SignupResponse;
+ let userNotExplorable: misskey.entities.SignupResponse;
+ let userLocking: misskey.entities.SignupResponse;
+ let userAdmin: misskey.entities.SignupResponse;
+ let roleAdmin: misskey.entities.Role;
+ let userModerator: misskey.entities.SignupResponse;
+ let roleModerator: misskey.entities.Role;
+ let userRolePublic: misskey.entities.SignupResponse;
+ let rolePublic: misskey.entities.Role;
+ let userRoleBadge: misskey.entities.SignupResponse;
+ let roleBadge: misskey.entities.Role;
+ let userSilenced: misskey.entities.SignupResponse;
+ let roleSilenced: misskey.entities.Role;
+ let userSuspended: misskey.entities.SignupResponse;
+ let userDeletedBySelf: misskey.entities.SignupResponse;
+ let userDeletedByAdmin: misskey.entities.SignupResponse;
+ let userFollowingAlice: misskey.entities.SignupResponse;
+ let userFollowedByAlice: misskey.entities.SignupResponse;
+ let userBlockingAlice: misskey.entities.SignupResponse;
+ let userBlockedByAlice: misskey.entities.SignupResponse;
+ let userMutingAlice: misskey.entities.SignupResponse;
+ let userMutedByAlice: misskey.entities.SignupResponse;
+ let userRnMutingAlice: misskey.entities.SignupResponse;
+ let userRnMutedByAlice: misskey.entities.SignupResponse;
+ let userFollowRequesting: misskey.entities.SignupResponse;
+ let userFollowRequested: misskey.entities.SignupResponse;
beforeAll(async () => {
root = await signup({ username: 'root' });
alice = await signup({ username: 'alice' });
- aliceNote = await post(alice, { text: 'test' }) as any;
- alicePage = await page(alice);
- aliceList = (await api('users/list/create', { name: 'aliceList' }, alice)).body;
+ aliceNote = await post(alice, { text: 'test' });
bob = await signup({ username: 'bob' });
- bobNote = await post(bob, { text: 'test' }) as any;
+ bobNote = await post(bob, { text: 'test' });
carol = await signup({ username: 'carol' });
- dave = await signup({ username: 'dave' });
- ellen = await signup({ username: 'ellen' });
- frank = await signup({ username: 'frank' });
// @alice -> @replyingへのリプライ。Promise.allで一気に作るとtimeoutしてしまうのでreduceで一つ一つawaitする
usersReplying = await [...Array(10)].map((_, i) => i).reduce(async (acc, i) => {
@@ -238,7 +212,7 @@ describe('ユーザー', () => {
}
return (await acc).concat(u);
- }, Promise.resolve([] as User[]));
+ }, Promise.resolve([] as misskey.entities.SignupResponse[]));
userNoNote = await signup({ username: 'userNoNote' });
userNotExplorable = await signup({ username: 'userNotExplorable' });
@@ -306,7 +280,7 @@ describe('ユーザー', () => {
beforeEach(async () => {
alice = {
...alice,
- ...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }) as any,
+ ...await successfulApiCall({ endpoint: 'i', parameters: {}, user: alice }),
};
aliceNote = await successfulApiCall({ endpoint: 'notes/show', parameters: { noteId: aliceNote.id }, user: alice });
});
@@ -319,7 +293,7 @@ describe('ユーザー', () => {
endpoint: 'signup',
parameters: { username: 'zoe', password: 'password' },
user: undefined,
- }) as unknown as User; // BUG MeDetailedに足りないキーがある
+ }) as unknown as misskey.entities.SignupResponse; // BUG MeDetailedに足りないキーがある
// signupの時はtokenが含まれる特別なMeDetailedが返ってくる
assert.match(response.token, /[a-zA-Z0-9]{16}/);
@@ -329,7 +303,7 @@ describe('ユーザー', () => {
assert.strictEqual(response.name, null);
assert.strictEqual(response.username, 'zoe');
assert.strictEqual(response.host, null);
- assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
+ response.avatarUrl && assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
assert.strictEqual(response.avatarBlurhash, null);
assert.deepStrictEqual(response.avatarDecorations, []);
assert.strictEqual(response.isBot, false);
@@ -401,6 +375,7 @@ describe('ユーザー', () => {
assert.deepStrictEqual(response.unreadAnnouncements, []);
assert.deepStrictEqual(response.mutedWords, []);
assert.deepStrictEqual(response.mutedInstances, []);
+ // @ts-expect-error 後方互換のため
assert.deepStrictEqual(response.mutingNotificationTypes, []);
assert.deepStrictEqual(response.notificationRecieveConfig, {});
assert.deepStrictEqual(response.emailNotificationTypes, ['follow', 'receiveFollowRequest']);
@@ -430,66 +405,66 @@ describe('ユーザー', () => {
//#region 自分の情報の更新(i/update)
test.each([
- { parameters: (): object => ({ name: null }) },
- { parameters: (): object => ({ name: 'x'.repeat(50) }) },
- { parameters: (): object => ({ name: 'x' }) },
- { parameters: (): object => ({ name: 'My name' }) },
- { parameters: (): object => ({ description: null }) },
- { parameters: (): object => ({ description: 'x'.repeat(1500) }) },
- { parameters: (): object => ({ description: 'x' }) },
- { parameters: (): object => ({ description: 'My description' }) },
- { parameters: (): object => ({ location: null }) },
- { parameters: (): object => ({ location: 'x'.repeat(50) }) },
- { parameters: (): object => ({ location: 'x' }) },
- { parameters: (): object => ({ location: 'My location' }) },
- { parameters: (): object => ({ birthday: '0000-00-00' }) },
- { parameters: (): object => ({ birthday: '9999-99-99' }) },
- { parameters: (): object => ({ lang: 'en-US' }) },
- { parameters: (): object => ({ fields: [] }) },
- { parameters: (): object => ({ fields: [{ name: 'x', value: 'x' }] }) },
- { parameters: (): object => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない
- { parameters: (): object => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) },
- { parameters: (): object => ({ isLocked: true }) },
- { parameters: (): object => ({ isLocked: false }) },
- { parameters: (): object => ({ isExplorable: false }) },
- { parameters: (): object => ({ isExplorable: true }) },
- { parameters: (): object => ({ hideOnlineStatus: true }) },
- { parameters: (): object => ({ hideOnlineStatus: false }) },
- { parameters: (): object => ({ publicReactions: false }) },
- { parameters: (): object => ({ publicReactions: true }) },
- { parameters: (): object => ({ autoAcceptFollowed: true }) },
- { parameters: (): object => ({ autoAcceptFollowed: false }) },
- { parameters: (): object => ({ noCrawle: true }) },
- { parameters: (): object => ({ noCrawle: false }) },
- { parameters: (): object => ({ preventAiLearning: false }) },
- { parameters: (): object => ({ preventAiLearning: true }) },
- { parameters: (): object => ({ isBot: true }) },
- { parameters: (): object => ({ isBot: false }) },
- { parameters: (): object => ({ isCat: true }) },
- { parameters: (): object => ({ isCat: false }) },
- { parameters: (): object => ({ injectFeaturedNote: true }) },
- { parameters: (): object => ({ injectFeaturedNote: false }) },
- { parameters: (): object => ({ receiveAnnouncementEmail: true }) },
- { parameters: (): object => ({ receiveAnnouncementEmail: false }) },
- { parameters: (): object => ({ alwaysMarkNsfw: true }) },
- { parameters: (): object => ({ alwaysMarkNsfw: false }) },
- { parameters: (): object => ({ autoSensitive: true }) },
- { parameters: (): object => ({ autoSensitive: false }) },
- { parameters: (): object => ({ followingVisibility: 'private' }) },
- { parameters: (): object => ({ followingVisibility: 'followers' }) },
- { parameters: (): object => ({ followingVisibility: 'public' }) },
- { parameters: (): object => ({ followersVisibility: 'private' }) },
- { parameters: (): object => ({ followersVisibility: 'followers' }) },
- { parameters: (): object => ({ followersVisibility: 'public' }) },
- { parameters: (): object => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
- { parameters: (): object => ({ mutedWords: [['x'.repeat(194)]] }) },
- { parameters: (): object => ({ mutedWords: [] }) },
- { parameters: (): object => ({ mutedInstances: ['xxxx.xxxxx'] }) },
- { parameters: (): object => ({ mutedInstances: [] }) },
- { parameters: (): object => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) },
- { parameters: (): object => ({ notificationRecieveConfig: {} }) },
- { parameters: (): object => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) },
- { parameters: (): object => ({ emailNotificationTypes: [] }) },
+ { parameters: () => ({ name: null }) },
+ { parameters: () => ({ name: 'x'.repeat(50) }) },
+ { parameters: () => ({ name: 'x' }) },
+ { parameters: () => ({ name: 'My name' }) },
+ { parameters: () => ({ description: null }) },
+ { parameters: () => ({ description: 'x'.repeat(1500) }) },
+ { parameters: () => ({ description: 'x' }) },
+ { parameters: () => ({ description: 'My description' }) },
+ { parameters: () => ({ location: null }) },
+ { parameters: () => ({ location: 'x'.repeat(50) }) },
+ { parameters: () => ({ location: 'x' }) },
+ { parameters: () => ({ location: 'My location' }) },
+ { parameters: () => ({ birthday: '0000-00-00' }) },
+ { parameters: () => ({ birthday: '9999-99-99' }) },
+ { parameters: () => ({ lang: 'en-US' as const }) },
+ { parameters: () => ({ fields: [] }) },
+ { parameters: () => ({ fields: [{ name: 'x', value: 'x' }] }) },
+ { parameters: () => ({ fields: [{ name: 'x'.repeat(3000), value: 'x'.repeat(3000) }] }) }, // BUG? fieldには制限がない
+ { parameters: () => ({ fields: Array(16).fill({ name: 'x', value: 'y' }) }) },
+ { parameters: () => ({ isLocked: true }) },
+ { parameters: () => ({ isLocked: false }) },
+ { parameters: () => ({ isExplorable: false }) },
+ { parameters: () => ({ isExplorable: true }) },
+ { parameters: () => ({ hideOnlineStatus: true }) },
+ { parameters: () => ({ hideOnlineStatus: false }) },
+ { parameters: () => ({ publicReactions: false }) },
+ { parameters: () => ({ publicReactions: true }) },
+ { parameters: () => ({ autoAcceptFollowed: true }) },
+ { parameters: () => ({ autoAcceptFollowed: false }) },
+ { parameters: () => ({ noCrawle: true }) },
+ { parameters: () => ({ noCrawle: false }) },
+ { parameters: () => ({ preventAiLearning: false }) },
+ { parameters: () => ({ preventAiLearning: true }) },
+ { parameters: () => ({ isBot: true }) },
+ { parameters: () => ({ isBot: false }) },
+ { parameters: () => ({ isCat: true }) },
+ { parameters: () => ({ isCat: false }) },
+ { parameters: () => ({ injectFeaturedNote: true }) },
+ { parameters: () => ({ injectFeaturedNote: false }) },
+ { parameters: () => ({ receiveAnnouncementEmail: true }) },
+ { parameters: () => ({ receiveAnnouncementEmail: false }) },
+ { parameters: () => ({ alwaysMarkNsfw: true }) },
+ { parameters: () => ({ alwaysMarkNsfw: false }) },
+ { parameters: () => ({ autoSensitive: true }) },
+ { parameters: () => ({ autoSensitive: false }) },
+ { parameters: () => ({ followingVisibility: 'private' as const }) },
+ { parameters: () => ({ followingVisibility: 'followers' as const }) },
+ { parameters: () => ({ followingVisibility: 'public' as const }) },
+ { parameters: () => ({ followersVisibility: 'private' as const }) },
+ { parameters: () => ({ followersVisibility: 'followers' as const }) },
+ { parameters: () => ({ followersVisibility: 'public' as const }) },
+ { parameters: () => ({ mutedWords: Array(19).fill(['xxxxx']) }) },
+ { parameters: () => ({ mutedWords: [['x'.repeat(194)]] }) },
+ { parameters: () => ({ mutedWords: [] }) },
+ { parameters: () => ({ mutedInstances: ['xxxx.xxxxx'] }) },
+ { parameters: () => ({ mutedInstances: [] }) },
+ { parameters: () => ({ notificationRecieveConfig: { mention: { type: 'following' } } }) },
+ { parameters: () => ({ notificationRecieveConfig: {} }) },
+ { parameters: () => ({ emailNotificationTypes: ['mention', 'reply', 'quote', 'follow', 'receiveFollowRequest'] }) },
+ { parameters: () => ({ emailNotificationTypes: [] }) },
] as const)('を書き換えることができる($#)', async ({ parameters }) => {
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters(), user: alice });
const expected = { ...meDetailed(alice, true), ...parameters() };
@@ -498,13 +473,13 @@ describe('ユーザー', () => {
test('を書き換えることができる(Avatar)', async () => {
const aliceFile = (await uploadFile(alice)).body;
- const parameters = { avatarId: aliceFile.id };
+ const parameters = { avatarId: aliceFile!.id };
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
assert.match(response.avatarUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
assert.match(response.avatarBlurhash ?? '.', /[ -~]{54}/);
const expected = {
...meDetailed(alice, true),
- avatarId: aliceFile.id,
+ avatarId: aliceFile!.id,
avatarBlurhash: response.avatarBlurhash,
avatarUrl: response.avatarUrl,
};
@@ -523,13 +498,13 @@ describe('ユーザー', () => {
test('を書き換えることができる(Banner)', async () => {
const aliceFile = (await uploadFile(alice)).body;
- const parameters = { bannerId: aliceFile.id };
+ const parameters = { bannerId: aliceFile!.id };
const response = await successfulApiCall({ endpoint: 'i/update', parameters: parameters, user: alice });
assert.match(response.bannerUrl ?? '.', /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
assert.match(response.bannerBlurhash ?? '.', /[ -~]{54}/);
const expected = {
...meDetailed(alice, true),
- bannerId: aliceFile.id,
+ bannerId: aliceFile!.id,
bannerBlurhash: response.bannerBlurhash,
bannerUrl: response.bannerUrl,
};
@@ -579,13 +554,13 @@ describe('ユーザー', () => {
//#region ユーザー(users)
test.each([
- { label: 'ID昇順', parameters: { limit: 5 }, selector: (u: UserLite): string => u.id },
- { label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
- { label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
- { label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
- { label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
- { label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
- { label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
+ { label: 'ID昇順', parameters: { limit: 5 }, selector: (u: misskey.entities.UserLite): string => u.id },
+ { label: 'フォロワー昇順', parameters: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+ { label: 'フォロワー降順', parameters: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+ { label: '登録日時昇順', parameters: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+ { label: '登録日時降順', parameters: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+ { label: '投稿日時昇順', parameters: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
+ { label: '投稿日時降順', parameters: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
] as const)('をリスト形式で取得することができる($label)', async ({ parameters, selector }) => {
const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
@@ -598,15 +573,15 @@ describe('ユーザー', () => {
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: '「見つけやすくする」がOFFのユーザーが含まれない', user: (): User => userNotExplorable, excluded: true },
- { label: 'ミュートユーザーが含まれない', user: (): User => userMutedByAlice, excluded: true },
- { label: 'ブロックされているユーザーが含まれない', user: (): User => userBlockedByAlice, excluded: true },
- { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice, excluded: true },
- { label: '承認制ユーザーが含まれる', user: (): User => userLocking },
- { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
- { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
- { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
- { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+ { label: '「見つけやすくする」がOFFのユーザーが含まれない', user: () => userNotExplorable, excluded: true },
+ { label: 'ミュートユーザーが含まれない', user: () => userMutedByAlice, excluded: true },
+ { label: 'ブロックされているユーザーが含まれない', user: () => userBlockedByAlice, excluded: true },
+ { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice, excluded: true },
+ { label: '承認制ユーザーが含まれる', user: () => userLocking },
+ { label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+ { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+ { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+ { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
] as const)('をリスト形式で取得することができ、結果に$label', async ({ user, excluded }) => {
const parameters = { limit: 100 };
const response = await successfulApiCall({ endpoint: 'users', parameters, user: alice });
@@ -620,39 +595,44 @@ describe('ユーザー', () => {
//#region ユーザー情報(users/show)
test.each([
- { label: 'ID指定で自分自身を', parameters: (): object => ({ userId: alice.id }), user: (): User => alice, type: meDetailed },
- { label: 'ID指定で他人を', parameters: (): object => ({ userId: alice.id }), user: (): User => bob, type: userDetailedNotMeWithRelations },
- { label: 'ID指定かつ未認証', parameters: (): object => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe },
- { label: '@指定で自分自身を', parameters: (): object => ({ username: alice.username }), user: (): User => alice, type: meDetailed },
- { label: '@指定で他人を', parameters: (): object => ({ username: alice.username }), user: (): User => bob, type: userDetailedNotMeWithRelations },
- { label: '@指定かつ未認証', parameters: (): object => ({ username: alice.username }), user: undefined, type: userDetailedNotMe },
+ { label: 'ID指定で自分自身を', parameters: () => ({ userId: alice.id }), user: () => alice, type: meDetailed },
+ { label: 'ID指定で他人を', parameters: () => ({ userId: alice.id }), user: () => bob, type: userDetailedNotMeWithRelations },
+ { label: 'ID指定かつ未認証', parameters: () => ({ userId: alice.id }), user: undefined, type: userDetailedNotMe },
+ { label: '@指定で自分自身を', parameters: () => ({ username: alice.username }), user: () => alice, type: meDetailed },
+ { label: '@指定で他人を', parameters: () => ({ username: alice.username }), user: () => bob, type: userDetailedNotMeWithRelations },
+ { label: '@指定かつ未認証', parameters: () => ({ username: alice.username }), user: undefined, type: userDetailedNotMe },
] as const)('を取得することができる($label)', async ({ parameters, user, type }) => {
const response = await successfulApiCall({ endpoint: 'users/show', parameters: parameters(), user: user?.() });
const expected = type(alice);
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: 'Administratorになっている', user: (): User => userAdmin, me: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin },
- { label: '自分以外から見たときはAdministratorか判定できない', user: (): User => userAdmin, selector: (user: User): unknown => user.isAdmin, expected: (): undefined => undefined },
- { label: 'Moderatorになっている', user: (): User => userModerator, me: (): User => userModerator, selector: (user: User): unknown => user.isModerator },
- { label: '自分以外から見たときはModeratorか判定できない', user: (): User => userModerator, selector: (user: User): unknown => user.isModerator, expected: (): undefined => undefined },
- { label: 'サイレンスになっている', user: (): User => userSilenced, selector: (user: User): unknown => user.isSilenced },
- //{ label: 'サスペンドになっている', user: (): User => userSuspended, selector: (user: User): unknown => user.isSuspended },
- { label: '削除済みになっている', user: (): User => userDeletedBySelf, me: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted },
- { label: '自分以外から見たときは削除済みか判定できない', user: (): User => userDeletedBySelf, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined },
- { label: '削除済み(byAdmin)になっている', user: (): User => userDeletedByAdmin, me: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted },
- { label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: (): User => userDeletedByAdmin, selector: (user: User): unknown => user.isDeleted, expected: (): undefined => undefined },
- { label: 'フォロー中になっている', user: (): User => userFollowedByAlice, selector: (user: User): unknown => user.isFollowing },
- { label: 'フォローされている', user: (): User => userFollowingAlice, selector: (user: User): unknown => user.isFollowed },
- { label: 'ブロック中になっている', user: (): User => userBlockedByAlice, selector: (user: User): unknown => user.isBlocking },
- { label: 'ブロックされている', user: (): User => userBlockingAlice, selector: (user: User): unknown => user.isBlocked },
- { label: 'ミュート中になっている', user: (): User => userMutedByAlice, selector: (user: User): unknown => user.isMuted },
- { label: 'リノートミュート中になっている', user: (): User => userRnMutedByAlice, selector: (user: User): unknown => user.isRenoteMuted },
- { label: 'フォローリクエスト中になっている', user: (): User => userFollowRequested, me: (): User => userFollowRequesting, selector: (user: User): unknown => user.hasPendingFollowRequestFromYou },
- { label: 'フォローリクエストされている', user: (): User => userFollowRequesting, me: (): User => userFollowRequested, selector: (user: User): unknown => user.hasPendingFollowRequestToYou },
+ { label: 'Administratorになっている', user: () => userAdmin, me: () => userAdmin, selector: (user: misskey.entities.MeDetailed) => user.isAdmin },
+ // @ts-expect-error UserDetailedNotMe doesn't include isAdmin
+ { label: '自分以外から見たときはAdministratorか判定できない', user: () => userAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isAdmin, expected: () => undefined },
+ { label: 'Moderatorになっている', user: () => userModerator, me: () => userModerator, selector: (user: misskey.entities.MeDetailed) => user.isModerator },
+ // @ts-expect-error UserDetailedNotMe doesn't include isModerator
+ { label: '自分以外から見たときはModeratorか判定できない', user: () => userModerator, selector: (user: misskey.entities.UserDetailedNotMe) => user.isModerator, expected: () => undefined },
+ { label: 'サイレンスになっている', user: () => userSilenced, selector: (user: misskey.entities.UserDetailed) => user.isSilenced },
+ // FIXME: 落ちる
+ //{ label: 'サスペンドになっている', user: () => userSuspended, selector: (user: misskey.entities.UserDetailed) => user.isSuspended },
+ { label: '削除済みになっている', user: () => userDeletedBySelf, me: () => userDeletedBySelf, selector: (user: misskey.entities.MeDetailed) => user.isDeleted },
+ // @ts-expect-error UserDetailedNotMe doesn't include isDeleted
+ { label: '自分以外から見たときは削除済みか判定できない', user: () => userDeletedBySelf, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined },
+ { label: '削除済み(byAdmin)になっている', user: () => userDeletedByAdmin, me: () => userDeletedByAdmin, selector: (user: misskey.entities.MeDetailed) => user.isDeleted },
+ // @ts-expect-error UserDetailedNotMe doesn't include isDeleted
+ { label: '自分以外から見たときは削除済み(byAdmin)か判定できない', user: () => userDeletedByAdmin, selector: (user: misskey.entities.UserDetailedNotMe) => user.isDeleted, expected: () => undefined },
+ { label: 'フォロー中になっている', user: () => userFollowedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowing },
+ { label: 'フォローされている', user: () => userFollowingAlice, selector: (user: misskey.entities.UserDetailed) => user.isFollowed },
+ { label: 'ブロック中になっている', user: () => userBlockedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocking },
+ { label: 'ブロックされている', user: () => userBlockingAlice, selector: (user: misskey.entities.UserDetailed) => user.isBlocked },
+ { label: 'ミュート中になっている', user: () => userMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isMuted },
+ { label: 'リノートミュート中になっている', user: () => userRnMutedByAlice, selector: (user: misskey.entities.UserDetailed) => user.isRenoteMuted },
+ { label: 'フォローリクエスト中になっている', user: () => userFollowRequested, me: () => userFollowRequesting, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestFromYou },
+ { label: 'フォローリクエストされている', user: () => userFollowRequesting, me: () => userFollowRequested, selector: (user: misskey.entities.UserDetailed) => user.hasPendingFollowRequestToYou },
] as const)('を取得することができ、$labelこと', async ({ user, me, selector, expected }) => {
const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: user().id }, user: me?.() ?? alice });
- assert.strictEqual(selector(response), (expected ?? ((): true => true))());
+ assert.strictEqual(selector(response as any), (expected ?? ((): true => true))());
});
test('を取得することができ、Publicなロールがセットされていること', async () => {
const response = await successfulApiCall({ endpoint: 'users/show', parameters: { userId: userRolePublic.id }, user: alice });
@@ -694,17 +674,18 @@ describe('ユーザー', () => {
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
- { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
- { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
- { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
- { label: '承認制ユーザーが含まれる', user: (): User => userLocking },
- { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
- { label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: (): User => userSuspended, me: (): User => root },
+ { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+ { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+ { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+ { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+ { label: '承認制ユーザーが含まれる', user: () => userLocking },
+ { label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+ { label: 'サスペンドユーザーが(モデレーターが見るときは)含まれる', user: () => userSuspended, me: () => root },
// BUG サスペンドユーザーを一般ユーザーから見るとrootユーザーが返ってくる
- //{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: (): User => userSuspended, me: (): User => bob, excluded: true },
- { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
- { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+ //{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: () => userSuspended, me: () => bob, excluded: true },
+ { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+ { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
+ // @ts-expect-error excluded は上でコメントアウトされているので
] as const)('をID指定のリスト形式で取得することができ、結果に$label', async ({ user, me, excluded }) => {
const parameters = { userIds: [user().id] };
const response = await successfulApiCall({ endpoint: 'users/show', parameters, user: me?.() ?? alice });
@@ -729,15 +710,15 @@ describe('ユーザー', () => {
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
- { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
- { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
- { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
- { label: '承認制ユーザーが含まれる', user: (): User => userLocking },
- { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
- { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
- { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
- { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+ { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+ { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+ { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+ { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+ { label: '承認制ユーザーが含まれる', user: () => userLocking },
+ { label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+ { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+ { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+ { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
] as const)('を検索することができ、結果に$labelが含まれる', async ({ user, excluded }) => {
const parameters = { query: user().username, limit: 1 };
const response = await successfulApiCall({ endpoint: 'users/search', parameters, user: alice });
@@ -751,30 +732,30 @@ describe('ユーザー', () => {
//#region ID指定検索(users/search-by-username-and-host)
test.each([
- { label: '自分', parameters: { username: 'alice' }, user: (): User[] => [alice] },
- { label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: (): User[] => [alice] },
- { label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: (): User[] => [userFollowedByAlice] },
- { label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: (): User[] => [] },
- { label: 'ローカルの他人1', parameters: { username: 'bob' }, user: (): User[] => [bob] },
- { label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: (): User[] => [bob] },
- { label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: (): User[] => [bob] },
- { label: 'ローカル', parameters: { host: null, limit: 1 }, user: (): User[] => [userFollowedByAlice] },
- { label: 'ローカル', parameters: { host: '.', limit: 1 }, user: (): User[] => [userFollowedByAlice] },
+ { label: '自分', parameters: { username: 'alice' }, user: () => [alice] },
+ { label: '自分かつusernameが大文字', parameters: { username: 'ALICE' }, user: () => [alice] },
+ { label: 'ローカルのフォロイーでノートなし', parameters: { username: 'userFollowedByAlice' }, user: () => [userFollowedByAlice] },
+ { label: 'ローカルでノートなしは検索に載らない', parameters: { username: 'userNoNote' }, user: () => [] },
+ { label: 'ローカルの他人1', parameters: { username: 'bob' }, user: () => [bob] },
+ { label: 'ローカルの他人2', parameters: { username: 'bob', host: null }, user: () => [bob] },
+ { label: 'ローカルの他人3', parameters: { username: 'bob', host: '.' }, user: () => [bob] },
+ { label: 'ローカル', parameters: { host: null, limit: 1 }, user: () => [userFollowedByAlice] },
+ { label: 'ローカル', parameters: { host: '.', limit: 1 }, user: () => [userFollowedByAlice] },
])('をID&ホスト指定で検索できる($label)', async ({ parameters, user }) => {
const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
const expected = await Promise.all(user().map(u => show(u.id, alice)));
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
- { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
- { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
- { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
- { label: '承認制ユーザーが含まれる', user: (): User => userLocking },
- { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
- { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
- { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
- { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+ { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+ { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+ { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+ { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+ { label: '承認制ユーザーが含まれる', user: () => userLocking },
+ { label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+ { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+ { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+ { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
] as const)('をID&ホスト指定で検索でき、結果に$label', async ({ user, excluded }) => {
const parameters = { username: user().username };
const response = await successfulApiCall({ endpoint: 'users/search-by-username-and-host', parameters, user: alice });
@@ -796,15 +777,15 @@ describe('ユーザー', () => {
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
- { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
- { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
- { label: 'ブロックしてきているユーザーが含まれない', user: (): User => userBlockingAlice, excluded: true },
- { label: '承認制ユーザーが含まれる', user: (): User => userLocking },
- { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
- //{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
- { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
- { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+ { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+ { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+ { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+ { label: 'ブロックしてきているユーザーが含まれない', user: () => userBlockingAlice, excluded: true },
+ { label: '承認制ユーザーが含まれる', user: () => userLocking },
+ { label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+ //{ label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+ { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+ { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
] as const)('がよくリプライをするユーザーのリストを取得でき、結果に$label', async ({ user, excluded }) => {
const replyTo = (await successfulApiCall({ endpoint: 'users/notes', parameters: { userId: user().id }, user: undefined }))[0];
await post(alice, { text: `@${user().username} test`, replyId: replyTo.id });
@@ -818,12 +799,12 @@ describe('ユーザー', () => {
//#region ハッシュタグ(hashtags/users)
test.each([
- { label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
- { label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: UserDetailedNotMe): string => String(u.followersCount) },
- { label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
- { label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: UserDetailedNotMe): string => u.createdAt },
- { label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
- { label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: UserDetailedNotMe): string => String(u.updatedAt) },
+ { label: 'フォロワー昇順', sort: { sort: '+follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+ { label: 'フォロワー降順', sort: { sort: '-follower' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.followersCount) },
+ { label: '登録日時昇順', sort: { sort: '+createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+ { label: '登録日時降順', sort: { sort: '-createdAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => u.createdAt },
+ { label: '投稿日時昇順', sort: { sort: '+updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
+ { label: '投稿日時降順', sort: { sort: '-updatedAt' }, selector: (u: misskey.entities.UserDetailedNotMe): string => String(u.updatedAt) },
] as const)('をハッシュタグ指定で取得することができる($label)', async ({ sort, selector }) => {
const hashtag = 'test_hashtag';
await successfulApiCall({ endpoint: 'i/update', parameters: { description: `#${hashtag}` }, user: alice });
@@ -837,15 +818,15 @@ describe('ユーザー', () => {
assert.deepStrictEqual(response, expected);
});
test.each([
- { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: (): User => userNotExplorable },
- { label: 'ミュートユーザーが含まれる', user: (): User => userMutedByAlice },
- { label: 'ブロックされているユーザーが含まれる', user: (): User => userBlockedByAlice },
- { label: 'ブロックしてきているユーザーが含まれる', user: (): User => userBlockingAlice },
- { label: '承認制ユーザーが含まれる', user: (): User => userLocking },
- { label: 'サイレンスユーザーが含まれる', user: (): User => userSilenced },
- { label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
- { label: '削除済ユーザーが含まれる', user: (): User => userDeletedBySelf },
- { label: '削除済(byAdmin)ユーザーが含まれる', user: (): User => userDeletedByAdmin },
+ { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable },
+ { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice },
+ { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice },
+ { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice },
+ { label: '承認制ユーザーが含まれる', user: () => userLocking },
+ { label: 'サイレンスユーザーが含まれる', user: () => userSilenced },
+ { label: 'サスペンドユーザーが含まれない', user: () => userSuspended, excluded: true },
+ { label: '削除済ユーザーが含まれる', user: () => userDeletedBySelf },
+ { label: '削除済(byAdmin)ユーザーが含まれる', user: () => userDeletedByAdmin },
] as const)('をハッシュタグ指定で取得することができ、結果に$label', async ({ user, excluded }) => {
const hashtag = `user_test${user().username}`;
if (user() !== userSuspended) {
diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts
index fc35837420..aa082ff2f2 100644
--- a/packages/backend/test/unit/AnnouncementService.ts
+++ b/packages/backend/test/unit/AnnouncementService.ts
@@ -51,7 +51,7 @@ describe('AnnouncementService', () => {
function createAnnouncement(data: Partial = {}) {
return announcementsRepository.insert({
- id: genAidx(data.createdAt ?? new Date()),
+ id: genAidx(data.createdAt?.getTime() ?? Date.now()),
updatedAt: null,
title: 'Title',
text: 'Text',
diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts
index e6e68ccd6d..510b84b680 100644
--- a/packages/backend/test/unit/FetchInstanceMetadataService.ts
+++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts
@@ -19,8 +19,8 @@ import { DI } from '@/di-symbols.js';
import type { TestingModule } from '@nestjs/testing';
function mockRedis() {
- const hash = {};
- const set = jest.fn((key, value) => {
+ const hash = {} as any;
+ const set = jest.fn((key: string, value) => {
const ret = hash[key];
hash[key] = value;
return ret;
@@ -61,7 +61,7 @@ describe('FetchInstanceMetadataService', () => {
app.enableShutdownHooks();
- fetchInstanceMetadataService = app.get(FetchInstanceMetadataService);
+ fetchInstanceMetadataService = app.get(FetchInstanceMetadataService) as jest.Mocked;
federatedInstanceService = app.get(FederatedInstanceService) as jest.Mocked;
redisClient = app.get(DI.redis) as jest.Mocked;
httpRequestService = app.get(HttpRequestService) as jest.Mocked;
@@ -74,11 +74,11 @@ describe('FetchInstanceMetadataService', () => {
test('Lock and update', async () => {
redisClient.set = mockRedis();
const now = Date.now();
- federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } });
+ federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } } as any);
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
- await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
+ await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
expect(tryLockSpy).toHaveBeenCalledTimes(1);
expect(unlockSpy).toHaveBeenCalledTimes(1);
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
@@ -88,11 +88,11 @@ describe('FetchInstanceMetadataService', () => {
test('Lock and don\'t update', async () => {
redisClient.set = mockRedis();
const now = Date.now();
- federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now } });
+ federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now } } as any);
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
- await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
+ await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
expect(tryLockSpy).toHaveBeenCalledTimes(1);
expect(unlockSpy).toHaveBeenCalledTimes(1);
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1);
@@ -101,12 +101,13 @@ describe('FetchInstanceMetadataService', () => {
test('Do nothing when lock not acquired', async () => {
redisClient.set = mockRedis();
- federatedInstanceService.fetch.mockReturnValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } });
+ const now = Date.now();
+ federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
await fetchInstanceMetadataService.tryLock('example.com');
- await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' });
+ await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
expect(tryLockSpy).toHaveBeenCalledTimes(2);
expect(unlockSpy).toHaveBeenCalledTimes(0);
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts
index fe5ad31597..19d03570e0 100644
--- a/packages/backend/test/unit/RoleService.ts
+++ b/packages/backend/test/unit/RoleService.ts
@@ -228,11 +228,14 @@ describe('RoleService', () => {
},
target: 'conditional',
condFormula: {
+ id: '232a4221-9816-49a6-a967-ae0fac52ec5e',
type: 'and',
values: [{
+ id: '2a37ef43-2d93-4c4d-87f6-f2fdb7d9b530',
type: 'followersMoreThanOrEq',
value: 10,
}, {
+ id: '1bd67839-b126-4f92-bad0-4e285dab453b',
type: 'createdMoreThan',
sec: 60 * 60 * 24 * 7,
}],
diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts
index cd5dddd68d..86814fffe0 100644
--- a/packages/backend/test/utils.ts
+++ b/packages/backend/test/utils.ts
@@ -9,11 +9,10 @@ import { basename, isAbsolute } from 'node:path';
import { randomUUID } from 'node:crypto';
import { inspect } from 'node:util';
import WebSocket, { ClientOptions } from 'ws';
-import fetch, { File, RequestInit } from 'node-fetch';
+import fetch, { File, RequestInit, type Headers } from 'node-fetch';
import { DataSource } from 'typeorm';
import { JSDOM } from 'jsdom';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
-import { Packed } from '@/misc/json-schema.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
import { entities } from '../src/postgres.js';
import { loadConfig } from '../src/config.js';
@@ -21,7 +20,7 @@ import type * as misskey from 'misskey-js';
export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js';
-interface UserToken {
+export interface UserToken {
token: string;
bearer?: boolean;
}
@@ -35,20 +34,15 @@ export const cookie = (me: UserToken): string => {
return `token=${me.token};`;
};
-export const api = async (endpoint: string, params: any, me?: UserToken) => {
- const normalized = endpoint.replace(/^\//, '');
- return await request(`api/${normalized}`, params, me);
-};
-
-export type ApiRequest = {
- endpoint: string,
- parameters: object,
+export type ApiRequest = {
+ endpoint: E,
+ parameters: P,
user: UserToken | undefined,
};
-export const successfulApiCall = async (request: ApiRequest, assertion: {
+export const successfulApiCall = async (request: ApiRequest, assertion: {
status?: number,
-} = {}): Promise => {
+} = {}): Promise> => {
const { endpoint, parameters, user } = request;
const res = await api(endpoint, parameters, user);
const status = assertion.status ?? (res.body == null ? 204 : 200);
@@ -56,7 +50,7 @@ export const successfulApiCall = async (request: ApiRequest, assertion: {
return res.body;
};
-export const failedApiCall = async (request: ApiRequest, assertion: {
+export const failedApiCall = async (request: ApiRequest, assertion: {
status: number,
code: string,
id: string
@@ -70,7 +64,7 @@ export const failedApiCall = async (request: ApiRequest, assertion: {
return res.body;
};
-const request = async (path: string, params: any, me?: UserToken): Promise<{
+export const api = async (path: E, params: misskey.Endpoints[E]['req'], me?: UserToken): Promise<{
status: number,
headers: Headers,
body: any
@@ -86,7 +80,7 @@ const request = async (path: string, params: any, me?: UserToken): Promise<{
bodyAuth.i = me.token;
}
- const res = await relativeFetch(path, {
+ const res = await relativeFetch(`api/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(Object.assign(bodyAuth, params)),
@@ -141,7 +135,7 @@ export const signup = async (params?: Partial => {
+export const post = async (user: UserToken, params: misskey.Endpoints['notes/create']['req']): Promise => {
const q = params;
const res = await api('notes/create', q, user);
@@ -159,8 +153,8 @@ export const createAppToken = async (user: UserToken, permissions: (typeof missk
};
// 非公開ノートをAPI越しに見たときのノート NoteEntityService.ts
-export const hiddenNote = (note: any): any => {
- const temp = {
+export const hiddenNote = (note: misskey.entities.Note): misskey.entities.Note => {
+ const temp: misskey.entities.Note = {
...note,
fileIds: [],
files: [],
@@ -173,21 +167,22 @@ export const hiddenNote = (note: any): any => {
return temp;
};
-export const react = async (user: UserToken, note: any, reaction: string): Promise => {
+export const react = async (user: UserToken, note: misskey.entities.Note, reaction: string): Promise => {
await api('notes/reactions/create', {
noteId: note.id,
reaction: reaction,
}, user);
};
-export const userList = async (user: UserToken, userList: any = {}): Promise => {
+export const userList = async (user: UserToken, userList: Partial = {}): Promise => {
const res = await api('users/lists/create', {
name: 'test',
+ ...userList,
}, user);
return res.body;
};
-export const page = async (user: UserToken, page: any = {}): Promise => {
+export const page = async (user: UserToken, page: Partial = {}): Promise => {
const res = await api('pages/create', {
alignCenter: false,
content: [
@@ -198,7 +193,7 @@ export const page = async (user: UserToken, page: any = {}): Promise => {
},
],
eyeCatchingImageId: null,
- font: 'sans-serif',
+ font: 'sans-serif' as any,
hideTitleWhenPinned: false,
name: '1678594845072',
script: '',
@@ -210,7 +205,7 @@ export const page = async (user: UserToken, page: any = {}): Promise => {
return res.body;
};
-export const play = async (user: UserToken, play: any = {}): Promise => {
+export const play = async (user: UserToken, play: Partial = {}): Promise => {
const res = await api('flash/create', {
permissions: [],
script: 'test',
@@ -221,7 +216,7 @@ export const play = async (user: UserToken, play: any = {}): Promise => {
return res.body;
};
-export const clip = async (user: UserToken, clip: any = {}): Promise => {
+export const clip = async (user: UserToken, clip: Partial = {}): Promise => {
const res = await api('clips/create', {
description: null,
isPublic: true,
@@ -231,18 +226,18 @@ export const clip = async (user: UserToken, clip: any = {}): Promise => {
return res.body;
};
-export const galleryPost = async (user: UserToken, channel: any = {}): Promise => {
+export const galleryPost = async (user: UserToken, galleryPost: Partial = {}): Promise => {
const res = await api('gallery/posts/create', {
description: null,
fileIds: [],
isSensitive: false,
title: 'test',
- ...channel,
+ ...galleryPost,
}, user);
return res.body;
};
-export const channel = async (user: UserToken, channel: any = {}): Promise => {
+export const channel = async (user: UserToken, channel: Partial = {}): Promise => {
const res = await api('channels/create', {
bannerId: null,
description: null,
@@ -252,7 +247,7 @@ export const channel = async (user: UserToken, channel: any = {}): Promise
return res.body;
};
-export const role = async (user: UserToken, role: any = {}, policies: any = {}): Promise => {
+export const role = async (user: UserToken, role: Partial = {}, policies: any = {}): Promise => {
const res = await api('admin/roles/create', {
asBadge: false,
canEditMembersByModerator: false,
@@ -260,7 +255,7 @@ export const role = async (user: UserToken, role: any = {}, policies: any = {}):
condFormula: {
id: 'ebef1684-672d-49b6-ad82-1b3ec3784f85',
type: 'isRemote',
- },
+ } as any,
description: '',
displayOrder: 0,
iconUrl: null,
@@ -298,7 +293,7 @@ interface UploadOptions {
export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{
status: number,
headers: Headers,
- body: misskey.Endpoints['drive/files/create']['res'] | null
+ body: misskey.entities.DriveFile | null
}> => {
const absPath = path == null
? new URL('resources/Lenna.jpg', import.meta.url)
@@ -335,14 +330,14 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO
};
};
-export const uploadUrl = async (user: UserToken, url: string): Promise> => {
+export const uploadUrl = async (user: UserToken, url: string): Promise => {
const marker = Math.random().toString();
const catcher = makeStreamCatcher(
user,
'main',
(msg) => msg.type === 'urlUploadFinished' && msg.body.marker === marker,
- (msg) => msg.body.file as Packed<'DriveFile'>,
+ (msg) => msg.body.file,
60 * 1000,
);
From 983480131bf6ac48b3834d334deb97a6b3f2f4f6 Mon Sep 17 00:00:00 2001
From: tamaina
Date: Mon, 4 Mar 2024 12:54:13 +0900
Subject: [PATCH 003/218] chore: Automated release (#13075)
* chore: Automated release
* follow
---
.github/workflows/release-edit-with-push.yml | 40 ++++++
.github/workflows/release-with-dispatch.yml | 122 +++++++++++++++++++
.github/workflows/release-with-ready.yml | 38 ++++++
3 files changed, 200 insertions(+)
create mode 100644 .github/workflows/release-edit-with-push.yml
create mode 100644 .github/workflows/release-with-dispatch.yml
create mode 100644 .github/workflows/release-with-ready.yml
diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml
new file mode 100644
index 0000000000..944b98eb7c
--- /dev/null
+++ b/.github/workflows/release-edit-with-push.yml
@@ -0,0 +1,40 @@
+name: "Release Manager: sync changelog with PR"
+
+on:
+ push:
+ branches:
+ - release/**
+ paths:
+ - 'CHANGELOG.md'
+
+env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+permissions:
+ contents: write
+ issues: write
+ pull-requests: write
+
+jobs:
+ edit:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ # headがrelease/かつopenのPRを1つ取得
+ - name: Get PR
+ run: |
+ echo "pr_number=$(gh pr list --limit 1 --head "${{ github.ref_name }}" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
+ id: get_pr
+ - name: Get target version
+ uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1
+ id: v
+ # CHANGELOG.mdの内容を取得
+ - name: Get changelog
+ uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v1
+ with:
+ version: ${{ steps.v.outputs.target_version }}
+ id: changelog
+ # PRのnotesを更新
+ - name: Update PR
+ run: |
+ gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}"
diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml
new file mode 100644
index 0000000000..1a954739d9
--- /dev/null
+++ b/.github/workflows/release-with-dispatch.yml
@@ -0,0 +1,122 @@
+name: "Release Manager [Dispatch]"
+
+on:
+ workflow_dispatch:
+ inputs:
+ ## Specify the type of the next release.
+ #version_increment_type:
+ # type: choice
+ # description: 'VERSION INCREMENT TYPE'
+ # default: 'patch'
+ # required: false
+ # options:
+ # - 'major'
+ # - 'minor'
+ # - 'patch'
+ merge:
+ type: boolean
+ description: 'MERGE RELEASE BRANCH TO MAIN'
+ default: false
+
+env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+permissions:
+ contents: write
+ issues: write
+ pull-requests: write
+
+jobs:
+ get-pr:
+ runs-on: ubuntu-latest
+ outputs:
+ pr_number: ${{ steps.get_pr.outputs.pr_number }}
+ steps:
+ - uses: actions/checkout@v4
+ # headがrelease/かつopenのPRを1つ取得
+ - name: Get PRs
+ run: |
+ echo "pr_number=$(gh pr list --limit 1 --search "head:release/ is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
+ id: get_pr
+
+ merge:
+ uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v1
+ needs: get-pr
+ if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge == true }}
+ with:
+ pr_number: ${{ needs.get-pr.outputs.pr_number }}
+ package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+ # Text to prepend to the changelog
+ # The first line must be `## Unreleased`
+ changes_template: |
+ ## Unreleased
+
+ ### General
+ -
+
+ ### Client
+ -
+
+ ### Server
+ -
+
+ use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+ secrets:
+ RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+ RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
+ RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
+ RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
+
+ create-prerelease:
+ uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
+ needs: get-pr
+ if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge != true }}
+ with:
+ pr_number: ${{ needs.get-pr.outputs.pr_number }}
+ package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+ use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+ secrets:
+ RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+ RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
+
+ create-target:
+ uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v1
+ needs: get-pr
+ if: ${{ needs.get-pr.outputs.pr_number == '' }}
+ with:
+ # The script for version increment.
+ # process.env.CURRENT_VERSION: The current version.
+ #
+ # Misskey calender versioning (yyyy.MM.patch) example
+ version_increment_script: |
+ const now = new Date();
+ const year = now.toLocaleDateString('en-US', { year: 'numeric', timeZone: 'Asia/Tokyo' });
+ const month = now.toLocaleDateString('en-US', { month: 'numeric', timeZone: 'Asia/Tokyo' });
+ const [major, minor, _patch] = process.env.CURRENT_VERSION.split('.');
+ const patch = Number(_patch.split('-')[0]);
+ if (Number.isNaN(patch)) {
+ console.error('Invalid patch version', year, month, process.env.CURRENT_VERSION, major, minor, _patch);
+ throw new Error('Invalid patch version');
+ }
+ if (year !== major || month !== minor) {
+ return `${year}.${month}.0`;
+ } else {
+ return `${major}.${minor}.${patch + 1}`;
+ }
+ ##Semver example
+ #version_increment_script: |
+ # const [major, minor, patch] = process.env.CURRENT_VERSION.split('.');
+ # if ("${{ inputs.version_increment_type }}" === "major") {
+ # return `${Number(major) + 1}.0.0`;
+ # } else if ("${{ inputs.version_increment_type }}" === "minor") {
+ # return `${major}.${Number(minor) + 1}.0`;
+ # } else {
+ # return `${major}.${minor}.${Number(patch) + 1}`;
+ # }
+ package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+ use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+ secrets:
+ RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+ RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
+ RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }}
+ RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }}
diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml
new file mode 100644
index 0000000000..b64ed20791
--- /dev/null
+++ b/.github/workflows/release-with-ready.yml
@@ -0,0 +1,38 @@
+name: "Release Manager: release RC when ready for review"
+
+on:
+ pull_request:
+ types: [ready_for_review]
+
+env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+permissions:
+ contents: write
+ issues: write
+ pull-requests: write
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ outputs:
+ ref: ${{ steps.get_pr.outputs.ref }}
+ steps:
+ - uses: actions/checkout@v4
+ # PR情報を取得
+ - name: Get PR
+ run: |
+ pr_json=$(gh pr view ${{ github.event.pull_request.number }} --json isDraft,headRefName)
+ echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
+ id: get_pr
+ release:
+ uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
+ needs: check
+ if: startsWith(needs.check.outputs.ref, 'release/')
+ with:
+ pr_number: ${{ github.event.pull_request.number }}
+ package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }}
+ use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }}
+ secrets:
+ RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }}
+ RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
From 9542cb8d6253a93b06a68b9ac3647367f8f7354c Mon Sep 17 00:00:00 2001
From: tamaina
Date: Mon, 4 Mar 2024 13:48:57 +0900
Subject: [PATCH 004/218] =?UTF-8?q?fix(backend):=20=E3=83=AA=E3=83=A2?=
=?UTF-8?q?=E3=83=BC=E3=83=88=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=81=AE?=
=?UTF-8?q?=E6=83=85=E5=A0=B1=E3=81=8C=E6=9B=B4=E6=96=B0=E3=81=A7=E3=81=8D?=
=?UTF-8?q?=E3=81=AA=E3=81=8F=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=84=E3=81=9F?=
=?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#13507)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix(backend): fetchInstanceMetadataのLockが永遠に解除されない問題を修正
Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
* fix test
* fix
* comment
* comment
* improve test
---------
Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
---
.../src/core/FetchInstanceMetadataService.ts | 28 ++++++++++++++-----
.../test/unit/FetchInstanceMetadataService.ts | 24 ++++++++++++++--
2 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts
index bc270bd28f..8d173855f3 100644
--- a/packages/backend/src/core/FetchInstanceMetadataService.ts
+++ b/packages/backend/src/core/FetchInstanceMetadataService.ts
@@ -51,21 +51,35 @@ export class FetchInstanceMetadataService {
}
@bindThis
- public async tryLock(host: string): Promise {
- const mutex = await this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '1', 'GET');
- return mutex !== '1';
+ // public for test
+ public async tryLock(host: string): Promise {
+ // TODO: マイグレーションなのであとで消す (2024.3.1)
+ this.redisClient.del(`fetchInstanceMetadata:mutex:${host}`);
+
+ return await this.redisClient.set(
+ `fetchInstanceMetadata:mutex:v2:${host}`, '1',
+ 'EX', 30, // 30秒したら自動でロック解除 https://github.com/misskey-dev/misskey/issues/13506#issuecomment-1975375395
+ 'GET' // 古い値を返す(なかったらnull)
+ );
}
@bindThis
- public unlock(host: string): Promise<'OK'> {
- return this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '0');
+ // public for test
+ public unlock(host: string): Promise {
+ return this.redisClient.del(`fetchInstanceMetadata:mutex:v2:${host}`);
}
@bindThis
public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise {
const host = instance.host;
- // Acquire mutex to ensure no parallel runs
- if (!await this.tryLock(host)) return;
+
+ // finallyでunlockされてしまうのでtry内でロックチェックをしない
+ // (returnであってもfinallyは実行される)
+ if (!force && await this.tryLock(host) === '1') {
+ // 1が返ってきていたらロックされているという意味なので、何もしない
+ return;
+ }
+
try {
if (!force) {
const _instance = await this.federatedInstanceService.fetch(host);
diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts
index 510b84b680..bf8f3ab0e3 100644
--- a/packages/backend/test/unit/FetchInstanceMetadataService.ts
+++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts
@@ -56,6 +56,7 @@ describe('FetchInstanceMetadataService', () => {
} else if (token === DI.redis) {
return mockRedis;
}
+ return null;
})
.compile();
@@ -78,6 +79,7 @@ describe('FetchInstanceMetadataService', () => {
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
+
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
expect(tryLockSpy).toHaveBeenCalledTimes(1);
expect(unlockSpy).toHaveBeenCalledTimes(1);
@@ -92,6 +94,7 @@ describe('FetchInstanceMetadataService', () => {
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
+
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
expect(tryLockSpy).toHaveBeenCalledTimes(1);
expect(unlockSpy).toHaveBeenCalledTimes(1);
@@ -104,13 +107,30 @@ describe('FetchInstanceMetadataService', () => {
const now = Date.now();
federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
httpRequestService.getJson.mockImplementation(() => { throw Error(); });
+ await fetchInstanceMetadataService.tryLock('example.com');
const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
- await fetchInstanceMetadataService.tryLock('example.com');
+
await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any);
- expect(tryLockSpy).toHaveBeenCalledTimes(2);
+ expect(tryLockSpy).toHaveBeenCalledTimes(1);
expect(unlockSpy).toHaveBeenCalledTimes(0);
expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
expect(httpRequestService.getJson).toHaveBeenCalledTimes(0);
});
+
+ test('Do when lock not acquired but forced', async () => {
+ redisClient.set = mockRedis();
+ const now = Date.now();
+ federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any);
+ httpRequestService.getJson.mockImplementation(() => { throw Error(); });
+ await fetchInstanceMetadataService.tryLock('example.com');
+ const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock');
+ const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock');
+
+ await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any, true);
+ expect(tryLockSpy).toHaveBeenCalledTimes(0);
+ expect(unlockSpy).toHaveBeenCalledTimes(1);
+ expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0);
+ expect(httpRequestService.getJson).toHaveBeenCalled();
+ });
});
From 96ab1af03b821ac265a1e8ff492c154b80e02759 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Mon, 4 Mar 2024 16:09:24 +0900
Subject: [PATCH 005/218] Update CHANGELOG.md
---
CHANGELOG.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bafee277d2..ca7bf85fd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,17 @@
-->
+## Unreleased
+
+### General
+-
+
+### Client
+-
+
+### Server
+-
+
## 2024.3.1
### General
From 13f5fafdbc869207141f2a2f1f75f61c3147372d Mon Sep 17 00:00:00 2001
From: tamaina
Date: Mon, 4 Mar 2024 10:39:43 +0000
Subject: [PATCH 006/218] remove template txt
---
CHANGELOG.md | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca7bf85fd0..349e99d133 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,17 +1,3 @@
-
-
## Unreleased
### General
From 83a5bc0ecd05a352e164bda1f66f48962159c427 Mon Sep 17 00:00:00 2001
From: tamaina
Date: Tue, 5 Mar 2024 14:26:16 +0900
Subject: [PATCH 007/218] =?UTF-8?q?=20doc:=20Nest=E3=81=A7=E5=BE=AA?=
=?UTF-8?q?=E7=92=B0=E4=BE=9D=E5=AD=98=E3=81=8C=E3=81=82=E3=82=8B=E5=A0=B4?=
=?UTF-8?q?=E5=90=88=E3=81=AECONTRIBUTING.md=E3=81=AB=E6=9B=B8=E3=81=8F=20?=
=?UTF-8?q?=20(#13522)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* doc: Nestモジュールテストの例をCONTRIBUTING.mdに書く
* rm normal test
* forwardRef
---
CONTRIBUTING.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a3263bf6aa..dcb625626d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -316,6 +316,98 @@ export const handlers = [
Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files.
+## Nest
+
+### Nest Service Circular dependency / Nestでサービスの循環参照でエラーが起きた場合
+
+#### forwardRef
+まずは簡単に`forwardRef`を試してみる
+
+```typescript
+export class FooService {
+ constructor(
+ @Inject(forwardRef(() => BarService))
+ private barService: BarService
+ ) {
+ }
+}
+```
+
+#### OnModuleInit
+できなければ`OnModuleInit`を使う
+
+```typescript
+import { Injectable, OnModuleInit } from '@nestjs/common';
+import { ModuleRef } from '@nestjs/core';
+import { BarService } from '@/core/BarService';
+
+@Injectable()
+export class FooService implements OnModuleInit {
+ private barService: BarService // constructorから移動してくる
+
+ constructor(
+ private moduleRef: ModuleRef,
+ ) {
+ }
+
+ async onModuleInit() {
+ this.barService = this.moduleRef.get(BarService.name);
+ }
+
+ public async niceMethod() {
+ return await this.barService.incredibleMethod({ hoge: 'fuga' });
+ }
+}
+```
+
+##### Service Unit Test
+テストで`onModuleInit`を呼び出す必要がある
+
+```typescript
+// import ...
+
+describe('test', () => {
+ let app: TestingModule;
+ let fooService: FooService; // for test case
+ let barService: BarService; // for test case
+
+ beforeEach(async () => {
+ app = await Test.createTestingModule({
+ imports: ...,
+ providers: [
+ FooService,
+ { // mockする (mockは必須ではないかもしれない)
+ provide: BarService,
+ useFactory: () => ({
+ incredibleMethod: jest.fn(),
+ }),
+ },
+ { // Provideにする
+ provide: BarService.name,
+ useExisting: BarService,
+ },
+ ],
+ })
+ .useMocker(...
+ .compile();
+
+ fooService = app.get(FooService);
+ barService = app.get(BarService) as jest.Mocked;
+
+ // onModuleInitを実行する
+ await fooService.onModuleInit();
+ });
+
+ test('nice', () => {
+ await fooService.niceMethod();
+
+ expect(barService.incredibleMethod).toHaveBeenCalled();
+ expect(barService.incredibleMethod.mock.lastCall![0])
+ .toEqual({ hoge: 'fuga' });
+ });
+})
+```
+
## Notes
### Misskeyのドメイン固有の概念は`Mi`をprefixする
From 45672a70f9f8fd932896468f9bfdc6c511013682 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 5 Mar 2024 17:27:33 +0900
Subject: [PATCH 008/218] =?UTF-8?q?fix(frontend):=20router=E9=81=B7?=
=?UTF-8?q?=E7=A7=BB=E6=99=82=E3=81=ABmatchAll=E3=81=AB=E5=85=A5=E3=81=A3?=
=?UTF-8?q?=E3=81=9F=E5=A0=B4=E5=90=88=E4=B8=80=E5=BA=A6`location.href`?=
=?UTF-8?q?=E3=82=92=E7=B5=8C=E7=94=B1=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?=
=?UTF-8?q?=E3=81=AB=20(#13509)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix(frontend): router遷移時にmatchAllに入った場合一度`location.href`を経由するように
* Update Changelog
* Update CHANGELOG.md
* remove unnecessary args
---
CHANGELOG.md | 2 +-
packages/frontend/src/nirax.ts | 20 ++++++++++++--------
packages/frontend/vite.config.local-dev.ts | 3 +++
3 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 349e99d133..0cebaabffd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@
-
### Client
--
+- Fix: 一部のページ内リンクが正しく動作しない問題を修正
### Server
-
diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts
index 616fb104e6..6a8ea09ed6 100644
--- a/packages/frontend/src/nirax.ts
+++ b/packages/frontend/src/nirax.ts
@@ -373,7 +373,7 @@ export class Router extends EventEmitter implements IRouter {
this.currentRoute.value = res.route;
this.currentKey = res.route.globalCacheKey ?? key ?? path;
- if (emitChange) {
+ if (emitChange && res.route.path !== '/:(*)') {
this.emit('change', {
beforePath,
path,
@@ -408,13 +408,17 @@ export class Router extends EventEmitter implements IRouter {
if (cancel) return;
}
const res = this.navigate(path, null);
- this.emit('push', {
- beforePath,
- path: res._parsedRoute.fullPath,
- route: res.route,
- props: res.props,
- key: this.currentKey,
- });
+ if (res.route.path === '/:(*)') {
+ location.href = path;
+ } else {
+ this.emit('push', {
+ beforePath,
+ path: res._parsedRoute.fullPath,
+ route: res.route,
+ props: res.props,
+ key: this.currentKey,
+ });
+ }
}
public replace(path: string, key?: string | null) {
diff --git a/packages/frontend/vite.config.local-dev.ts b/packages/frontend/vite.config.local-dev.ts
index 6d9488797c..460787fd05 100644
--- a/packages/frontend/vite.config.local-dev.ts
+++ b/packages/frontend/vite.config.local-dev.ts
@@ -48,6 +48,9 @@ const devConfig = {
},
'/url': httpUrl,
'/proxy': httpUrl,
+ '/_info_card_': httpUrl,
+ '/bios': httpUrl,
+ '/cli': httpUrl,
},
},
build: {
From 08d618bb8b98199a4670313019d6a85ad4cf155b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Tue, 5 Mar 2024 18:06:57 +0900
Subject: [PATCH 009/218] =?UTF-8?q?enhance(frontend):=20=E8=87=AA=E5=88=86?=
=?UTF-8?q?=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88=E3=81=AE=E6=B7=BB=E4=BB=98?=
=?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=8B=E3=82=89=E7=9B=B4?=
=?UTF-8?q?=E6=8E=A5=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E8=A9=B3?=
=?UTF-8?q?=E7=B4=B0=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB=E9=A3=9B=E3=81=B9?=
=?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B=20(#1352?=
=?UTF-8?q?0)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* enhance(frontend): 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるようにする
* 他のファイルタイプにも対応
* Update Changelog
---------
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
CHANGELOG.md | 1 +
.../src/core/entities/DriveFileEntityService.ts | 2 +-
packages/frontend/src/components/MkMediaAudio.vue | 15 ++++++++++++---
packages/frontend/src/components/MkMediaImage.vue | 9 ++++++++-
packages/frontend/src/components/MkMediaVideo.vue | 15 ++++++++++++---
5 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0cebaabffd..1b90094279 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
-
### Client
+- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
### Server
diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts
index 8affe2b3bf..26bf386cbc 100644
--- a/packages/backend/src/core/entities/DriveFileEntityService.ts
+++ b/packages/backend/src/core/entities/DriveFileEntityService.ts
@@ -248,7 +248,7 @@ export class DriveFileEntityService {
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
detail: true,
}) : null,
- userId: opts.withUser ? file.userId : null,
+ userId: file.userId,
user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId) : null,
});
}
diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue
index d42146f941..96c9b9fd66 100644
--- a/packages/frontend/src/components/MkMediaAudio.vue
+++ b/packages/frontend/src/components/MkMediaAudio.vue
@@ -66,7 +66,7 @@ import * as os from '@/os.js';
import bytes from '@/filters/bytes.js';
import { hms } from '@/filters/hms.js';
import MkMediaRange from '@/components/MkMediaRange.vue';
-import { iAmModerator } from '@/account.js';
+import { $i, iAmModerator } from '@/account.js';
const props = defineProps<{
audio: Misskey.entities.DriveFile;
@@ -96,8 +96,6 @@ function showMenu(ev: MouseEvent) {
if (iAmModerator) {
menu.push({
- type: 'divider',
- }, {
text: props.audio.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: props.audio.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
danger: true,
@@ -105,6 +103,17 @@ function showMenu(ev: MouseEvent) {
});
}
+ if ($i?.id === props.audio.userId) {
+ menu.push({
+ type: 'divider',
+ }, {
+ type: 'link' as const,
+ text: i18n.ts._fileViewer.title,
+ icon: 'ti ti-info-circle',
+ to: `/my/drive/file/${props.audio.id}`,
+ });
+ }
+
menuShowing.value = true;
os.popupMenu(menu, ev.currentTarget ?? ev.target, {
align: 'right',
diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue
index 4ba2c76133..82f36fe5c4 100644
--- a/packages/frontend/src/components/MkMediaImage.vue
+++ b/packages/frontend/src/components/MkMediaImage.vue
@@ -59,7 +59,7 @@ import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
-import { iAmModerator } from '@/account.js';
+import { $i, iAmModerator } from '@/account.js';
const props = withDefaults(defineProps<{
image: Misskey.entities.DriveFile;
@@ -114,6 +114,13 @@ function showMenu(ev: MouseEvent) {
action: () => {
os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true });
},
+ }] : []), ...($i?.id === props.image.userId ? [{
+ type: 'divider' as const,
+ }, {
+ type: 'link' as const,
+ text: i18n.ts._fileViewer.title,
+ icon: 'ti ti-info-circle',
+ to: `/my/drive/file/${props.image.id}`,
}] : [])], ev.currentTarget ?? ev.target);
}
diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index eab4fdfd6b..73c1b6ff9d 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -94,7 +94,7 @@ import * as os from '@/os.js';
import { isFullscreenNotSupported } from '@/scripts/device-kind.js';
import hasAudio from '@/scripts/media-has-audio.js';
import MkMediaRange from '@/components/MkMediaRange.vue';
-import { iAmModerator } from '@/account.js';
+import { $i, iAmModerator } from '@/account.js';
const props = defineProps<{
video: Misskey.entities.DriveFile;
@@ -122,8 +122,6 @@ function showMenu(ev: MouseEvent) {
if (iAmModerator) {
menu.push({
- type: 'divider',
- }, {
text: props.video.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: props.video.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',
danger: true,
@@ -131,6 +129,17 @@ function showMenu(ev: MouseEvent) {
});
}
+ if ($i?.id === props.video.userId) {
+ menu.push({
+ type: 'divider',
+ }, {
+ type: 'link' as const,
+ text: i18n.ts._fileViewer.title,
+ icon: 'ti ti-info-circle',
+ to: `/my/drive/file/${props.video.id}`,
+ });
+ }
+
menuShowing.value = true;
os.popupMenu(menu, ev.currentTarget ?? ev.target, {
align: 'right',
From 4457b02db2ca7591afa8683141e4b223170ea367 Mon Sep 17 00:00:00 2001
From: tamaina
Date: Wed, 6 Mar 2024 08:08:32 +0000
Subject: [PATCH 010/218] =?UTF-8?q?fix(frontend)=3F:=20importAppScript?=
=?UTF-8?q?=E3=81=AFimport=E3=82=92await=E3=81=99=E3=82=8B=E3=82=88?=
=?UTF-8?q?=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/backend/src/server/web/boot.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index 59441826b0..396536948e 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -86,8 +86,8 @@
//#endregion
//#region Script
- function importAppScript() {
- import(`/vite/${CLIENT_ENTRY}`)
+ async function importAppScript() {
+ await import(`/vite/${CLIENT_ENTRY}`)
.catch(async e => {
console.error(e);
renderError('APP_IMPORT', e);
From 00c1e4eb550c68f43ae44ba9f0c8da9887fc2180 Mon Sep 17 00:00:00 2001
From: tamaina
Date: Wed, 6 Mar 2024 09:40:47 +0000
Subject: [PATCH 011/218] =?UTF-8?q?perf:=20boot.js=E3=81=AE=E8=AA=BF?=
=?UTF-8?q?=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/backend/src/server/web/boot.js | 525 ++++++++++++++----------
1 file changed, 300 insertions(+), 225 deletions(-)
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index 396536948e..bc7b800d22 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -7,17 +7,257 @@
* BOOT LOADER
* サーバーからレスポンスされるHTMLに埋め込まれるスクリプトで、以下の役割を持ちます。
* - 翻訳ファイルをフェッチする。
- * - バージョンに基づいて適切なメインスクリプトを読み込む。
+ * - 事前に挿入されたCLIENT_ENTRYを読んで適切なメインスクリプトを読み込む。
* - キャッシュされたコンパイル済みテーマを適用する。
* - クライアントの設定値に基づいて対応するHTMLクラス等を設定する。
+ * - もしメインスクリプトの読み込みなどでエラーが発生した場合は、renderErrorでエラーを描画する。
* テーマをこの段階で設定するのは、メインスクリプトが読み込まれる間もテーマを適用したいためです。
- * 注: webpackは介さないため、このファイルではrequireやimportは使えません。
*/
'use strict';
+var misskey_loader = new Set();
+
// ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
-(async () => {
+function boot() {
+ const defaultSolutions = [
+ 'Clear the browser cache / ブラウザのキャッシュをクリアする',
+ 'Update your os and browser / ブラウザおよびOSを最新バージョンに更新する',
+ 'Disable an adblocker / アドブロッカーを無効にする',
+ '(Tor Browser) Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する'
+ ];
+
+ const onErrorStyle = `
+ * {
+ font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
+ }
+
+ #misskey_app,
+ #splash {
+ display: none !important;
+ }
+
+ body,
+ html {
+ background-color: #222;
+ color: #dfddcc;
+ justify-content: center;
+ margin: auto;
+ padding: 10px;
+ text-align: center;
+ }
+
+ button {
+ border-radius: 999px;
+ padding: 0px 12px 0px 12px;
+ border: none;
+ cursor: pointer;
+ margin-bottom: 12px;
+ }
+
+ .button-big {
+ background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
+ line-height: 50px;
+ }
+
+ .button-big:hover {
+ background: rgb(153, 204, 0);
+ }
+
+ .button-small {
+ background: #444;
+ line-height: 40px;
+ }
+
+ .button-small:hover {
+ background: #555;
+ }
+
+ .button-label-big {
+ color: #222;
+ font-weight: bold;
+ font-size: 1.2em;
+ padding: 12px;
+ }
+
+ .button-label-small {
+ color: rgb(153, 204, 0);
+ font-size: 16px;
+ padding: 12px;
+ }
+
+ a {
+ color: rgb(134, 179, 0);
+ text-decoration: none;
+ }
+
+ p,
+ li {
+ font-size: 16px;
+ }
+
+ .icon-warning {
+ color: #dec340;
+ height: 4rem;
+ padding-top: 2rem;
+ }
+
+ h1 {
+ font-size: 1.5em;
+ margin: 1em;
+ }
+
+ summary {
+ cursor: pointer;
+ }
+
+ code {
+ font-family: Fira, FiraCode, monospace;
+ }
+
+ #errors {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .errorInfo {
+ background: #333;
+ width: 40rem;
+ max-width: 100%;
+ border-radius: 10px;
+ justify-content: center;
+ padding: 1rem;
+ margin-bottom: 1rem;
+ box-sizing: border-box;
+ }
+
+ .errorInfo > pre {
+ text-wrap: auto;
+ text-wrap: balance;
+ }
+ `;
+
+
+ const addStyle = (styleText) => {
+ try {
+ let css = document.createElement('style');
+ css.appendChild(document.createTextNode(styleText));
+ document.head.appendChild(css);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+
+ const renderError = (code, details, solutions = defaultSolutions) => {
+ if (document.readyState === 'loading') {
+ window.addEventListener('DOMContentLoaded', () => {
+ renderError(code, details, solutions);
+ });
+ try {
+ addStyle(onErrorStyle);
+ } catch (e) { }
+ return;
+ }
+
+ let errorsElement = document.getElementById('errors');
+
+ if (!errorsElement) {
+ // エラー描画用のビューになっていない場合は、エラー描画用のビューに切り替える
+ document.body.innerHTML = `
+
+
+
+
+
+ Failed to load 読み込みに失敗しました
+
+ Reload / リロード
+
+ The following actions may solve the problem. / 以下を行うと解決する可能性があります。
+ ${solutions.map(x => `${x}
`).join('')}
+
+ Other options / その他のオプション
+
+
+ Clear preferences and cache
+
+
+
+
+
+ Start the simple client
+
+
+
+
+
+ Start the repair tool
+
+
+
+
+
+ `;
+ errorsElement = document.getElementById('errors');
+ }
+
+ if (typeof details === 'string') {
+ const errorEl = document.createElement('div');
+ errorEl.classList.add('errorInfo');
+
+ const titleCodeElement = document.createElement('code');
+ titleCodeElement.textContent = `ERROR CODE: ${code}`;
+ errorEl.appendChild(titleCodeElement);
+
+ errorEl.appendChild(document.createElement('br'));
+
+ const detailsCodeElement = document.createElement('code');
+ detailsCodeElement.textContent = details;
+ errorEl.appendChild(detailsCodeElement);
+
+ errorsElement.appendChild(errorEl);
+ } else if (details instanceof Error) {
+ const errorEl = document.createElement('details');
+ errorEl.classList.add('errorInfo');
+
+ const summaryElement = document.createElement('summary');
+ const titleCodeElement = document.createElement('code');
+ titleCodeElement.textContent = `ERROR CODE: ${code}`;
+ summaryElement.appendChild(titleCodeElement);
+ errorEl.appendChild(summaryElement);
+
+ const detailsPreElement = document.createElement('pre');
+ const detailsMessageElement = document.createElement('code');
+ detailsMessageElement.textContent = details.message;
+ detailsPreElement.appendChild(detailsMessageElement);
+ detailsPreElement.appendChild(document.createElement('br'));
+ const detailsCodeElement = document.createElement('code');
+ detailsCodeElement.textContent = details.stack;
+ detailsPreElement.appendChild(detailsCodeElement);
+ errorEl.appendChild(detailsPreElement);
+
+ errorsElement.appendChild(errorEl);
+ } else {
+ const errorEl = document.createElement('details');
+ errorEl.classList.add('errorInfo');
+
+ const summaryElement = document.createElement('summary');
+ const titleCodeElement = document.createElement('code');
+ titleCodeElement.textContent = `ERROR CODE: ${code}`;
+ summaryElement.appendChild(titleCodeElement);
+ errorEl.appendChild(summaryElement);
+
+ const detailsCodeElement = document.createElement('code');
+ detailsCodeElement.textContent = JSON.stringify(details);
+ errorEl.appendChild(detailsCodeElement);
+
+ errorsElement.appendChild(errorEl);
+ }
+
+ addStyle(onErrorStyle);
+ }
+
window.onerror = (e) => {
console.error(e);
renderError('SOMETHING_HAPPENED', e);
@@ -30,63 +270,65 @@
let forceError = localStorage.getItem('forceError');
if (forceError != null) {
renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
+ renderError('FORCED_ERROR', Error('This error is forced by having forceError in local storage.'));
+ return;
}
- //#region Detect language & fetch translations
- if (!localStorage.hasOwnProperty('locale')) {
- const supportedLangs = LANGS;
- let lang = localStorage.getItem('lang');
- if (lang == null || !supportedLangs.includes(lang)) {
- if (supportedLangs.includes(navigator.language)) {
- lang = navigator.language;
- } else {
- lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
+ //#region After DOM loaded
+ async function oncontentload() {
+ const providedMetaEl = document.getElementById('misskey_meta');
+ const meta = providedMetaEl && providedMetaEl.textContent ? JSON.parse(providedMetaEl.textContent) : null;
+ const providedAt = providedMetaEl && providedMetaEl.dataset.generatedAt ? parseInt(providedMetaEl.dataset.generatedAt) : 0;
+ console.log('providedAt', providedAt, 'now', Date.now());
+ if (providedAt < Date.now() - 1000 * 60 * 60 * 24) {
+ // 古いデータがなぜか提供された場合は、エラーを描画する
+ renderError(
+ 'META_PROVIDED_AT_TOO_OLD',
+ 'This view is too old. Please reload.',
+ [
+ 'Reload / リロードする',
+ 'Clear the browser cache then reload / ブラウザのキャッシュをクリアしてリロードする',
+ 'Disable an adblocker / アドブロッカーを無効にする',
+ ]
+ );
+ return;
+ }
- // Fallback
- if (lang == null) lang = 'en-US';
+ //#region Detect language & fetch translations on first load
+ if (!localStorage.hasOwnProperty('locale')) {
+ const supportedLangs = LANGS;
+ let lang = localStorage.getItem('lang');
+ if (lang == null || !supportedLangs.includes(lang)) {
+ if (supportedLangs.includes(navigator.language)) {
+ lang = navigator.language;
+ } else {
+ lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
+
+ // Fallback
+ if (lang == null) lang = 'en-US';
+ }
+ }
+
+ const v = meta?.version;
+
+ // for https://github.com/misskey-dev/misskey/issues/10202
+ if (lang == null || lang.toString == null || lang.toString() === 'null') {
+ console.warn('invalid lang value detected!!!', typeof lang, lang);
+ lang = 'en-US';
+ }
+
+ const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
+ if (localRes.status === 200) {
+ localStorage.setItem('lang', lang);
+ localStorage.setItem('locale', await localRes.text());
+ localStorage.setItem('localeVersion', v);
+ } else {
+ renderError('LOCALE_FETCH');
+ return;
}
}
+ //#endregion
- const metaRes = await window.fetch('/api/meta', {
- method: 'POST',
- body: JSON.stringify({}),
- credentials: 'omit',
- cache: 'no-cache',
- headers: {
- 'Content-Type': 'application/json',
- },
- });
- if (metaRes.status !== 200) {
- renderError('META_FETCH');
- return;
- }
- const meta = await metaRes.json();
- const v = meta.version;
- if (v == null) {
- renderError('META_FETCH_V');
- return;
- }
-
- // for https://github.com/misskey-dev/misskey/issues/10202
- if (lang == null || lang.toString == null || lang.toString() === 'null') {
- console.error('invalid lang value detected!!!', typeof lang, lang);
- lang = 'en-US';
- }
-
- const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
- if (localRes.status === 200) {
- localStorage.setItem('lang', lang);
- localStorage.setItem('locale', await localRes.text());
- localStorage.setItem('localeVersion', v);
- } else {
- renderError('LOCALE_FETCH');
- return;
- }
- }
- //#endregion
-
- //#region Script
- async function importAppScript() {
await import(`/vite/${CLIENT_ENTRY}`)
.catch(async e => {
console.error(e);
@@ -94,12 +336,11 @@
});
}
- // タイミングによっては、この時点でDOMの構築が済んでいる場合とそうでない場合とがある
if (document.readyState !== 'loading') {
- importAppScript();
+ misskey_loader.add(oncontentload());
} else {
window.addEventListener('DOMContentLoaded', () => {
- importAppScript();
+ misskey_loader.add(oncontentload());
});
}
//#endregion
@@ -148,172 +389,6 @@
style.innerHTML = customCss;
document.head.appendChild(style);
}
+}
- async function addStyle(styleText) {
- let css = document.createElement('style');
- css.appendChild(document.createTextNode(styleText));
- document.head.appendChild(css);
- }
-
- function renderError(code, details) {
- let errorsElement = document.getElementById('errors');
-
- if (!errorsElement) {
- document.body.innerHTML = `
-
-
-
-
-
- Failed to load 読み込みに失敗しました
-
- Reload / リロード
-
- The following actions may solve the problem. / 以下を行うと解決する可能性があります。
- Clear the browser cache / ブラウザのキャッシュをクリアする
- Update your os and browser / ブラウザおよびOSを最新バージョンに更新する
- Disable an adblocker / アドブロッカーを無効にする
- (Tor Browser) Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する
-
- Other options / その他のオプション
-
-
- Clear preferences and cache
-
-
-
-
-
- Start the simple client
-
-
-
-
-
- Start the repair tool
-
-
-
-
-
- `;
- errorsElement = document.getElementById('errors');
- }
- const detailsElement = document.createElement('details');
- detailsElement.id = 'errorInfo';
- detailsElement.innerHTML = `
-
-
- ERROR CODE: ${code}
-
- ${JSON.stringify(details)}
`;
- errorsElement.appendChild(detailsElement);
- addStyle(`
- * {
- font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
- }
-
- #misskey_app,
- #splash {
- display: none !important;
- }
-
- body,
- html {
- background-color: #222;
- color: #dfddcc;
- justify-content: center;
- margin: auto;
- padding: 10px;
- text-align: center;
- }
-
- button {
- border-radius: 999px;
- padding: 0px 12px 0px 12px;
- border: none;
- cursor: pointer;
- margin-bottom: 12px;
- }
-
- .button-big {
- background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
- line-height: 50px;
- }
-
- .button-big:hover {
- background: rgb(153, 204, 0);
- }
-
- .button-small {
- background: #444;
- line-height: 40px;
- }
-
- .button-small:hover {
- background: #555;
- }
-
- .button-label-big {
- color: #222;
- font-weight: bold;
- font-size: 1.2em;
- padding: 12px;
- }
-
- .button-label-small {
- color: rgb(153, 204, 0);
- font-size: 16px;
- padding: 12px;
- }
-
- a {
- color: rgb(134, 179, 0);
- text-decoration: none;
- }
-
- p,
- li {
- font-size: 16px;
- }
-
- .icon-warning {
- color: #dec340;
- height: 4rem;
- padding-top: 2rem;
- }
-
- h1 {
- font-size: 1.5em;
- margin: 1em;
- }
-
- code {
- font-family: Fira, FiraCode, monospace;
- }
-
- #errorInfo {
- background: #333;
- margin-bottom: 2rem;
- padding: 0.5rem 1rem;
- width: 40rem;
- border-radius: 10px;
- justify-content: center;
- margin: auto;
- }
-
- #errorInfo summary {
- cursor: pointer;
- }
-
- #errorInfo summary > * {
- display: inline;
- }
-
- @media screen and (max-width: 500px) {
- #errorInfo {
- width: 50%;
- }
- `)
- }
-})();
+boot();
From 62922352b3cddaee9f72261448d862002e55a67c Mon Sep 17 00:00:00 2001
From: tamaina
Date: Wed, 6 Mar 2024 09:49:01 +0000
Subject: [PATCH 012/218] =?UTF-8?q?Revert=20"perf:=20boot.js=E3=81=AE?=
=?UTF-8?q?=E8=AA=BF=E6=95=B4"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit 00c1e4eb550c68f43ae44ba9f0c8da9887fc2180.
---
packages/backend/src/server/web/boot.js | 523 ++++++++++--------------
1 file changed, 224 insertions(+), 299 deletions(-)
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index bc7b800d22..396536948e 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -7,257 +7,17 @@
* BOOT LOADER
* サーバーからレスポンスされるHTMLに埋め込まれるスクリプトで、以下の役割を持ちます。
* - 翻訳ファイルをフェッチする。
- * - 事前に挿入されたCLIENT_ENTRYを読んで適切なメインスクリプトを読み込む。
+ * - バージョンに基づいて適切なメインスクリプトを読み込む。
* - キャッシュされたコンパイル済みテーマを適用する。
* - クライアントの設定値に基づいて対応するHTMLクラス等を設定する。
- * - もしメインスクリプトの読み込みなどでエラーが発生した場合は、renderErrorでエラーを描画する。
* テーマをこの段階で設定するのは、メインスクリプトが読み込まれる間もテーマを適用したいためです。
+ * 注: webpackは介さないため、このファイルではrequireやimportは使えません。
*/
'use strict';
-var misskey_loader = new Set();
-
// ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
-function boot() {
- const defaultSolutions = [
- 'Clear the browser cache / ブラウザのキャッシュをクリアする',
- 'Update your os and browser / ブラウザおよびOSを最新バージョンに更新する',
- 'Disable an adblocker / アドブロッカーを無効にする',
- '(Tor Browser) Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する'
- ];
-
- const onErrorStyle = `
- * {
- font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
- }
-
- #misskey_app,
- #splash {
- display: none !important;
- }
-
- body,
- html {
- background-color: #222;
- color: #dfddcc;
- justify-content: center;
- margin: auto;
- padding: 10px;
- text-align: center;
- }
-
- button {
- border-radius: 999px;
- padding: 0px 12px 0px 12px;
- border: none;
- cursor: pointer;
- margin-bottom: 12px;
- }
-
- .button-big {
- background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
- line-height: 50px;
- }
-
- .button-big:hover {
- background: rgb(153, 204, 0);
- }
-
- .button-small {
- background: #444;
- line-height: 40px;
- }
-
- .button-small:hover {
- background: #555;
- }
-
- .button-label-big {
- color: #222;
- font-weight: bold;
- font-size: 1.2em;
- padding: 12px;
- }
-
- .button-label-small {
- color: rgb(153, 204, 0);
- font-size: 16px;
- padding: 12px;
- }
-
- a {
- color: rgb(134, 179, 0);
- text-decoration: none;
- }
-
- p,
- li {
- font-size: 16px;
- }
-
- .icon-warning {
- color: #dec340;
- height: 4rem;
- padding-top: 2rem;
- }
-
- h1 {
- font-size: 1.5em;
- margin: 1em;
- }
-
- summary {
- cursor: pointer;
- }
-
- code {
- font-family: Fira, FiraCode, monospace;
- }
-
- #errors {
- display: flex;
- flex-direction: column;
- align-items: center;
- }
-
- .errorInfo {
- background: #333;
- width: 40rem;
- max-width: 100%;
- border-radius: 10px;
- justify-content: center;
- padding: 1rem;
- margin-bottom: 1rem;
- box-sizing: border-box;
- }
-
- .errorInfo > pre {
- text-wrap: auto;
- text-wrap: balance;
- }
- `;
-
-
- const addStyle = (styleText) => {
- try {
- let css = document.createElement('style');
- css.appendChild(document.createTextNode(styleText));
- document.head.appendChild(css);
- } catch (e) {
- console.error(e);
- }
- }
-
- const renderError = (code, details, solutions = defaultSolutions) => {
- if (document.readyState === 'loading') {
- window.addEventListener('DOMContentLoaded', () => {
- renderError(code, details, solutions);
- });
- try {
- addStyle(onErrorStyle);
- } catch (e) { }
- return;
- }
-
- let errorsElement = document.getElementById('errors');
-
- if (!errorsElement) {
- // エラー描画用のビューになっていない場合は、エラー描画用のビューに切り替える
- document.body.innerHTML = `
-
-
-
-
-
- Failed to load 読み込みに失敗しました
-
- Reload / リロード
-
- The following actions may solve the problem. / 以下を行うと解決する可能性があります。
- ${solutions.map(x => `${x}
`).join('')}
-
- Other options / その他のオプション
-
-
- Clear preferences and cache
-
-
-
-
-
- Start the simple client
-
-
-
-
-
- Start the repair tool
-
-
-
-
-
- `;
- errorsElement = document.getElementById('errors');
- }
-
- if (typeof details === 'string') {
- const errorEl = document.createElement('div');
- errorEl.classList.add('errorInfo');
-
- const titleCodeElement = document.createElement('code');
- titleCodeElement.textContent = `ERROR CODE: ${code}`;
- errorEl.appendChild(titleCodeElement);
-
- errorEl.appendChild(document.createElement('br'));
-
- const detailsCodeElement = document.createElement('code');
- detailsCodeElement.textContent = details;
- errorEl.appendChild(detailsCodeElement);
-
- errorsElement.appendChild(errorEl);
- } else if (details instanceof Error) {
- const errorEl = document.createElement('details');
- errorEl.classList.add('errorInfo');
-
- const summaryElement = document.createElement('summary');
- const titleCodeElement = document.createElement('code');
- titleCodeElement.textContent = `ERROR CODE: ${code}`;
- summaryElement.appendChild(titleCodeElement);
- errorEl.appendChild(summaryElement);
-
- const detailsPreElement = document.createElement('pre');
- const detailsMessageElement = document.createElement('code');
- detailsMessageElement.textContent = details.message;
- detailsPreElement.appendChild(detailsMessageElement);
- detailsPreElement.appendChild(document.createElement('br'));
- const detailsCodeElement = document.createElement('code');
- detailsCodeElement.textContent = details.stack;
- detailsPreElement.appendChild(detailsCodeElement);
- errorEl.appendChild(detailsPreElement);
-
- errorsElement.appendChild(errorEl);
- } else {
- const errorEl = document.createElement('details');
- errorEl.classList.add('errorInfo');
-
- const summaryElement = document.createElement('summary');
- const titleCodeElement = document.createElement('code');
- titleCodeElement.textContent = `ERROR CODE: ${code}`;
- summaryElement.appendChild(titleCodeElement);
- errorEl.appendChild(summaryElement);
-
- const detailsCodeElement = document.createElement('code');
- detailsCodeElement.textContent = JSON.stringify(details);
- errorEl.appendChild(detailsCodeElement);
-
- errorsElement.appendChild(errorEl);
- }
-
- addStyle(onErrorStyle);
- }
-
+(async () => {
window.onerror = (e) => {
console.error(e);
renderError('SOMETHING_HAPPENED', e);
@@ -270,65 +30,63 @@ function boot() {
let forceError = localStorage.getItem('forceError');
if (forceError != null) {
renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.')
- renderError('FORCED_ERROR', Error('This error is forced by having forceError in local storage.'));
- return;
}
- //#region After DOM loaded
- async function oncontentload() {
- const providedMetaEl = document.getElementById('misskey_meta');
- const meta = providedMetaEl && providedMetaEl.textContent ? JSON.parse(providedMetaEl.textContent) : null;
- const providedAt = providedMetaEl && providedMetaEl.dataset.generatedAt ? parseInt(providedMetaEl.dataset.generatedAt) : 0;
- console.log('providedAt', providedAt, 'now', Date.now());
- if (providedAt < Date.now() - 1000 * 60 * 60 * 24) {
- // 古いデータがなぜか提供された場合は、エラーを描画する
- renderError(
- 'META_PROVIDED_AT_TOO_OLD',
- 'This view is too old. Please reload.',
- [
- 'Reload / リロードする',
- 'Clear the browser cache then reload / ブラウザのキャッシュをクリアしてリロードする',
- 'Disable an adblocker / アドブロッカーを無効にする',
- ]
- );
+ //#region Detect language & fetch translations
+ if (!localStorage.hasOwnProperty('locale')) {
+ const supportedLangs = LANGS;
+ let lang = localStorage.getItem('lang');
+ if (lang == null || !supportedLangs.includes(lang)) {
+ if (supportedLangs.includes(navigator.language)) {
+ lang = navigator.language;
+ } else {
+ lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
+
+ // Fallback
+ if (lang == null) lang = 'en-US';
+ }
+ }
+
+ const metaRes = await window.fetch('/api/meta', {
+ method: 'POST',
+ body: JSON.stringify({}),
+ credentials: 'omit',
+ cache: 'no-cache',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ if (metaRes.status !== 200) {
+ renderError('META_FETCH');
+ return;
+ }
+ const meta = await metaRes.json();
+ const v = meta.version;
+ if (v == null) {
+ renderError('META_FETCH_V');
return;
}
- //#region Detect language & fetch translations on first load
- if (!localStorage.hasOwnProperty('locale')) {
- const supportedLangs = LANGS;
- let lang = localStorage.getItem('lang');
- if (lang == null || !supportedLangs.includes(lang)) {
- if (supportedLangs.includes(navigator.language)) {
- lang = navigator.language;
- } else {
- lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
-
- // Fallback
- if (lang == null) lang = 'en-US';
- }
- }
-
- const v = meta?.version;
-
- // for https://github.com/misskey-dev/misskey/issues/10202
- if (lang == null || lang.toString == null || lang.toString() === 'null') {
- console.warn('invalid lang value detected!!!', typeof lang, lang);
- lang = 'en-US';
- }
-
- const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
- if (localRes.status === 200) {
- localStorage.setItem('lang', lang);
- localStorage.setItem('locale', await localRes.text());
- localStorage.setItem('localeVersion', v);
- } else {
- renderError('LOCALE_FETCH');
- return;
- }
+ // for https://github.com/misskey-dev/misskey/issues/10202
+ if (lang == null || lang.toString == null || lang.toString() === 'null') {
+ console.error('invalid lang value detected!!!', typeof lang, lang);
+ lang = 'en-US';
}
- //#endregion
+ const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
+ if (localRes.status === 200) {
+ localStorage.setItem('lang', lang);
+ localStorage.setItem('locale', await localRes.text());
+ localStorage.setItem('localeVersion', v);
+ } else {
+ renderError('LOCALE_FETCH');
+ return;
+ }
+ }
+ //#endregion
+
+ //#region Script
+ async function importAppScript() {
await import(`/vite/${CLIENT_ENTRY}`)
.catch(async e => {
console.error(e);
@@ -336,11 +94,12 @@ function boot() {
});
}
+ // タイミングによっては、この時点でDOMの構築が済んでいる場合とそうでない場合とがある
if (document.readyState !== 'loading') {
- misskey_loader.add(oncontentload());
+ importAppScript();
} else {
window.addEventListener('DOMContentLoaded', () => {
- misskey_loader.add(oncontentload());
+ importAppScript();
});
}
//#endregion
@@ -389,6 +148,172 @@ function boot() {
style.innerHTML = customCss;
document.head.appendChild(style);
}
-}
-boot();
+ async function addStyle(styleText) {
+ let css = document.createElement('style');
+ css.appendChild(document.createTextNode(styleText));
+ document.head.appendChild(css);
+ }
+
+ function renderError(code, details) {
+ let errorsElement = document.getElementById('errors');
+
+ if (!errorsElement) {
+ document.body.innerHTML = `
+
+
+
+
+
+ Failed to load 読み込みに失敗しました
+
+ Reload / リロード
+
+ The following actions may solve the problem. / 以下を行うと解決する可能性があります。
+ Clear the browser cache / ブラウザのキャッシュをクリアする
+ Update your os and browser / ブラウザおよびOSを最新バージョンに更新する
+ Disable an adblocker / アドブロッカーを無効にする
+ (Tor Browser) Set dom.webaudio.enabled to true / dom.webaudio.enabledをtrueに設定する
+
+ Other options / その他のオプション
+
+
+ Clear preferences and cache
+
+
+
+
+
+ Start the simple client
+
+
+
+
+
+ Start the repair tool
+
+
+
+
+
+ `;
+ errorsElement = document.getElementById('errors');
+ }
+ const detailsElement = document.createElement('details');
+ detailsElement.id = 'errorInfo';
+ detailsElement.innerHTML = `
+
+
+ ERROR CODE: ${code}
+
+ ${JSON.stringify(details)}
`;
+ errorsElement.appendChild(detailsElement);
+ addStyle(`
+ * {
+ font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
+ }
+
+ #misskey_app,
+ #splash {
+ display: none !important;
+ }
+
+ body,
+ html {
+ background-color: #222;
+ color: #dfddcc;
+ justify-content: center;
+ margin: auto;
+ padding: 10px;
+ text-align: center;
+ }
+
+ button {
+ border-radius: 999px;
+ padding: 0px 12px 0px 12px;
+ border: none;
+ cursor: pointer;
+ margin-bottom: 12px;
+ }
+
+ .button-big {
+ background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
+ line-height: 50px;
+ }
+
+ .button-big:hover {
+ background: rgb(153, 204, 0);
+ }
+
+ .button-small {
+ background: #444;
+ line-height: 40px;
+ }
+
+ .button-small:hover {
+ background: #555;
+ }
+
+ .button-label-big {
+ color: #222;
+ font-weight: bold;
+ font-size: 1.2em;
+ padding: 12px;
+ }
+
+ .button-label-small {
+ color: rgb(153, 204, 0);
+ font-size: 16px;
+ padding: 12px;
+ }
+
+ a {
+ color: rgb(134, 179, 0);
+ text-decoration: none;
+ }
+
+ p,
+ li {
+ font-size: 16px;
+ }
+
+ .icon-warning {
+ color: #dec340;
+ height: 4rem;
+ padding-top: 2rem;
+ }
+
+ h1 {
+ font-size: 1.5em;
+ margin: 1em;
+ }
+
+ code {
+ font-family: Fira, FiraCode, monospace;
+ }
+
+ #errorInfo {
+ background: #333;
+ margin-bottom: 2rem;
+ padding: 0.5rem 1rem;
+ width: 40rem;
+ border-radius: 10px;
+ justify-content: center;
+ margin: auto;
+ }
+
+ #errorInfo summary {
+ cursor: pointer;
+ }
+
+ #errorInfo summary > * {
+ display: inline;
+ }
+
+ @media screen and (max-width: 500px) {
+ #errorInfo {
+ width: 50%;
+ }
+ `)
+ }
+})();
From 7ead98cbe592e6911e4a54550cb7bb507e782d7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
<67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Wed, 6 Mar 2024 21:08:42 +0900
Subject: [PATCH 013/218] =?UTF-8?q?enhance(frontend):=20=E3=83=AA=E3=82=A2?=
=?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E7=B7=8F=E6=95=B0?=
=?UTF-8?q?=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?=
=?UTF-8?q?=E3=81=AB=20(#13532)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* enhance(frontend): リアクションの総数を表示するように
* Update Changelog
* リアクション選択済の色をaccentに
---
CHANGELOG.md | 2 ++
locales/index.d.ts | 4 +++
locales/ja-JP.yml | 1 +
.../src/core/entities/NoteEntityService.ts | 1 +
.../backend/src/models/json-schema/note.ts | 4 +++
packages/frontend/src/components/MkNote.vue | 25 ++++++++++-----
.../src/components/MkNoteDetailed.vue | 31 ++++++++++++-------
.../src/components/MkNotification.vue | 27 ++++++++++------
.../src/components/MkTutorialDialog.Note.vue | 1 +
.../components/MkTutorialDialog.PostNote.vue | 1 +
.../components/MkTutorialDialog.Sensitive.vue | 1 +
.../frontend/src/scripts/use-note-capture.ts | 2 ++
packages/frontend/src/style.scss | 7 +++++
packages/misskey-js/src/autogen/types.ts | 1 +
14 files changed, 79 insertions(+), 29 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b90094279..7bdfa53e99 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,8 @@
### Client
- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
+- Enhance: リアクション・いいねの総数を表示するように
+- Enhance: リアクション受け入れが「いいねのみ」の場合はリアクション絵文字一覧を表示しないように
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
### Server
diff --git a/locales/index.d.ts b/locales/index.d.ts
index c1aa163f98..3ac4ff9e74 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -8909,6 +8909,10 @@ export interface Locale extends ILocale {
* {n}人がリアクションしました
*/
"reactedBySomeUsers": ParameterizedString<"n">;
+ /**
+ * {n}人がいいねしました
+ */
+ "likedBySomeUsers": ParameterizedString<"n">;
/**
* {n}人がリノートしました
*/
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 51380e49c5..177d6a06c9 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2355,6 +2355,7 @@ _notification:
sendTestNotification: "テスト通知を送信する"
notificationWillBeDisplayedLikeThis: "通知はこのように表示されます"
reactedBySomeUsers: "{n}人がリアクションしました"
+ likedBySomeUsers: "{n}人がいいねしました"
renotedBySomeUsers: "{n}人がリノートしました"
followedBySomeUsers: "{n}人にフォローされました"
flushNotification: "通知の履歴をリセットする"
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 5b6affc6a5..22d01462e7 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -333,6 +333,7 @@ export class NoteEntityService implements OnModuleInit {
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
renoteCount: note.renoteCount,
repliesCount: note.repliesCount,
+ reactionCount: Object.values(note.reactions).reduce((a, b) => a + b, 0),
reactions: this.reactionService.convertLegacyReactions(note.reactions),
reactionEmojis: this.customEmojiService.populateEmojis(reactionEmojiNames, host),
reactionAndUserPairCache: opts.withReactionAndUserPairCache ? note.reactionAndUserPairCache : undefined,
diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts
index bb4ccc7ee4..2641161c8b 100644
--- a/packages/backend/src/models/json-schema/note.ts
+++ b/packages/backend/src/models/json-schema/note.ts
@@ -223,6 +223,10 @@ export const packedNoteSchema = {
}],
},
},
+ reactionCount: {
+ type: 'number',
+ optional: false, nullable: false,
+ },
renoteCount: {
type: 'number',
optional: false, nullable: false,
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 03a283cab3..656ccc7959 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -93,7 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ appearNote.channel.name }}
-
+
{{ i18n.ts.more }}
@@ -101,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only