test(backend): APIテストの復活 (#10163)
* Revert 1c5291f818
* APIテストの復活
* apiテストの移行
* moduleNameMapper修正
* simpleGetでthrowしないように
status確認しているので要らない
* longer timeout
* ローカルでは問題ないのになんで
* case sensitive
* Run Nest instance within the current process
* Skip some setIntervals
* wait for 5 seconds
* kill them all!!
* logHeapUsage: true
* detectOpenHandlesがじゃましているらしい
* maxWorkers=1?
* restore drive api tests
* workerIdleMemoryLimit: 500MB
* 1024MiB
* Wait what
This commit is contained in:
parent
53987fadd7
commit
61215e50ff
27 changed files with 734 additions and 528 deletions
477
packages/backend/test/e2e/api-visibility.ts
Normal file
477
packages/backend/test/e2e/api-visibility.ts
Normal file
|
@ -0,0 +1,477 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, post, startServer } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('API visibility', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
describe('Note visibility', () => {
|
||||
//#region vars
|
||||
/** ヒロイン */
|
||||
let alice: any;
|
||||
/** フォロワー */
|
||||
let follower: any;
|
||||
/** 非フォロワー */
|
||||
let other: any;
|
||||
/** 非フォロワーでもリプライやメンションをされた人 */
|
||||
let target: any;
|
||||
/** specified mentionでmentionを飛ばされる人 */
|
||||
let target2: any;
|
||||
|
||||
/** public-post */
|
||||
let pub: any;
|
||||
/** home-post */
|
||||
let home: any;
|
||||
/** followers-post */
|
||||
let fol: any;
|
||||
/** specified-post */
|
||||
let spe: any;
|
||||
|
||||
/** public-reply to target's post */
|
||||
let pubR: any;
|
||||
/** home-reply to target's post */
|
||||
let homeR: any;
|
||||
/** followers-reply to target's post */
|
||||
let folR: any;
|
||||
/** specified-reply to target's post */
|
||||
let speR: any;
|
||||
|
||||
/** public-mention to target */
|
||||
let pubM: any;
|
||||
/** home-mention to target */
|
||||
let homeM: any;
|
||||
/** followers-mention to target */
|
||||
let folM: any;
|
||||
/** specified-mention to target */
|
||||
let speM: any;
|
||||
|
||||
/** reply target post */
|
||||
let tgt: any;
|
||||
//#endregion
|
||||
|
||||
const show = async (noteId: any, by: any) => {
|
||||
return await api('/notes/show', {
|
||||
noteId,
|
||||
}, by);
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
//#region prepare
|
||||
// signup
|
||||
alice = await signup({ username: 'alice' });
|
||||
follower = await signup({ username: 'follower' });
|
||||
other = await signup({ username: 'other' });
|
||||
target = await signup({ username: 'target' });
|
||||
target2 = await signup({ username: 'target2' });
|
||||
|
||||
// follow alice <= follower
|
||||
await api('/following/create', { userId: alice.id }, follower);
|
||||
|
||||
// normal posts
|
||||
pub = await post(alice, { text: 'x', visibility: 'public' });
|
||||
home = await post(alice, { text: 'x', visibility: 'home' });
|
||||
fol = await post(alice, { text: 'x', visibility: 'followers' });
|
||||
spe = await post(alice, { text: 'x', visibility: 'specified', visibleUserIds: [target.id] });
|
||||
|
||||
// replies
|
||||
tgt = await post(target, { text: 'y', visibility: 'public' });
|
||||
pubR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'public' });
|
||||
homeR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'home' });
|
||||
folR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'followers' });
|
||||
speR = await post(alice, { text: 'x', replyId: tgt.id, visibility: 'specified' });
|
||||
|
||||
// mentions
|
||||
pubM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'public' });
|
||||
homeM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'home' });
|
||||
folM = await post(alice, { text: '@target x', replyId: tgt.id, visibility: 'followers' });
|
||||
speM = await post(alice, { text: '@target2 x', replyId: tgt.id, visibility: 'specified' });
|
||||
//#endregion
|
||||
});
|
||||
|
||||
//#region show post
|
||||
// public
|
||||
test('[show] public-postを自分が見れる', async () => {
|
||||
const res = await show(pub.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-postをフォロワーが見れる', async () => {
|
||||
const res = await show(pub.id, follower);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-postを非フォロワーが見れる', async () => {
|
||||
const res = await show(pub.id, other);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-postを未認証が見れる', async () => {
|
||||
const res = await show(pub.id, null);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
// home
|
||||
test('[show] home-postを自分が見れる', async () => {
|
||||
const res = await show(home.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-postをフォロワーが見れる', async () => {
|
||||
const res = await show(home.id, follower);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-postを非フォロワーが見れる', async () => {
|
||||
const res = await show(home.id, other);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-postを未認証が見れる', async () => {
|
||||
const res = await show(home.id, null);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
// followers
|
||||
test('[show] followers-postを自分が見れる', async () => {
|
||||
const res = await show(fol.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] followers-postをフォロワーが見れる', async () => {
|
||||
const res = await show(fol.id, follower);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] followers-postを非フォロワーが見れない', async () => {
|
||||
const res = await show(fol.id, other);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] followers-postを未認証が見れない', async () => {
|
||||
const res = await show(fol.id, null);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
// specified
|
||||
test('[show] specified-postを自分が見れる', async () => {
|
||||
const res = await show(spe.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] specified-postを指定ユーザーが見れる', async () => {
|
||||
const res = await show(spe.id, target);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] specified-postをフォロワーが見れない', async () => {
|
||||
const res = await show(spe.id, follower);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-postを非フォロワーが見れない', async () => {
|
||||
const res = await show(spe.id, other);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-postを未認証が見れない', async () => {
|
||||
const res = await show(spe.id, null);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//#region show reply
|
||||
// public
|
||||
test('[show] public-replyを自分が見れる', async () => {
|
||||
const res = await show(pubR.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-replyをされた人が見れる', async () => {
|
||||
const res = await show(pubR.id, target);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-replyをフォロワーが見れる', async () => {
|
||||
const res = await show(pubR.id, follower);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-replyを非フォロワーが見れる', async () => {
|
||||
const res = await show(pubR.id, other);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] public-replyを未認証が見れる', async () => {
|
||||
const res = await show(pubR.id, null);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
// home
|
||||
test('[show] home-replyを自分が見れる', async () => {
|
||||
const res = await show(homeR.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-replyをされた人が見れる', async () => {
|
||||
const res = await show(homeR.id, target);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-replyをフォロワーが見れる', async () => {
|
||||
const res = await show(homeR.id, follower);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-replyを非フォロワーが見れる', async () => {
|
||||
const res = await show(homeR.id, other);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] home-replyを未認証が見れる', async () => {
|
||||
const res = await show(homeR.id, null);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
// followers
|
||||
test('[show] followers-replyを自分が見れる', async () => {
|
||||
const res = await show(folR.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] followers-replyを非フォロワーでもリプライされていれば見れる', async () => {
|
||||
const res = await show(folR.id, target);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] followers-replyをフォロワーが見れる', async () => {
|
||||
const res = await show(folR.id, follower);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] followers-replyを非フォロワーが見れない', async () => {
|
||||
const res = await show(folR.id, other);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] followers-replyを未認証が見れない', async () => {
|
||||
const res = await show(folR.id, null);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
// specified
|
||||
test('[show] specified-replyを自分が見れる', async () => {
|
||||
const res = await show(speR.id, alice);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] specified-replyを指定ユーザーが見れる', async () => {
|
||||
const res = await show(speR.id, target);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] specified-replyをされた人が指定されてなくても見れる', async () => {
|
||||
const res = await show(speR.id, target);
|
||||
assert.strictEqual(res.body.text, 'x');
|
||||
});
|
||||
|
||||
test('[show] specified-replyをフォロワーが見れない', async () => {
|
||||
const res = await show(speR.id, follower);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-replyを非フォロワーが見れない', async () => {
|
||||
const res = await show(speR.id, other);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-replyを未認証が見れない', async () => {
|
||||
const res = await show(speR.id, null);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//#region show mention
|
||||
// public
|
||||
test('[show] public-mentionを自分が見れる', async () => {
|
||||
const res = await show(pubM.id, alice);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] public-mentionをされた人が見れる', async () => {
|
||||
const res = await show(pubM.id, target);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] public-mentionをフォロワーが見れる', async () => {
|
||||
const res = await show(pubM.id, follower);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] public-mentionを非フォロワーが見れる', async () => {
|
||||
const res = await show(pubM.id, other);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] public-mentionを未認証が見れる', async () => {
|
||||
const res = await show(pubM.id, null);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
// home
|
||||
test('[show] home-mentionを自分が見れる', async () => {
|
||||
const res = await show(homeM.id, alice);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] home-mentionをされた人が見れる', async () => {
|
||||
const res = await show(homeM.id, target);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] home-mentionをフォロワーが見れる', async () => {
|
||||
const res = await show(homeM.id, follower);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] home-mentionを非フォロワーが見れる', async () => {
|
||||
const res = await show(homeM.id, other);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] home-mentionを未認証が見れる', async () => {
|
||||
const res = await show(homeM.id, null);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
// followers
|
||||
test('[show] followers-mentionを自分が見れる', async () => {
|
||||
const res = await show(folM.id, alice);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] followers-mentionをメンションされていれば非フォロワーでも見れる', async () => {
|
||||
const res = await show(folM.id, target);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] followers-mentionをフォロワーが見れる', async () => {
|
||||
const res = await show(folM.id, follower);
|
||||
assert.strictEqual(res.body.text, '@target x');
|
||||
});
|
||||
|
||||
test('[show] followers-mentionを非フォロワーが見れない', async () => {
|
||||
const res = await show(folM.id, other);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] followers-mentionを未認証が見れない', async () => {
|
||||
const res = await show(folM.id, null);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
// specified
|
||||
test('[show] specified-mentionを自分が見れる', async () => {
|
||||
const res = await show(speM.id, alice);
|
||||
assert.strictEqual(res.body.text, '@target2 x');
|
||||
});
|
||||
|
||||
test('[show] specified-mentionを指定ユーザーが見れる', async () => {
|
||||
const res = await show(speM.id, target);
|
||||
assert.strictEqual(res.body.text, '@target2 x');
|
||||
});
|
||||
|
||||
test('[show] specified-mentionをされた人が指定されてなかったら見れない', async () => {
|
||||
const res = await show(speM.id, target2);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-mentionをフォロワーが見れない', async () => {
|
||||
const res = await show(speM.id, follower);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-mentionを非フォロワーが見れない', async () => {
|
||||
const res = await show(speM.id, other);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
|
||||
test('[show] specified-mentionを未認証が見れない', async () => {
|
||||
const res = await show(speM.id, null);
|
||||
assert.strictEqual(res.body.isHidden, true);
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//#region HTL
|
||||
test('[HTL] public-post が 自分が見れる', async () => {
|
||||
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);
|
||||
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);
|
||||
assert.strictEqual(res.status, 200);
|
||||
const notes = res.body.filter((n: any) => n.id === fol.id);
|
||||
assert.strictEqual(notes[0].text, 'x');
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//#region RTL
|
||||
test('[replies] followers-reply が フォロワーから見れる', async () => {
|
||||
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);
|
||||
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);
|
||||
assert.strictEqual(res.status, 200);
|
||||
const notes = res.body.filter((n: any) => n.id === folR.id);
|
||||
assert.strictEqual(notes[0].text, 'x');
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//#region MTL
|
||||
test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => {
|
||||
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);
|
||||
assert.strictEqual(res.status, 200);
|
||||
const notes = res.body.filter((n: any) => n.id === folM.id);
|
||||
assert.strictEqual(notes[0].text, '@target x');
|
||||
});
|
||||
//#endregion
|
||||
});
|
||||
});
|
||||
|
83
packages/backend/test/e2e/api.ts
Normal file
83
packages/backend/test/e2e/api.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, startServer } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('API', () => {
|
||||
let p: INestApplicationContext;
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
let carol: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
carol = await signup({ username: 'carol' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
describe('General validation', () => {
|
||||
test('wrong type', async () => {
|
||||
const res = await api('/test', {
|
||||
required: true,
|
||||
string: 42,
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('missing require param', async () => {
|
||||
const res = await api('/test', {
|
||||
string: 'a',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('invalid misskey:id (empty string)', async () => {
|
||||
const res = await api('/test', {
|
||||
required: true,
|
||||
id: '',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('valid misskey:id', async () => {
|
||||
const res = await api('/test', {
|
||||
required: true,
|
||||
id: '8wvhjghbxu',
|
||||
});
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
|
||||
test('default value', async () => {
|
||||
const res = await api('/test', {
|
||||
required: true,
|
||||
string: 'a',
|
||||
});
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.body.default, 'hello');
|
||||
});
|
||||
|
||||
test('can set null even if it has default value', async () => {
|
||||
const res = await api('/test', {
|
||||
required: true,
|
||||
nullableDefault: null,
|
||||
});
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.body.nullableDefault, null);
|
||||
});
|
||||
|
||||
test('cannot set undefined if it has default value', async () => {
|
||||
const res = await api('/test', {
|
||||
required: true,
|
||||
nullableDefault: undefined,
|
||||
});
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.body.nullableDefault, 'hello');
|
||||
});
|
||||
});
|
||||
});
|
85
packages/backend/test/e2e/block.ts
Normal file
85
packages/backend/test/e2e/block.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, post, startServer } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('Block', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
// alice blocks bob
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
let carol: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
carol = await signup({ username: 'carol' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
test('Block作成', async () => {
|
||||
const res = await api('/blocking/create', {
|
||||
userId: bob.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
|
||||
test('ブロックされているユーザーをフォローできない', async () => {
|
||||
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');
|
||||
});
|
||||
|
||||
test('ブロックされているユーザーにリアクションできない', async () => {
|
||||
const note = await post(alice, { text: 'hello' });
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
test('ブロックされているユーザーに返信できない', async () => {
|
||||
const note = await post(alice, { text: 'hello' });
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
test('ブロックされているユーザーのノートをRenoteできない', async () => {
|
||||
const note = await post(alice, { text: 'hello' });
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
// TODO: ユーザーリストに入れられないテスト
|
||||
|
||||
// TODO: ユーザーリストから除外されるテスト
|
||||
|
||||
test('タイムライン(LTL)にブロックされているユーザーの投稿が含まれない', async () => {
|
||||
const aliceNote = await post(alice);
|
||||
const bobNote = await post(bob);
|
||||
const carolNote = await post(carol);
|
||||
|
||||
const res = await api('/notes/local-timeline', {}, bob);
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
797
packages/backend/test/e2e/endpoints.ts
Normal file
797
packages/backend/test/e2e/endpoints.ts
Normal file
|
@ -0,0 +1,797 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
// node-fetch only supports it's own Blob yet
|
||||
// https://github.com/node-fetch/node-fetch/pull/1664
|
||||
import { Blob } from 'node-fetch';
|
||||
import { startServer, signup, post, api, uploadFile } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('Endpoints', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
let carol: any;
|
||||
let dave: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
carol = await signup({ username: 'carol' });
|
||||
dave = await signup({ username: 'dave' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
describe('signup', () => {
|
||||
test('不正なユーザー名でアカウントが作成できない', async () => {
|
||||
const res = await api('signup', {
|
||||
username: 'test.',
|
||||
password: 'test',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('空のパスワードでアカウントが作成できない', async () => {
|
||||
const res = await api('signup', {
|
||||
username: 'test',
|
||||
password: '',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('正しくアカウントが作成できる', async () => {
|
||||
const me = {
|
||||
username: 'test1',
|
||||
password: 'test1',
|
||||
};
|
||||
|
||||
const res = await api('signup', me);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.username, me.username);
|
||||
});
|
||||
|
||||
test('同じユーザー名のアカウントは作成できない', async () => {
|
||||
const res = await api('signup', {
|
||||
username: 'test1',
|
||||
password: 'test1',
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('signin', () => {
|
||||
test('間違ったパスワードでサインインできない', async () => {
|
||||
const res = await api('signin', {
|
||||
username: 'test1',
|
||||
password: 'bar',
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 403);
|
||||
});
|
||||
|
||||
test('クエリをインジェクションできない', async () => {
|
||||
const res = await api('signin', {
|
||||
username: 'test1',
|
||||
password: {
|
||||
$gt: '',
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('正しい情報でサインインできる', async () => {
|
||||
const res = await api('signin', {
|
||||
username: 'test1',
|
||||
password: 'test1',
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('i/update', () => {
|
||||
test('アカウント設定を更新できる', async () => {
|
||||
const myName = '大室櫻子';
|
||||
const myLocation = '七森中';
|
||||
const myBirthday = '2000-09-07';
|
||||
|
||||
const res = await api('/i/update', {
|
||||
name: myName,
|
||||
location: myLocation,
|
||||
birthday: myBirthday,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.name, myName);
|
||||
assert.strictEqual(res.body.location, myLocation);
|
||||
assert.strictEqual(res.body.birthday, myBirthday);
|
||||
});
|
||||
|
||||
test('名前を空白にできる', async () => {
|
||||
const res = await api('/i/update', {
|
||||
name: ' ',
|
||||
}, alice);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.body.name, ' ');
|
||||
});
|
||||
|
||||
test('誕生日の設定を削除できる', async () => {
|
||||
await api('/i/update', {
|
||||
birthday: '2000-09-07',
|
||||
}, alice);
|
||||
|
||||
const res = await api('/i/update', {
|
||||
birthday: null,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.birthday, null);
|
||||
});
|
||||
|
||||
test('不正な誕生日の形式で怒られる', async () => {
|
||||
const res = await api('/i/update', {
|
||||
birthday: '2000/09/07',
|
||||
}, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('users/show', () => {
|
||||
test('ユーザーが取得できる', async () => {
|
||||
const res = await api('/users/show', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.id, alice.id);
|
||||
});
|
||||
|
||||
test('ユーザーが存在しなかったら怒る', async () => {
|
||||
const res = await api('/users/show', {
|
||||
userId: '000000000000000000000000',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('間違ったIDで怒られる', async () => {
|
||||
const res = await api('/users/show', {
|
||||
userId: 'kyoppie',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notes/show', () => {
|
||||
test('投稿が取得できる', async () => {
|
||||
const myPost = await post(alice, {
|
||||
text: 'test',
|
||||
});
|
||||
|
||||
const res = await api('/notes/show', {
|
||||
noteId: myPost.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.id, myPost.id);
|
||||
assert.strictEqual(res.body.text, myPost.text);
|
||||
});
|
||||
|
||||
test('投稿が存在しなかったら怒る', async () => {
|
||||
const res = await api('/notes/show', {
|
||||
noteId: '000000000000000000000000',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('間違ったIDで怒られる', async () => {
|
||||
const res = await api('/notes/show', {
|
||||
noteId: 'kyoppie',
|
||||
});
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notes/reactions/create', () => {
|
||||
test('リアクションできる', async () => {
|
||||
const bobPost = await post(bob);
|
||||
|
||||
const res = await api('/notes/reactions/create', {
|
||||
noteId: bobPost.id,
|
||||
reaction: '🚀',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 204);
|
||||
|
||||
const resNote = await api('/notes/show', {
|
||||
noteId: bobPost.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(resNote.status, 200);
|
||||
assert.strictEqual(resNote.body.reactions['🚀'], 1);
|
||||
});
|
||||
|
||||
test('自分の投稿にもリアクションできる', async () => {
|
||||
const myPost = await post(alice);
|
||||
|
||||
const res = await api('/notes/reactions/create', {
|
||||
noteId: myPost.id,
|
||||
reaction: '🚀',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 204);
|
||||
});
|
||||
|
||||
test('二重にリアクションすると上書きされる', async () => {
|
||||
const bobPost = await post(bob);
|
||||
|
||||
await api('/notes/reactions/create', {
|
||||
noteId: bobPost.id,
|
||||
reaction: '🥰',
|
||||
}, alice);
|
||||
|
||||
const res = await api('/notes/reactions/create', {
|
||||
noteId: bobPost.id,
|
||||
reaction: '🚀',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 204);
|
||||
|
||||
const resNote = await api('/notes/show', {
|
||||
noteId: bobPost.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(resNote.status, 200);
|
||||
assert.deepStrictEqual(resNote.body.reactions, { '🚀': 1 });
|
||||
});
|
||||
|
||||
test('存在しない投稿にはリアクションできない', async () => {
|
||||
const res = await api('/notes/reactions/create', {
|
||||
noteId: '000000000000000000000000',
|
||||
reaction: '🚀',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('空のパラメータで怒られる', async () => {
|
||||
const res = await api('/notes/reactions/create', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('間違ったIDで怒られる', async () => {
|
||||
const res = await api('/notes/reactions/create', {
|
||||
noteId: 'kyoppie',
|
||||
reaction: '🚀',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('following/create', () => {
|
||||
test('フォローできる', async () => {
|
||||
const res = await api('/following/create', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
|
||||
test('既にフォローしている場合は怒る', async () => {
|
||||
const res = await api('/following/create', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないユーザーはフォローできない', async () => {
|
||||
const res = await api('/following/create', {
|
||||
userId: '000000000000000000000000',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('自分自身はフォローできない', async () => {
|
||||
const res = await api('/following/create', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('空のパラメータで怒られる', async () => {
|
||||
const res = await api('/following/create', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('間違ったIDで怒られる', async () => {
|
||||
const res = await api('/following/create', {
|
||||
userId: 'foo',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('following/delete', () => {
|
||||
test('フォロー解除できる', async () => {
|
||||
await api('/following/create', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
const res = await api('/following/delete', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
|
||||
test('フォローしていない場合は怒る', async () => {
|
||||
const res = await api('/following/delete', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないユーザーはフォロー解除できない', async () => {
|
||||
const res = await api('/following/delete', {
|
||||
userId: '000000000000000000000000',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('自分自身はフォロー解除できない', async () => {
|
||||
const res = await api('/following/delete', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('空のパラメータで怒られる', async () => {
|
||||
const res = await api('/following/delete', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('間違ったIDで怒られる', async () => {
|
||||
const res = await api('/following/delete', {
|
||||
userId: 'kyoppie',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('drive', () => {
|
||||
test('ドライブ情報を取得できる', async () => {
|
||||
await uploadFile(alice, {
|
||||
blob: new Blob([new Uint8Array(256)]),
|
||||
});
|
||||
await uploadFile(alice, {
|
||||
blob: new Blob([new Uint8Array(512)]),
|
||||
});
|
||||
await uploadFile(alice, {
|
||||
blob: new Blob([new Uint8Array(1024)]),
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
describe('drive/files/create', () => {
|
||||
test('ファイルを作成できる', async () => {
|
||||
const res = await uploadFile(alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.name, 'Lenna.jpg');
|
||||
});
|
||||
|
||||
test('ファイルに名前を付けられる', async () => {
|
||||
const res = await uploadFile(alice, { name: 'Belmond.png' });
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.name, 'Belmond.png');
|
||||
});
|
||||
|
||||
test('ファイル無しで怒られる', async () => {
|
||||
const res = await api('/drive/files/create', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('SVGファイルを作成できる', async () => {
|
||||
const res = await uploadFile(alice, { path: 'image.svg' });
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
describe('drive/files/update', () => {
|
||||
test('名前を更新できる', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
const newName = 'いちごパスタ.png';
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
name: newName,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.name, newName);
|
||||
});
|
||||
|
||||
test('他人のファイルは更新できない', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
name: 'いちごパスタ.png',
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('親フォルダを更新できる', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: folder.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.folderId, folder.id);
|
||||
});
|
||||
|
||||
test('親フォルダを無しにできる', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
|
||||
await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: folder.id,
|
||||
}, alice);
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: null,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.folderId, null);
|
||||
});
|
||||
|
||||
test('他人のフォルダには入れられない', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, bob)).body;
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: folder.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないフォルダで怒られる', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: '000000000000000000000000',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('不正なフォルダIDで怒られる', async () => {
|
||||
const file = (await uploadFile(alice)).body;
|
||||
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: file.id,
|
||||
folderId: 'foo',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('ファイルが存在しなかったら怒る', async () => {
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: '000000000000000000000000',
|
||||
name: 'いちごパスタ.png',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('間違ったIDで怒られる', async () => {
|
||||
const res = await api('/drive/files/update', {
|
||||
fileId: 'kyoppie',
|
||||
name: 'いちごパスタ.png',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('drive/folders/create', () => {
|
||||
test('フォルダを作成できる', async () => {
|
||||
const res = await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.name, 'test');
|
||||
});
|
||||
});
|
||||
|
||||
describe('drive/folders/update', () => {
|
||||
test('名前を更新できる', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
name: 'new name',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.name, 'new name');
|
||||
});
|
||||
|
||||
test('他人のフォルダを更新できない', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, bob)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
name: 'new name',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('親フォルダを更新できる', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
const parentFolder = (await api('/drive/folders/create', {
|
||||
name: 'parent',
|
||||
}, alice)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: parentFolder.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.parentId, parentFolder.id);
|
||||
});
|
||||
|
||||
test('親フォルダを無しに更新できる', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
const parentFolder = (await api('/drive/folders/create', {
|
||||
name: 'parent',
|
||||
}, alice)).body;
|
||||
await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: parentFolder.id,
|
||||
}, alice);
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: null,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.parentId, null);
|
||||
});
|
||||
|
||||
test('他人のフォルダを親フォルダに設定できない', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
const parentFolder = (await api('/drive/folders/create', {
|
||||
name: 'parent',
|
||||
}, bob)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: parentFolder.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('フォルダが循環するような構造にできない', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
const parentFolder = (await api('/drive/folders/create', {
|
||||
name: 'parent',
|
||||
}, alice)).body;
|
||||
await api('/drive/folders/update', {
|
||||
folderId: parentFolder.id,
|
||||
parentId: folder.id,
|
||||
}, alice);
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: parentFolder.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('フォルダが循環するような構造にできない(再帰的)', async () => {
|
||||
const folderA = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
const folderB = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
const folderC = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
await api('/drive/folders/update', {
|
||||
folderId: folderB.id,
|
||||
parentId: folderA.id,
|
||||
}, alice);
|
||||
await api('/drive/folders/update', {
|
||||
folderId: folderC.id,
|
||||
parentId: folderB.id,
|
||||
}, alice);
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folderA.id,
|
||||
parentId: folderC.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('フォルダが循環するような構造にできない(自身)', async () => {
|
||||
const folderA = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folderA.id,
|
||||
parentId: folderA.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しない親フォルダを設定できない', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: '000000000000000000000000',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('不正な親フォルダIDで怒られる', async () => {
|
||||
const folder = (await api('/drive/folders/create', {
|
||||
name: 'test',
|
||||
}, alice)).body;
|
||||
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: folder.id,
|
||||
parentId: 'foo',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないフォルダを更新できない', async () => {
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: '000000000000000000000000',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('不正なフォルダIDで怒られる', async () => {
|
||||
const res = await api('/drive/folders/update', {
|
||||
folderId: 'foo',
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notes/replies', () => {
|
||||
test('自分に閲覧権限のない投稿は含まれない', async () => {
|
||||
const alicePost = await post(alice, {
|
||||
text: 'foo',
|
||||
});
|
||||
|
||||
await post(bob, {
|
||||
replyId: alicePost.id,
|
||||
text: 'bar',
|
||||
visibility: 'specified',
|
||||
visibleUserIds: [alice.id],
|
||||
});
|
||||
|
||||
const res = await api('/notes/replies', {
|
||||
noteId: alicePost.id,
|
||||
}, carol);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notes/timeline', () => {
|
||||
test('フォロワー限定投稿が含まれる', async () => {
|
||||
await api('/following/create', {
|
||||
userId: carol.id,
|
||||
}, dave);
|
||||
|
||||
const carolPost = await post(carol, {
|
||||
text: 'foo',
|
||||
visibility: 'followers',
|
||||
});
|
||||
|
||||
const res = await api('/notes/timeline', {}, dave);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.length, 1);
|
||||
assert.strictEqual(res.body[0].id, carolPost.id);
|
||||
});
|
||||
});
|
||||
});
|
193
packages/backend/test/e2e/fetch-resource.ts
Normal file
193
packages/backend/test/e2e/fetch-resource.ts
Normal file
|
@ -0,0 +1,193 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { startServer, signup, post, api, simpleGet } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
// Request Accept
|
||||
const ONLY_AP = 'application/activity+json';
|
||||
const PREFER_AP = 'application/activity+json, */*';
|
||||
const PREFER_HTML = 'text/html, */*';
|
||||
const UNSPECIFIED = '*/*';
|
||||
|
||||
// Response Content-Type
|
||||
const AP = 'application/activity+json; charset=utf-8';
|
||||
const HTML = 'text/html; charset=utf-8';
|
||||
|
||||
describe('Fetch resource', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
let alice: any;
|
||||
let alicesPost: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
alicesPost = await post(alice, {
|
||||
text: 'test',
|
||||
});
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
describe('Common', () => {
|
||||
test('meta', async () => {
|
||||
const res = await api('/meta', {
|
||||
});
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
|
||||
test('GET root', async () => {
|
||||
const res = await simpleGet('/');
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, HTML);
|
||||
});
|
||||
|
||||
test('GET docs', async () => {
|
||||
const res = await simpleGet('/docs/ja-JP/about');
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, HTML);
|
||||
});
|
||||
|
||||
test('GET api-doc (廃止)', async () => {
|
||||
const res = await simpleGet('/api-doc');
|
||||
assert.strictEqual(res.status, 404);
|
||||
});
|
||||
|
||||
test('GET api.json (廃止)', async () => {
|
||||
const res = await simpleGet('/api.json');
|
||||
assert.strictEqual(res.status, 404);
|
||||
});
|
||||
|
||||
test('GET api/foo (存在しない)', async () => {
|
||||
const res = await simpleGet('/api/foo');
|
||||
assert.strictEqual(res.status, 404);
|
||||
assert.strictEqual(res.body.error.code, 'UNKNOWN_API_ENDPOINT');
|
||||
});
|
||||
|
||||
test('GET favicon.ico', async () => {
|
||||
const res = await simpleGet('/favicon.ico');
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'image/vnd.microsoft.icon');
|
||||
});
|
||||
|
||||
test('GET apple-touch-icon.png', async () => {
|
||||
const res = await simpleGet('/apple-touch-icon.png');
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'image/png');
|
||||
});
|
||||
|
||||
test('GET twemoji svg', async () => {
|
||||
const res = await simpleGet('/twemoji/2764.svg');
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'image/svg+xml');
|
||||
});
|
||||
|
||||
test('GET twemoji svg with hyphen', async () => {
|
||||
const res = await simpleGet('/twemoji/2764-fe0f-200d-1f525.svg');
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'image/svg+xml');
|
||||
});
|
||||
});
|
||||
|
||||
describe('/@:username', () => {
|
||||
test('Only AP => AP', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}`, ONLY_AP);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, AP);
|
||||
});
|
||||
|
||||
test('Prefer AP => AP', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}`, PREFER_AP);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, AP);
|
||||
});
|
||||
|
||||
test('Prefer HTML => HTML', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}`, PREFER_HTML);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, HTML);
|
||||
});
|
||||
|
||||
test('Unspecified => HTML', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}`, UNSPECIFIED);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, HTML);
|
||||
});
|
||||
});
|
||||
|
||||
describe('/users/:id', () => {
|
||||
test('Only AP => AP', async () => {
|
||||
const res = await simpleGet(`/users/${alice.id}`, ONLY_AP);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, AP);
|
||||
});
|
||||
|
||||
test('Prefer AP => AP', async () => {
|
||||
const res = await simpleGet(`/users/${alice.id}`, PREFER_AP);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, AP);
|
||||
});
|
||||
|
||||
test('Prefer HTML => Redirect to /@:username', async () => {
|
||||
const res = await simpleGet(`/users/${alice.id}`, PREFER_HTML);
|
||||
assert.strictEqual(res.status, 302);
|
||||
assert.strictEqual(res.location, `/@${alice.username}`);
|
||||
});
|
||||
|
||||
test('Undecided => HTML', async () => {
|
||||
const res = await simpleGet(`/users/${alice.id}`, UNSPECIFIED);
|
||||
assert.strictEqual(res.status, 302);
|
||||
assert.strictEqual(res.location, `/@${alice.username}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('/notes/:id', () => {
|
||||
test('Only AP => AP', async () => {
|
||||
const res = await simpleGet(`/notes/${alicesPost.id}`, ONLY_AP);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, AP);
|
||||
});
|
||||
|
||||
test('Prefer AP => AP', async () => {
|
||||
const res = await simpleGet(`/notes/${alicesPost.id}`, PREFER_AP);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, AP);
|
||||
});
|
||||
|
||||
test('Prefer HTML => HTML', async () => {
|
||||
const res = await simpleGet(`/notes/${alicesPost.id}`, PREFER_HTML);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, HTML);
|
||||
});
|
||||
|
||||
test('Unspecified => HTML', async () => {
|
||||
const res = await simpleGet(`/notes/${alicesPost.id}`, UNSPECIFIED);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, HTML);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Feeds', () => {
|
||||
test('RSS', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}.rss`, UNSPECIFIED);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'application/rss+xml; charset=utf-8');
|
||||
});
|
||||
|
||||
test('ATOM', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}.atom`, UNSPECIFIED);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'application/atom+xml; charset=utf-8');
|
||||
});
|
||||
|
||||
test('JSON', async () => {
|
||||
const res = await simpleGet(`/@${alice.username}.json`, UNSPECIFIED);
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.type, 'application/json; charset=utf-8');
|
||||
});
|
||||
});
|
||||
});
|
165
packages/backend/test/e2e/ff-visibility.ts
Normal file
165
packages/backend/test/e2e/ff-visibility.ts
Normal file
|
@ -0,0 +1,165 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, startServer, simpleGet } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('FF visibility', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
test('ffVisibility が public なユーザーのフォロー/フォロワーを誰でも見れる', async () => {
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'public',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await api('/users/following', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
const followersRes = await api('/users/followers', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(followingRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||
assert.strictEqual(followersRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||
});
|
||||
|
||||
test('ffVisibility が followers なユーザーのフォロー/フォロワーを自分で見れる', async () => {
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'followers',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await api('/users/following', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
const followersRes = await api('/users/followers', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(followingRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||
assert.strictEqual(followersRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||
});
|
||||
|
||||
test('ffVisibility が followers なユーザーのフォロー/フォロワーを非フォロワーが見れない', async () => {
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'followers',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await api('/users/following', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
const followersRes = await api('/users/followers', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(followingRes.status, 400);
|
||||
assert.strictEqual(followersRes.status, 400);
|
||||
});
|
||||
|
||||
test('ffVisibility が followers なユーザーのフォロー/フォロワーをフォロワーが見れる', async () => {
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'followers',
|
||||
}, alice);
|
||||
|
||||
await api('/following/create', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
const followingRes = await api('/users/following', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
const followersRes = await api('/users/followers', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(followingRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||
assert.strictEqual(followersRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||
});
|
||||
|
||||
test('ffVisibility が private なユーザーのフォロー/フォロワーを自分で見れる', async () => {
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'private',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await api('/users/following', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
const followersRes = await api('/users/followers', {
|
||||
userId: alice.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(followingRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followingRes.body), true);
|
||||
assert.strictEqual(followersRes.status, 200);
|
||||
assert.strictEqual(Array.isArray(followersRes.body), true);
|
||||
});
|
||||
|
||||
test('ffVisibility が private なユーザーのフォロー/フォロワーを他人が見れない', async () => {
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'private',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await api('/users/following', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
const followersRes = await api('/users/followers', {
|
||||
userId: alice.id,
|
||||
}, bob);
|
||||
|
||||
assert.strictEqual(followingRes.status, 400);
|
||||
assert.strictEqual(followersRes.status, 400);
|
||||
});
|
||||
|
||||
describe('AP', () => {
|
||||
test('ffVisibility が public 以外ならばAPからは取得できない', async () => {
|
||||
{
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'public',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json');
|
||||
const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
|
||||
assert.strictEqual(followingRes.status, 200);
|
||||
assert.strictEqual(followersRes.status, 200);
|
||||
}
|
||||
{
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'followers',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json');
|
||||
const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
|
||||
assert.strictEqual(followingRes.status, 403);
|
||||
assert.strictEqual(followersRes.status, 403);
|
||||
}
|
||||
{
|
||||
await api('/i/update', {
|
||||
ffVisibility: 'private',
|
||||
}, alice);
|
||||
|
||||
const followingRes = await simpleGet(`/users/${alice.id}/following`, 'application/activity+json');
|
||||
const followersRes = await simpleGet(`/users/${alice.id}/followers`, 'application/activity+json');
|
||||
assert.strictEqual(followingRes.status, 403);
|
||||
assert.strictEqual(followersRes.status, 403);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
123
packages/backend/test/e2e/mute.ts
Normal file
123
packages/backend/test/e2e/mute.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, post, react, startServer, waitFire } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('Mute', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
// alice mutes carol
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
let carol: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
carol = await signup({ username: 'carol' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
test('ミュート作成', async () => {
|
||||
const res = await api('/mute/create', {
|
||||
userId: carol.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 204);
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
|
||||
});
|
||||
|
||||
test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => {
|
||||
// 状態リセット
|
||||
await api('/i/read-all-unread-notes', {}, alice);
|
||||
|
||||
await post(carol, { text: '@alice hi' });
|
||||
|
||||
const res = await api('/i', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.body.hasUnreadMentions, false);
|
||||
});
|
||||
|
||||
test('ミュートしているユーザーからメンションされても、ストリームに unreadMention イベントが流れてこない', async () => {
|
||||
// 状態リセット
|
||||
await api('/i/read-all-unread-notes', {}, alice);
|
||||
|
||||
const fired = await waitFire(alice, 'main', () => post(carol, { text: '@alice hi' }), msg => msg.type === 'unreadMention');
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('ミュートしているユーザーからメンションされても、ストリームに unreadNotification イベントが流れてこない', async () => {
|
||||
// 状態リセット
|
||||
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');
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
describe('Timeline', () => {
|
||||
test('タイムラインにミュートしているユーザーの投稿が含まれない', async () => {
|
||||
const aliceNote = await post(alice);
|
||||
const bobNote = await post(bob);
|
||||
const carolNote = await post(carol);
|
||||
|
||||
const res = await api('/notes/local-timeline', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
|
||||
});
|
||||
|
||||
test('タイムラインにミュートしているユーザーの投稿のRenoteが含まれない', async () => {
|
||||
const aliceNote = await post(alice);
|
||||
const carolNote = await post(carol);
|
||||
const bobNote = await post(bob, {
|
||||
renoteId: carolNote.id,
|
||||
});
|
||||
|
||||
const res = await api('/notes/local-timeline', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Notification', () => {
|
||||
test('通知にミュートしているユーザーの通知が含まれない(リアクション)', async () => {
|
||||
const aliceNote = await post(alice);
|
||||
await react(bob, aliceNote, 'like');
|
||||
await react(carol, aliceNote, 'like');
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
370
packages/backend/test/e2e/note.ts
Normal file
370
packages/backend/test/e2e/note.ts
Normal file
|
@ -0,0 +1,370 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Note } from '@/models/entities/Note.js';
|
||||
import { signup, post, uploadUrl, startServer, initTestDb, api } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('Note', () => {
|
||||
let p: INestApplicationContext;
|
||||
let Notes: any;
|
||||
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
const connection = await initTestDb(true);
|
||||
Notes = connection.getRepository(Note);
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
test('投稿できる', async () => {
|
||||
const post = {
|
||||
text: 'test',
|
||||
};
|
||||
|
||||
const res = await api('/notes/create', post, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.text, post.text);
|
||||
});
|
||||
|
||||
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', {
|
||||
fileIds: [file.id],
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.deepStrictEqual(res.body.createdNote.fileIds, [file.id]);
|
||||
}, 1000 * 10);
|
||||
|
||||
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', {
|
||||
text: 'test',
|
||||
fileIds: [file.id],
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE');
|
||||
assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
|
||||
}, 1000 * 10);
|
||||
|
||||
test('存在しないファイルで怒られる', async () => {
|
||||
const res = await api('/notes/create', {
|
||||
text: 'test',
|
||||
fileIds: ['000000000000000000000000'],
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE');
|
||||
assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
|
||||
});
|
||||
|
||||
test('不正なファイルIDで怒られる', async () => {
|
||||
const res = await api('/notes/create', {
|
||||
fileIds: ['kyoppie'],
|
||||
}, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE');
|
||||
assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306');
|
||||
});
|
||||
|
||||
test('返信できる', async () => {
|
||||
const bobPost = await post(bob, {
|
||||
text: 'foo',
|
||||
});
|
||||
|
||||
const alicePost = {
|
||||
text: 'bar',
|
||||
replyId: bobPost.id,
|
||||
};
|
||||
|
||||
const res = await api('/notes/create', alicePost, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.text, alicePost.text);
|
||||
assert.strictEqual(res.body.createdNote.replyId, alicePost.replyId);
|
||||
assert.strictEqual(res.body.createdNote.reply.text, bobPost.text);
|
||||
});
|
||||
|
||||
test('renoteできる', async () => {
|
||||
const bobPost = await post(bob, {
|
||||
text: 'test',
|
||||
});
|
||||
|
||||
const alicePost = {
|
||||
renoteId: bobPost.id,
|
||||
};
|
||||
|
||||
const res = await api('/notes/create', alicePost, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.renoteId, alicePost.renoteId);
|
||||
assert.strictEqual(res.body.createdNote.renote.text, bobPost.text);
|
||||
});
|
||||
|
||||
test('引用renoteできる', async () => {
|
||||
const bobPost = await post(bob, {
|
||||
text: 'test',
|
||||
});
|
||||
|
||||
const alicePost = {
|
||||
text: 'test',
|
||||
renoteId: bobPost.id,
|
||||
};
|
||||
|
||||
const res = await api('/notes/create', alicePost, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.text, alicePost.text);
|
||||
assert.strictEqual(res.body.createdNote.renoteId, alicePost.renoteId);
|
||||
assert.strictEqual(res.body.createdNote.renote.text, bobPost.text);
|
||||
});
|
||||
|
||||
test('文字数ぎりぎりで怒られない', async () => {
|
||||
const post = {
|
||||
text: '!'.repeat(3000),
|
||||
};
|
||||
const res = await api('/notes/create', post, alice);
|
||||
assert.strictEqual(res.status, 200);
|
||||
});
|
||||
|
||||
test('文字数オーバーで怒られる', async () => {
|
||||
const post = {
|
||||
text: '!'.repeat(3001),
|
||||
};
|
||||
const res = await api('/notes/create', post, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないリプライ先で怒られる', async () => {
|
||||
const post = {
|
||||
text: 'test',
|
||||
replyId: '000000000000000000000000',
|
||||
};
|
||||
const res = await api('/notes/create', post, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないrenote対象で怒られる', async () => {
|
||||
const post = {
|
||||
renoteId: '000000000000000000000000',
|
||||
};
|
||||
const res = await api('/notes/create', post, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('不正なリプライ先IDで怒られる', async () => {
|
||||
const post = {
|
||||
text: 'test',
|
||||
replyId: 'foo',
|
||||
};
|
||||
const res = await api('/notes/create', post, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('不正なrenote対象IDで怒られる', async () => {
|
||||
const post = {
|
||||
renoteId: 'foo',
|
||||
};
|
||||
const res = await api('/notes/create', post, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('存在しないユーザーにメンションできる', async () => {
|
||||
const post = {
|
||||
text: '@ghost yo',
|
||||
};
|
||||
|
||||
const res = await api('/notes/create', post, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.text, post.text);
|
||||
});
|
||||
|
||||
test('同じユーザーに複数メンションしても内部的にまとめられる', async () => {
|
||||
const post = {
|
||||
text: '@bob @bob @bob yo',
|
||||
};
|
||||
|
||||
const res = await api('/notes/create', post, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.text, post.text);
|
||||
|
||||
const noteDoc = await Notes.findOneBy({ id: res.body.createdNote.id });
|
||||
assert.deepStrictEqual(noteDoc.mentions, [bob.id]);
|
||||
});
|
||||
|
||||
describe('notes/create', () => {
|
||||
test('投票を添付できる', async () => {
|
||||
const res = await api('/notes/create', {
|
||||
text: 'test',
|
||||
poll: {
|
||||
choices: ['foo', 'bar'],
|
||||
},
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.createdNote.poll != null, true);
|
||||
});
|
||||
|
||||
test('投票の選択肢が無くて怒られる', async () => {
|
||||
const res = await api('/notes/create', {
|
||||
poll: {},
|
||||
}, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('投票の選択肢が無くて怒られる (空の配列)', async () => {
|
||||
const res = await api('/notes/create', {
|
||||
poll: {
|
||||
choices: [],
|
||||
},
|
||||
}, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('投票の選択肢が1つで怒られる', async () => {
|
||||
const res = await api('/notes/create', {
|
||||
poll: {
|
||||
choices: ['Strawberry Pasta'],
|
||||
},
|
||||
}, alice);
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('投票できる', async () => {
|
||||
const { body } = await api('/notes/create', {
|
||||
text: 'test',
|
||||
poll: {
|
||||
choices: ['sakura', 'izumi', 'ako'],
|
||||
},
|
||||
}, alice);
|
||||
|
||||
const res = await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 1,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 204);
|
||||
});
|
||||
|
||||
test('複数投票できない', async () => {
|
||||
const { body } = await api('/notes/create', {
|
||||
text: 'test',
|
||||
poll: {
|
||||
choices: ['sakura', 'izumi', 'ako'],
|
||||
},
|
||||
}, alice);
|
||||
|
||||
await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 0,
|
||||
}, alice);
|
||||
|
||||
const res = await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 2,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
|
||||
test('許可されている場合は複数投票できる', async () => {
|
||||
const { body } = await api('/notes/create', {
|
||||
text: 'test',
|
||||
poll: {
|
||||
choices: ['sakura', 'izumi', 'ako'],
|
||||
multiple: true,
|
||||
},
|
||||
}, alice);
|
||||
|
||||
await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 0,
|
||||
}, alice);
|
||||
|
||||
await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 1,
|
||||
}, alice);
|
||||
|
||||
const res = await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 2,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 204);
|
||||
});
|
||||
|
||||
test('締め切られている場合は投票できない', async () => {
|
||||
const { body } = await api('/notes/create', {
|
||||
text: 'test',
|
||||
poll: {
|
||||
choices: ['sakura', 'izumi', 'ako'],
|
||||
expiredAfter: 1,
|
||||
},
|
||||
}, alice);
|
||||
|
||||
await new Promise(x => setTimeout(x, 2));
|
||||
|
||||
const res = await api('/notes/polls/vote', {
|
||||
noteId: body.createdNote.id,
|
||||
choice: 1,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 400);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notes/delete', () => {
|
||||
test('delete a reply', async () => {
|
||||
const mainNoteRes = await api('notes/create', {
|
||||
text: 'main post',
|
||||
}, alice);
|
||||
const replyOneRes = await api('notes/create', {
|
||||
text: 'reply one',
|
||||
replyId: mainNoteRes.body.createdNote.id,
|
||||
}, alice);
|
||||
const replyTwoRes = await api('notes/create', {
|
||||
text: 'reply two',
|
||||
replyId: mainNoteRes.body.createdNote.id,
|
||||
}, alice);
|
||||
|
||||
const deleteOneRes = await api('notes/delete', {
|
||||
noteId: replyOneRes.body.createdNote.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(deleteOneRes.status, 204);
|
||||
let mainNote = await Notes.findOneBy({ id: mainNoteRes.body.createdNote.id });
|
||||
assert.strictEqual(mainNote.repliesCount, 1);
|
||||
|
||||
const deleteTwoRes = await api('notes/delete', {
|
||||
noteId: replyTwoRes.body.createdNote.id,
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(deleteTwoRes.status, 204);
|
||||
mainNote = await Notes.findOneBy({ id: mainNoteRes.body.createdNote.id });
|
||||
assert.strictEqual(mainNote.repliesCount, 0);
|
||||
});
|
||||
});
|
||||
});
|
547
packages/backend/test/e2e/streaming.ts
Normal file
547
packages/backend/test/e2e/streaming.ts
Normal file
|
@ -0,0 +1,547 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Following } from '@/models/entities/Following.js';
|
||||
import { connectStream, signup, api, post, startServer, initTestDb, waitFire } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('Streaming', () => {
|
||||
let p: INestApplicationContext;
|
||||
let Followings: any;
|
||||
|
||||
const follow = async (follower: any, followee: any) => {
|
||||
await Followings.save({
|
||||
id: 'a',
|
||||
createdAt: new Date(),
|
||||
followerId: follower.id,
|
||||
followeeId: followee.id,
|
||||
followerHost: follower.host,
|
||||
followerInbox: null,
|
||||
followerSharedInbox: null,
|
||||
followeeHost: followee.host,
|
||||
followeeInbox: null,
|
||||
followeeSharedInbox: null,
|
||||
});
|
||||
};
|
||||
|
||||
describe('Streaming', () => {
|
||||
// Local users
|
||||
let ayano: any;
|
||||
let kyoko: any;
|
||||
let chitose: any;
|
||||
|
||||
// Remote users
|
||||
let akari: any;
|
||||
let chinatsu: any;
|
||||
|
||||
let kyokoNote: any;
|
||||
let list: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
const connection = await initTestDb(true);
|
||||
Followings = connection.getRepository(Following);
|
||||
|
||||
ayano = await signup({ username: 'ayano' });
|
||||
kyoko = await signup({ username: 'kyoko' });
|
||||
chitose = await signup({ username: 'chitose' });
|
||||
|
||||
akari = await signup({ username: 'akari', host: 'example.com' });
|
||||
chinatsu = await signup({ username: 'chinatsu', host: 'example.com' });
|
||||
|
||||
kyokoNote = await post(kyoko, { text: 'foo' });
|
||||
|
||||
// Follow: ayano => kyoko
|
||||
await api('following/create', { userId: kyoko.id }, ayano);
|
||||
|
||||
// Follow: ayano => akari
|
||||
await follow(ayano, akari);
|
||||
|
||||
// List: chitose => ayano, kyoko
|
||||
list = await api('users/lists/create', {
|
||||
name: 'my list',
|
||||
}, chitose).then(x => x.body);
|
||||
|
||||
await api('users/lists/push', {
|
||||
listId: list.id,
|
||||
userId: ayano.id,
|
||||
}, chitose);
|
||||
|
||||
await api('users/lists/push', {
|
||||
listId: list.id,
|
||||
userId: kyoko.id,
|
||||
}, chitose);
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
describe('Events', () => {
|
||||
test('mention event', async () => {
|
||||
const fired = await waitFire(
|
||||
kyoko, 'main', // kyoko:main
|
||||
() => post(ayano, { text: 'foo @kyoko bar' }), // ayano mention => kyoko
|
||||
msg => msg.type === 'mention' && msg.body.userId === ayano.id, // wait ayano
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('renote event', async () => {
|
||||
const fired = await waitFire(
|
||||
kyoko, 'main', // kyoko:main
|
||||
() => post(ayano, { renoteId: kyokoNote.id }), // ayano renote
|
||||
msg => msg.type === 'renote' && msg.body.renoteId === kyokoNote.id, // wait renote
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Home Timeline', () => {
|
||||
test('自分の投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'homeTimeline', // ayano:Home
|
||||
() => api('notes/create', { text: 'foo' }, ayano), // ayano posts
|
||||
msg => msg.type === 'note' && msg.body.text === 'foo',
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしているユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'homeTimeline', // ayano:home
|
||||
() => api('notes/create', { text: 'foo' }, kyoko), // kyoko posts
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしていないユーザーの投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
kyoko, 'homeTimeline', // kyoko:home
|
||||
() => api('notes/create', { text: 'foo' }, ayano), // ayano posts
|
||||
msg => msg.type === 'note' && msg.body.userId === ayano.id, // wait ayano
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('フォローしているユーザーのダイレクト投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'homeTimeline', // ayano:home
|
||||
() => api('notes/create', { text: 'foo', visibility: 'specified', visibleUserIds: [ayano.id] }, kyoko), // kyoko dm => ayano
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしているユーザーでも自分が指定されていないダイレクト投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'homeTimeline', // ayano:home
|
||||
() => api('notes/create', { text: 'foo', visibility: 'specified', visibleUserIds: [chitose.id] }, kyoko), // kyoko dm => chitose
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
}); // Home
|
||||
|
||||
describe('Local Timeline', () => {
|
||||
test('自分の投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo' }, ayano), // ayano posts
|
||||
msg => msg.type === 'note' && msg.body.text === 'foo',
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしていないローカルユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo' }, chitose), // chitose posts
|
||||
msg => msg.type === 'note' && msg.body.userId === chitose.id, // wait chitose
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('リモートユーザーの投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo' }, chinatsu), // chinatsu posts
|
||||
msg => msg.type === 'note' && msg.body.userId === chinatsu.id, // wait chinatsu
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('フォローしてたとしてもリモートユーザーの投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo' }, akari), // akari posts
|
||||
msg => msg.type === 'note' && msg.body.userId === akari.id, // wait akari
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('ホーム指定の投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo', visibility: 'home' }, kyoko), // kyoko home posts
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('フォローしているローカルユーザーのダイレクト投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo', visibility: 'specified', visibleUserIds: [ayano.id] }, kyoko), // kyoko DM => ayano
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('フォローしていないローカルユーザーのフォロワー宛て投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'localTimeline', // ayano:Local
|
||||
() => api('notes/create', { text: 'foo', visibility: 'followers' }, chitose),
|
||||
msg => msg.type === 'note' && msg.body.userId === chitose.id, // wait chitose
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Hybrid Timeline', () => {
|
||||
test('自分の投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo' }, ayano), // ayano posts
|
||||
msg => msg.type === 'note' && msg.body.text === 'foo',
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしていないローカルユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo' }, chitose), // chitose posts
|
||||
msg => msg.type === 'note' && msg.body.userId === chitose.id, // wait chitose
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしているリモートユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo' }, akari), // akari posts
|
||||
msg => msg.type === 'note' && msg.body.userId === akari.id, // wait akari
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしていないリモートユーザーの投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo' }, chinatsu), // chinatsu posts
|
||||
msg => msg.type === 'note' && msg.body.userId === chinatsu.id, // wait chinatsu
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('フォローしているユーザーのダイレクト投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo', visibility: 'specified', visibleUserIds: [ayano.id] }, kyoko),
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしているユーザーのホーム投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo', visibility: 'home' }, kyoko),
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしていないローカルユーザーのホーム投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo', visibility: 'home' }, chitose),
|
||||
msg => msg.type === 'note' && msg.body.userId === chitose.id,
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
test('フォローしていないローカルユーザーのフォロワー宛て投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'hybridTimeline', // ayano:Hybrid
|
||||
() => api('notes/create', { text: 'foo', visibility: 'followers' }, chitose),
|
||||
msg => msg.type === 'note' && msg.body.userId === chitose.id,
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Global Timeline', () => {
|
||||
test('フォローしていないローカルユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'globalTimeline', // ayano:Global
|
||||
() => api('notes/create', { text: 'foo' }, chitose), // chitose posts
|
||||
msg => msg.type === 'note' && msg.body.userId === chitose.id, // wait chitose
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('フォローしていないリモートユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'globalTimeline', // ayano:Global
|
||||
() => api('notes/create', { text: 'foo' }, chinatsu), // chinatsu posts
|
||||
msg => msg.type === 'note' && msg.body.userId === chinatsu.id, // wait chinatsu
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('ホーム投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
ayano, 'globalTimeline', // ayano:Global
|
||||
() => api('notes/create', { text: 'foo', visibility: 'home' }, kyoko), // kyoko posts
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id, // wait kyoko
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserList Timeline', () => {
|
||||
test('リストに入れているユーザーの投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
chitose, 'userList',
|
||||
() => api('notes/create', { text: 'foo' }, ayano),
|
||||
msg => msg.type === 'note' && msg.body.userId === ayano.id,
|
||||
{ listId: list.id },
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
test('リストに入れていないユーザーの投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
chitose, 'userList',
|
||||
() => api('notes/create', { text: 'foo' }, chinatsu),
|
||||
msg => msg.type === 'note' && msg.body.userId === chinatsu.id,
|
||||
{ listId: list.id },
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
|
||||
// #4471
|
||||
test('リストに入れているユーザーのダイレクト投稿が流れる', async () => {
|
||||
const fired = await waitFire(
|
||||
chitose, 'userList',
|
||||
() => api('notes/create', { text: 'foo', visibility: 'specified', visibleUserIds: [chitose.id] }, ayano),
|
||||
msg => msg.type === 'note' && msg.body.userId === ayano.id,
|
||||
{ listId: list.id },
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, true);
|
||||
});
|
||||
|
||||
// #4335
|
||||
test('リストに入れているがフォローはしてないユーザーのフォロワー宛て投稿は流れない', async () => {
|
||||
const fired = await waitFire(
|
||||
chitose, 'userList',
|
||||
() => api('notes/create', { text: 'foo', visibility: 'followers' }, kyoko),
|
||||
msg => msg.type === 'note' && msg.body.userId === kyoko.id,
|
||||
{ listId: list.id },
|
||||
);
|
||||
|
||||
assert.strictEqual(fired, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Hashtag Timeline', () => {
|
||||
test('指定したハッシュタグの投稿が流れる', () => new Promise<void>(async done => {
|
||||
const ws = await connectStream(chitose, 'hashtag', ({ type, body }) => {
|
||||
if (type === 'note') {
|
||||
assert.deepStrictEqual(body.text, '#foo');
|
||||
ws.close();
|
||||
done();
|
||||
}
|
||||
}, {
|
||||
q: [
|
||||
['foo'],
|
||||
],
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#foo',
|
||||
});
|
||||
}));
|
||||
|
||||
// XXX: QueryFailedError: duplicate key value violates unique constraint "IDX_347fec870eafea7b26c8a73bac"
|
||||
|
||||
// test('指定したハッシュタグの投稿が流れる (AND)', () => new Promise<void>(async done => {
|
||||
// let fooCount = 0;
|
||||
// let barCount = 0;
|
||||
// let fooBarCount = 0;
|
||||
|
||||
// const ws = await connectStream(chitose, 'hashtag', ({ type, body }) => {
|
||||
// if (type === 'note') {
|
||||
// if (body.text === '#foo') fooCount++;
|
||||
// if (body.text === '#bar') barCount++;
|
||||
// if (body.text === '#foo #bar') fooBarCount++;
|
||||
// }
|
||||
// }, {
|
||||
// q: [
|
||||
// ['foo', 'bar'],
|
||||
// ],
|
||||
// });
|
||||
|
||||
// post(chitose, {
|
||||
// text: '#foo',
|
||||
// });
|
||||
|
||||
// post(chitose, {
|
||||
// text: '#bar',
|
||||
// });
|
||||
|
||||
// post(chitose, {
|
||||
// text: '#foo #bar',
|
||||
// });
|
||||
|
||||
// setTimeout(() => {
|
||||
// assert.strictEqual(fooCount, 0);
|
||||
// assert.strictEqual(barCount, 0);
|
||||
// assert.strictEqual(fooBarCount, 1);
|
||||
// ws.close();
|
||||
// done();
|
||||
// }, 3000);
|
||||
// }));
|
||||
|
||||
test('指定したハッシュタグの投稿が流れる (OR)', () => new Promise<void>(async done => {
|
||||
let fooCount = 0;
|
||||
let barCount = 0;
|
||||
let fooBarCount = 0;
|
||||
let piyoCount = 0;
|
||||
|
||||
const ws = await connectStream(chitose, 'hashtag', ({ type, body }) => {
|
||||
if (type === 'note') {
|
||||
if (body.text === '#foo') fooCount++;
|
||||
if (body.text === '#bar') barCount++;
|
||||
if (body.text === '#foo #bar') fooBarCount++;
|
||||
if (body.text === '#piyo') piyoCount++;
|
||||
}
|
||||
}, {
|
||||
q: [
|
||||
['foo'],
|
||||
['bar'],
|
||||
],
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#foo',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#bar',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#foo #bar',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#piyo',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
assert.strictEqual(fooCount, 1);
|
||||
assert.strictEqual(barCount, 1);
|
||||
assert.strictEqual(fooBarCount, 1);
|
||||
assert.strictEqual(piyoCount, 0);
|
||||
ws.close();
|
||||
done();
|
||||
}, 3000);
|
||||
}));
|
||||
|
||||
test('指定したハッシュタグの投稿が流れる (AND + OR)', () => new Promise<void>(async done => {
|
||||
let fooCount = 0;
|
||||
let barCount = 0;
|
||||
let fooBarCount = 0;
|
||||
let piyoCount = 0;
|
||||
let waaaCount = 0;
|
||||
|
||||
const ws = await connectStream(chitose, 'hashtag', ({ type, body }) => {
|
||||
if (type === 'note') {
|
||||
if (body.text === '#foo') fooCount++;
|
||||
if (body.text === '#bar') barCount++;
|
||||
if (body.text === '#foo #bar') fooBarCount++;
|
||||
if (body.text === '#piyo') piyoCount++;
|
||||
if (body.text === '#waaa') waaaCount++;
|
||||
}
|
||||
}, {
|
||||
q: [
|
||||
['foo', 'bar'],
|
||||
['piyo'],
|
||||
],
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#foo',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#bar',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#foo #bar',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#piyo',
|
||||
});
|
||||
|
||||
post(chitose, {
|
||||
text: '#waaa',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
assert.strictEqual(fooCount, 0);
|
||||
assert.strictEqual(barCount, 0);
|
||||
assert.strictEqual(fooBarCount, 1);
|
||||
assert.strictEqual(piyoCount, 1);
|
||||
assert.strictEqual(waaaCount, 0);
|
||||
ws.close();
|
||||
done();
|
||||
}, 3000);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
103
packages/backend/test/e2e/thread-mute.ts
Normal file
103
packages/backend/test/e2e/thread-mute.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, post, connectStream, startServer } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('Note thread mute', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
let alice: any;
|
||||
let bob: any;
|
||||
let carol: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
bob = await signup({ username: 'bob' });
|
||||
carol = await signup({ username: 'carol' });
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async () => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
test('notes/mentions にミュートしているスレッドの投稿が含まれない', async () => {
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === carolReply.id), false);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === carolReplyWithoutMention.id), false);
|
||||
});
|
||||
|
||||
test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => {
|
||||
// 状態リセット
|
||||
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);
|
||||
|
||||
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
||||
|
||||
const res = await api('/i', {}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.body.hasUnreadMentions, false);
|
||||
});
|
||||
|
||||
test('ミュートしているスレッドからメンションされても、ストリームに unreadMention イベントが流れてこない', () => new Promise<void>(async done => {
|
||||
// 状態リセット
|
||||
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);
|
||||
|
||||
let fired = false;
|
||||
|
||||
const ws = await connectStream(alice, 'main', async ({ type, body }) => {
|
||||
if (type === 'unreadMention') {
|
||||
if (body === bobNote.id) return;
|
||||
fired = true;
|
||||
}
|
||||
});
|
||||
|
||||
const carolReply = await post(carol, { replyId: bobNote.id, text: '@bob @alice child note' });
|
||||
|
||||
setTimeout(() => {
|
||||
assert.strictEqual(fired, false);
|
||||
ws.close();
|
||||
done();
|
||||
}, 5000);
|
||||
}));
|
||||
|
||||
test('i/notifications にミュートしているスレッドの通知が含まれない', async () => {
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.some((notification: any) => notification.note.id === carolReply.id), false);
|
||||
assert.strictEqual(res.body.some((notification: any) => notification.note.id === carolReplyWithoutMention.id), false);
|
||||
|
||||
// NOTE: bobの投稿はスレッドミュート前に行われたため通知に含まれていてもよい
|
||||
});
|
||||
});
|
61
packages/backend/test/e2e/user-notes.ts
Normal file
61
packages/backend/test/e2e/user-notes.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
process.env.NODE_ENV = 'test';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { signup, api, post, uploadUrl, startServer } from '../utils.js';
|
||||
import type { INestApplicationContext } from '@nestjs/common';
|
||||
|
||||
describe('users/notes', () => {
|
||||
let p: INestApplicationContext;
|
||||
|
||||
let alice: any;
|
||||
let jpgNote: any;
|
||||
let pngNote: any;
|
||||
let jpgPngNote: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
p = await startServer();
|
||||
alice = await signup({ username: 'alice' });
|
||||
const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');
|
||||
const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.png');
|
||||
jpgNote = await post(alice, {
|
||||
fileIds: [jpg.id],
|
||||
});
|
||||
pngNote = await post(alice, {
|
||||
fileIds: [png.id],
|
||||
});
|
||||
jpgPngNote = await post(alice, {
|
||||
fileIds: [jpg.id, png.id],
|
||||
});
|
||||
}, 1000 * 60 * 2);
|
||||
|
||||
afterAll(async() => {
|
||||
await p.close();
|
||||
});
|
||||
|
||||
test('ファイルタイプ指定 (jpg)', async () => {
|
||||
const res = await api('/users/notes', {
|
||||
userId: alice.id,
|
||||
fileType: ['image/jpeg'],
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.length, 2);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === jpgNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === jpgPngNote.id), true);
|
||||
});
|
||||
|
||||
test('ファイルタイプ指定 (jpg or png)', async () => {
|
||||
const res = await api('/users/notes', {
|
||||
userId: alice.id,
|
||||
fileType: ['image/jpeg', 'image/png'],
|
||||
}, alice);
|
||||
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(Array.isArray(res.body), true);
|
||||
assert.strictEqual(res.body.length, 3);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === jpgNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === pngNote.id), true);
|
||||
assert.strictEqual(res.body.some((note: any) => note.id === jpgPngNote.id), true);
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue