diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-02-26 20:21:54 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-26 20:21:54 +0900 |
| commit | 02c8fd9de51b6a8471ab9a89f23bcfeaecd7626c (patch) | |
| tree | 018a46cad9a19cc8cdfcff91442b343a637b56f8 /packages/backend/src/server/api/endpoints/notes/create.test.ts | |
| parent | Merge pull request #10058 from misskey-dev/develop (diff) | |
| parent | Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop (diff) | |
| download | misskey-02c8fd9de51b6a8471ab9a89f23bcfeaecd7626c.tar.gz misskey-02c8fd9de51b6a8471ab9a89f23bcfeaecd7626c.tar.bz2 misskey-02c8fd9de51b6a8471ab9a89f23bcfeaecd7626c.zip | |
Merge pull request #10108 from misskey-dev/develop
* Add dialog to remove follower (#9718)
* update PULL_REQUEST_TEMPLATE
* 起動時にRedisの疎通確認を行う (#9832)
* 起動時にRedisの疎通確認を行う
* check:connectをstart内に移動
---------
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
* Pass `--detectOpenHandles` to Jest (#9895)
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
* enhance(client): MkUrlPreviewの閉じるボタンを見やすく (#9913)
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
* test(backend): restore ap-request tests (#9997)
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
* fix/refaftor(client): MkTime.vueの変更 (#10061)
* fix(client): MkTime.timeにstringでもDateでない値が入った場合、?を表示
* fix(client): MkTimeを改良
* numberを許容
* falsyな値もとる
* 不明
* ありません
* fix
* fix(server): notes/createで、fileIdsと見つかったファイルの数が異なる場合はエラーにする (#9911)
* fix(server): notes/createで、fileIdsと見つかったファイルの数が異なる場合はエラーにする
* NO_SUCH_FILE
* Update codecov.yml
* Update apple-touch-icon.png
* デプロイされているプレビュー環境がない場合はプレビュー環境を削除しないようにする (#10062)
* デプロイされているプレビュー環境がない場合はDestroy preview environmentを実行しないようにする
* CIがない場合の処理追加
* enhance(client): improve clip menu ux
* 未知のユーザーが deleteActor されたら処理をスキップする (#10067)
* fix(client): Android ChromeでPWAとしてインストールできない問題を修正 (#10069)
* fix(client): Android ChromeでPWAとしてインストールできない問題を修正
* 順番関係ある?
* Windows環境でswcを使うと正常にビルドができない問題の修正 (#10074)
* Update @swc/core to v1.3.36
* Update CHANGELOG.md
* Update CHANGELOG.md
* バックグラウンドで一定時間経過したらページネーションのアイテム更新をしない (#10053)
* :art:
* feat: 2つの検索画面の統合 (#9949) (#10038)
* feat: 検索画面の UI を統一
* fix: エラーの修正
* add: changelog
---------
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
* enhance(client): ノートメニューからユーザーメニューを開けるように
Resolve #10019
* enhance(client): renoteした際の表示を改善
Resolve #10078
* Update CHANGELOG.md
* enhance(client): tweak contextmenu position calculation
* :art:
* :art:
* feat: in-channel featured note
Resolve #9938
* refactor(frontend): fix eslint error (#10084)
* Simplify search.vue (remove dead code) (#10088)
* Simplify search.vue
This is already handled by the code above it, no need to handle it twice
* Remove unused imports
* Update about-misskey.vue
* test(server): add validation test of api:notes/create (#10090)
* fix(server): notes/createのバリデーションが効いていない
Fix #10079
Co-Authored-By: mei23 <m@m544.net>
* anyOf内にバリデーションを書いても最初の一つしかチェックされない
* :v:
* wip
* wip
* :v:
* RequiredProp
* Revert "RequiredProp"
This reverts commit 74693900119a590263106fa3adefd008d69ce80c.
* add api:notes/create
* fix lint
* text
* :v:
* improve readability
---------
Co-authored-by: mei23 <m@m544.net>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
* New Crowdin updates (#10059)
* New translations ja-JP.yml (Japanese, Kansai)
* New translations ja-JP.yml (Romanian)
* New translations ja-JP.yml (French)
* New translations ja-JP.yml (Spanish)
* New translations ja-JP.yml (Arabic)
* New translations ja-JP.yml (Czech)
* New translations ja-JP.yml (German)
* New translations ja-JP.yml (Italian)
* New translations ja-JP.yml (Korean)
* New translations ja-JP.yml (Polish)
* New translations ja-JP.yml (Russian)
* New translations ja-JP.yml (Slovak)
* New translations ja-JP.yml (Ukrainian)
* New translations ja-JP.yml (Chinese Simplified)
* New translations ja-JP.yml (Chinese Traditional)
* New translations ja-JP.yml (English)
* New translations ja-JP.yml (Vietnamese)
* New translations ja-JP.yml (Indonesian)
* New translations ja-JP.yml (Bengali)
* New translations ja-JP.yml (Thai)
* New translations ja-JP.yml (Japanese, Kansai)
* New translations ja-JP.yml (Chinese Traditional)
* New translations ja-JP.yml (Chinese Traditional)
* New translations ja-JP.yml (German)
* New translations ja-JP.yml (English)
* New translations ja-JP.yml (German)
* New translations ja-JP.yml (Ukrainian)
* New translations ja-JP.yml (Chinese Simplified)
* New translations ja-JP.yml (English)
* New translations ja-JP.yml (Ukrainian)
* New translations ja-JP.yml (Ukrainian)
* New translations ja-JP.yml (Ukrainian)
* New translations ja-JP.yml (Chinese Simplified)
* New translations ja-JP.yml (Japanese, Kansai)
* New translations ja-JP.yml (Thai)
* New translations ja-JP.yml (Thai)
* New translations ja-JP.yml (Thai)
* New translations ja-JP.yml (Spanish)
* New translations ja-JP.yml (Spanish)
* enhance(client): improve user menu ux
* enhance(client): photoswipe 表示時に戻る操作をしても前の画面に戻らないように (#10098)
* enhance(client): photoswipe 表示時に戻る操作をしても前の画面に戻らないように
* add: changelog
---------
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
* enhance(client): メニューの「もっと」からインスタンス情報を見れるように
* [Fix] fixed an typo in error message (#10102)
* Update codecov.yml
* Update CHANGELOG.md
* fix(server): エラーのスタックトレースは返さないように
Fix #10064
* [chore]Editorconfig: ymlに加えてyamlファイルに対しても同じ規約を適用する (#10081)
* Added yaml file in addition to yml file, in editorconfig
* Applied editorconfig for pnpm-workspace.yaml
---------
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
* update deps
* ホームタイムラインの読み込みでクエリタイムアウトになるのを修正する (#10106)
* refactor
* New translations ja-JP.yml (French) (#10103)
* Update CHANGELOG.md
* 13.8.0
---------
Co-authored-by: atsuchan <83960488+atsu1125@users.noreply.github.com>
Co-authored-by: Masaya Suzuki <15100604+massongit@users.noreply.github.com>
Co-authored-by: tamaina <tamaina@hotmail.co.jp>
Co-authored-by: Kagami Sascha Rosylight <saschanaz@outlook.com>
Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com>
Co-authored-by: xianon <xianon@hotmail.co.jp>
Co-authored-by: kabo2468 <28654659+kabo2468@users.noreply.github.com>
Co-authored-by: YS <47836716+yszkst@users.noreply.github.com>
Co-authored-by: Khsmty <me@khsmty.com>
Co-authored-by: Soni L <EnderMoneyMod@gmail.com>
Co-authored-by: mei23 <m@m544.net>
Co-authored-by: daima3629 <52790780+daima3629@users.noreply.github.com>
Co-authored-by: Windymelt <1113940+windymelt@users.noreply.github.com>
Diffstat (limited to 'packages/backend/src/server/api/endpoints/notes/create.test.ts')
| -rw-r--r-- | packages/backend/src/server/api/endpoints/notes/create.test.ts | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/packages/backend/src/server/api/endpoints/notes/create.test.ts b/packages/backend/src/server/api/endpoints/notes/create.test.ts new file mode 100644 index 0000000000..6bff7fc0c9 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/notes/create.test.ts @@ -0,0 +1,263 @@ +process.env.NODE_ENV = 'test'; + +import { readFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +import { describe, test, expect } from '@jest/globals'; +import { getValidator } from '../../../../../test/prelude/get-api-validator.js'; +import { paramDef } from './create.js'; + +const _filename = fileURLToPath(import.meta.url); +const _dirname = dirname(_filename); + +const VALID = true; +const INVALID = false; + +describe('api:notes/create', () => { + describe('validation', () => { + const v = getValidator(paramDef); + const tooLong = readFile(_dirname + '/../../../../../test/resources/misskey.svg', 'utf-8'); + + test('reject empty', () => { + const valid = v({ }); + expect(valid).toBe(INVALID); + }); + + describe('text', () => { + test('simple post', () => { + expect(v({ text: 'Hello, world!' })) + .toBe(VALID); + }); + + test('null post', () => { + expect(v({ text: null })) + .toBe(INVALID); + }); + + test('0 characters post', () => { + expect(v({ text: '' })) + .toBe(INVALID); + }); + + test('over 3000 characters post', async () => { + expect(v({ text: await tooLong })) + .toBe(INVALID); + }); + }); + + describe('cw', () => { + test('simple cw', () => { + expect(v({ text: 'Hello, world!', cw: 'Hello, world!' })) + .toBe(VALID); + }); + + test('null cw', () => { + expect(v({ text: 'Body', cw: null })) + .toBe(VALID); + }); + + test('0 characters cw', () => { + expect(v({ text: 'Body', cw: '' })) + .toBe(VALID); + }); + + test('reject only cw', () => { + expect(v({ cw: 'Hello, world!' })) + .toBe(INVALID); + }); + + test('over 100 characters cw', async () => { + expect(v({ text: 'Body', cw: await tooLong })) + .toBe(INVALID); + }); + }); + + describe('visibility', () => { + test('public', () => { + expect(v({ text: 'Hello, world!', visibility: 'public' })) + .toBe(VALID); + }); + + test('home', () => { + expect(v({ text: 'Hello, world!', visibility: 'home' })) + .toBe(VALID); + }); + + test('followers', () => { + expect(v({ text: 'Hello, world!', visibility: 'followers' })) + .toBe(VALID); + }); + + test('reject only visibility', () => { + expect(v({ visibility: 'public' })) + .toBe(INVALID); + }); + + test('reject invalid visibility', () => { + expect(v({ text: 'Hello, world!', visibility: 'invalid' })) + .toBe(INVALID); + }); + + test('reject null visibility', () => { + expect(v({ text: 'Hello, world!', visibility: null })) + .toBe(INVALID); + }); + + describe('visibility:specified', () => { + test('specified without visibleUserIds', () => { + expect(v({ text: 'Hello, world!', visibility: 'specified' })) + .toBe(VALID); + }); + + test('specified with empty visibleUserIds', () => { + expect(v({ text: 'Hello, world!', visibility: 'specified', visibleUserIds: [] })) + .toBe(VALID); + }); + + test('reject specified with non unique visibleUserIds', () => { + expect(v({ text: 'Hello, world!', visibility: 'specified', visibleUserIds: ['1', '1', '2'] })) + .toBe(INVALID); + }); + + test('reject specified with null visibleUserIds', () => { + expect(v({ text: 'Hello, world!', visibility: 'specified', visibleUserIds: null })) + .toBe(INVALID); + }); + }); + }); + + describe('fileIds', () => { + test('only fileIds', () => { + expect(v({ fileIds: ['1', '2', '3'] })) + .toBe(VALID); + }); + + test('text and fileIds', () => { + expect(v({ text: 'Hello, world!', fileIds: ['1', '2', '3'] })) + .toBe(VALID); + }); + + test('reject null fileIds', () => { + expect(v({ fileIds: null })) + .toBe(INVALID); + }); + + test('reject text and null fileIds (複合的なanyOfのバリデーションが正しく動作する)', () => { + expect(v({ text: 'Hello, world!', fileIds: null })) + .toBe(INVALID); + }); + + test('reject 0 files', () => { + expect(v({ fileIds: [] })) + .toBe(INVALID); + }); + + test('reject non unique', () => { + expect(v({ fileIds: ['1', '1', '2'] })) + .toBe(INVALID); + }); + + test('reject invalid id', () => { + expect(v({ fileIds: ['あ'] })) + .toBe(INVALID); + }); + + test('reject over 17 files', () => { + const valid = v({ text: 'Hello, world!', fileIds: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18'] }); + expect(valid).toBe(INVALID); + }); + }); + + describe('poll', () => { + test('note with poll', () => { + expect(v({ text: 'Hello, world!', poll: { choices: ['a', 'b', 'c'] } })) + .toBe(VALID); + }); + + test('null poll', () => { + expect(v({ text: 'Hello, world!', poll: null })) + .toBe(VALID); + }); + + test('allow only poll', () => { + expect(v({ poll: { choices: ['a', 'b', 'c'] } })) + .toBe(VALID); + }); + + test('poll with expiresAt', async () => { + expect(v({ poll: { choices: ['a', 'b', 'c'], expiresAt: 1 } })) + .toBe(VALID); + }); + + test('poll with expiredAfter', async () => { + expect(v({ poll: { choices: ['a', 'b', 'c'], expiredAfter: 1 } })) + .toBe(VALID); + }); + + test('reject poll without choices', () => { + expect(v({ poll: { } })) + .toBe(INVALID); + }); + + test('reject poll with empty choices', () => { + expect(v({ poll: { choices: [] } })) + .toBe(INVALID); + }); + + test('reject poll with null choices', () => { + expect(v({ poll: { choices: null } })) + .toBe(INVALID); + }); + + test('reject poll with 1 choice', () => { + expect(v({ poll: { choices: ['a'] } })) + .toBe(INVALID); + }); + + test('reject poll with too long choice', async () => { + expect(v({ poll: { choices: [await tooLong, '2'] } })) + .toBe(INVALID); + }); + + test('reject poll with too many choices', () => { + expect(v({ poll: { choices: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'] } })) + .toBe(INVALID); + }); + + test('reject poll with non unique choices', () => { + expect(v({ poll: { choices: ['a', 'a', 'b', 'c'] } })) + .toBe(INVALID); + }); + + test('reject poll with expiredAfter 0', async () => { + expect(v({ poll: { choices: ['a', 'b', 'c'], expiredAfter: 0 } })) + .toBe(INVALID); + }); + }); + + describe('renote', () => { + test('just a renote', () => { + expect(v({ renoteId: '1' })) + .toBe(VALID); + }); + test('just a quote', () => { + expect(v({ text: 'Hello, world!', renoteId: '1' })) + .toBe(VALID); + }); + test('reject invalid renoteId', () => { + expect(v({ renoteId: 'あ' })) + .toBe(INVALID); + }); + }); + + test('text, fileIds and poll', () => { + expect(v({ text: 'Hello, world!', fileIds: ['1', '2', '3'], poll: { choices: ['a', 'b', 'c'] } })) + .toBe(VALID); + }); + + test('text, invalid fileIds and invalid poll', () => { + expect(v({ text: 'Hello, world!', fileIds: ['あ'], poll: { choices: ['a'] } })) + .toBe(INVALID); + }); + }); +}); |