diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 9681cbec59..3b49173f45 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -8,7 +8,7 @@ on: pull_request: jobs: - jest: + unit: runs-on: ubuntu-latest strategy: @@ -51,9 +51,59 @@ jobs: - name: Build run: pnpm build - name: Test - run: pnpm jest-and-coverage - - name: Upload Coverage + run: pnpm --filter backend test-and-coverage + - name: Upload to Codecov uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/backend/coverage/coverage-final.json + + e2e: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.10.0] + + services: + postgres: + image: postgres:15 + ports: + - 54312:5432 + env: + POSTGRES_DB: test-misskey + POSTGRES_HOST_AUTH_METHOD: trust + redis: + image: redis:7 + ports: + - 56312:6379 + + steps: + - uses: actions/checkout@v4.1.1 + with: + submodules: true + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: false + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4.0.1 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + - run: corepack enable + - run: pnpm i --frozen-lockfile + - name: Check pnpm-lock.yaml + run: git diff --exit-code pnpm-lock.yaml + - name: Copy Configure + run: cp .github/misskey/test.yml .config + - name: Build + run: pnpm build + - name: Test + run: pnpm --filter backend test-and-coverage:e2e + - name: Upload to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./packages/backend/coverage/coverage-final.json diff --git a/.gitignore b/.gitignore index a66e527db0..d7b486b977 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ docker-compose.yml # misskey /build built +built-test /data /.cache-loader /db diff --git a/packages/backend/jest.config.cjs b/packages/backend/jest.config.cjs index 97d777c862..5a4aa4e15a 100644 --- a/packages/backend/jest.config.cjs +++ b/packages/backend/jest.config.cjs @@ -160,7 +160,6 @@ module.exports = { testMatch: [ "/test/unit/**/*.ts", "/src/**/*.test.ts", - "/test/e2e/**/*.ts", ], // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped diff --git a/packages/backend/jest.config.e2e.cjs b/packages/backend/jest.config.e2e.cjs new file mode 100644 index 0000000000..4502da47df --- /dev/null +++ b/packages/backend/jest.config.e2e.cjs @@ -0,0 +1,15 @@ +/* +* For a detailed explanation regarding each configuration property and type check, visit: +* https://jestjs.io/docs/en/configuration.html +*/ + +const base = require('./jest.config.cjs') + +module.exports = { + ...base, + globalSetup: "/built-test/entry.js", + setupFilesAfterEnv: ["/test/jest.setup.ts"], + testMatch: [ + "/test/e2e/**/*.ts", + ], +}; diff --git a/packages/backend/jest.config.unit.cjs b/packages/backend/jest.config.unit.cjs new file mode 100644 index 0000000000..aa5992936b --- /dev/null +++ b/packages/backend/jest.config.unit.cjs @@ -0,0 +1,14 @@ +/* +* For a detailed explanation regarding each configuration property and type check, visit: +* https://jestjs.io/docs/en/configuration.html +*/ + +const base = require('./jest.config.cjs') + +module.exports = { + ...base, + testMatch: [ + "/test/unit/**/*.ts", + "/src/**/*.test.ts", + ], +}; diff --git a/packages/backend/package.json b/packages/backend/package.json index 7b9654c207..5ab476295c 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -13,6 +13,7 @@ "revert": "pnpm typeorm migration:revert -d ormconfig.js", "check:connect": "node ./check_connect.js", "build": "swc src -d built -D", + "build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc", "watch:swc": "swc src -d built -D -w", "build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json", "watch": "node watch.mjs", @@ -21,11 +22,15 @@ "typecheck": "tsc --noEmit", "eslint": "eslint --quiet \"src/**/*.ts\"", "lint": "pnpm typecheck && pnpm eslint", - "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit", - "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit", + "jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.unit.cjs", + "jest:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.e2e.cjs", + "jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --config jest.config.unit.cjs", + "jest-and-coverage:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --config jest.config.e2e.cjs", "jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache", "test": "pnpm jest", + "test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e", "test-and-coverage": "pnpm jest-and-coverage", + "test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e", "generate-api-json": "node ./generate_api_json.js" }, "optionalDependencies": { @@ -178,6 +183,7 @@ "devDependencies": { "@jest/globals": "29.7.0", "@misskey-dev/eslint-plugin": "^1.0.0", + "@nestjs/platform-express": "^10.3.0", "@simplewebauthn/typescript-types": "8.3.4", "@swc/jest": "0.2.29", "@types/accepts": "1.3.7", @@ -226,9 +232,11 @@ "eslint": "8.56.0", "eslint-plugin-import": "2.29.1", "execa": "8.0.1", + "fkill": "^9.0.0", "jest": "29.7.0", "jest-mock": "29.7.0", "nodemon": "3.0.2", + "pid-port": "^1.0.0", "simple-oauth2": "5.0.0" } } diff --git a/packages/backend/test-server/.eslintrc.cjs b/packages/backend/test-server/.eslintrc.cjs new file mode 100644 index 0000000000..c261741a36 --- /dev/null +++ b/packages/backend/test-server/.eslintrc.cjs @@ -0,0 +1,32 @@ +module.exports = { + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + extends: [ + '../../shared/.eslintrc.js', + ], + rules: { + 'import/order': ['warn', { + 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], + 'pathGroups': [ + { + 'pattern': '@/**', + 'group': 'external', + 'position': 'after' + } + ], + }], + 'no-restricted-globals': [ + 'error', + { + 'name': '__dirname', + 'message': 'Not in ESModule. Use `import.meta.url` instead.' + }, + { + 'name': '__filename', + 'message': 'Not in ESModule. Use `import.meta.url` instead.' + } + ] + }, +}; diff --git a/packages/backend/test-server/.swcrc b/packages/backend/test-server/.swcrc new file mode 100644 index 0000000000..e3d6935169 --- /dev/null +++ b/packages/backend/test-server/.swcrc @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript", + "dynamicImport": true, + "decorators": true + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + }, + "experimental": { + "keepImportAssertions": true + }, + "baseUrl": "../built", + "paths": { + "@/*": ["*"] + }, + "target": "es2022" + }, + "minify": false +} diff --git a/packages/backend/test-server/entry.ts b/packages/backend/test-server/entry.ts new file mode 100644 index 0000000000..866a7e1f5b --- /dev/null +++ b/packages/backend/test-server/entry.ts @@ -0,0 +1,80 @@ +import { portToPid } from 'pid-port'; +import fkill from 'fkill'; +import Fastify from 'fastify'; +import { NestFactory } from '@nestjs/core'; +import { MainModule } from '@/MainModule.js'; +import { ServerService } from '@/server/ServerService.js'; +import { loadConfig } from '@/config.js'; +import { NestLogger } from '@/NestLogger.js'; + +const config = loadConfig(); +const originEnv = JSON.stringify(process.env); + +process.env.NODE_ENV = 'test'; + +/** + * テスト用のサーバインスタンスを起動する + */ +async function launch() { + await killTestServer(); + + console.log('starting application...'); + + const app = await NestFactory.createApplicationContext(MainModule, { + logger: new NestLogger(), + }); + const serverService = app.get(ServerService); + await serverService.launch(); + + await startControllerEndpoints(); + + // ジョブキューは必要な時にテストコード側で起動する + // ジョブキューが動くとテスト結果の確認に支障が出ることがあるので意図的に動かさないでいる + + console.log('application initialized.'); +} + +/** + * 既に重複したポートで待ち受けしているサーバがある場合はkillする + */ +async function killTestServer() { + // + try { + const pid = await portToPid(config.port); + if (pid) { + await fkill(pid, { force: true }); + } + } catch { + // NOP; + } +} + +/** + * 別プロセスに切り離してしまったが故に出来なくなった環境変数の書き換え等を実現するためのエンドポイントを作る + * @param port + */ +async function startControllerEndpoints(port = config.port + 1000) { + const fastify = Fastify(); + + fastify.post<{ Body: { key?: string, value?: string } }>('/env', async (req, res) => { + console.log(req.body); + const key = req.body['key']; + if (!key) { + res.code(400).send({ success: false }); + return; + } + + process.env[key] = req.body['value']; + + res.code(200).send({ success: true }); + }); + + fastify.post<{ Body: { key?: string, value?: string } }>('/env-reset', async (req, res) => { + process.env = JSON.parse(originEnv); + res.code(200).send({ success: true }); + }); + + await fastify.listen({ port: port, host: 'localhost' }); +} + +export default launch; diff --git a/packages/backend/test-server/tsconfig.json b/packages/backend/test-server/tsconfig.json new file mode 100644 index 0000000000..10313699c2 --- /dev/null +++ b/packages/backend/test-server/tsconfig.json @@ -0,0 +1,52 @@ +{ + "compilerOptions": { + "allowJs": true, + "noEmitOnError": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedParameters": false, + "noUnusedLocals": false, + "noFallthroughCasesInSwitch": true, + "declaration": false, + "sourceMap": true, + "target": "ES2022", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowSyntheticDefaultImports": true, + "removeComments": false, + "noLib": false, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": false, + "skipLibCheck": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "resolveJsonModule": true, + "isolatedModules": true, + "rootDir": "../src", + "baseUrl": "./", + "paths": { + "@/*": ["../src/*"] + }, + "outDir": "../built-test", + "types": [ + "node" + ], + "typeRoots": [ + "../src/@types", + "../node_modules/@types", + "../node_modules" + ], + "lib": [ + "esnext" + ] + }, + "compileOnSave": false, + "include": [ + "./**/*.ts", + "../src/**/*.ts" + ], + "exclude": [ + "../src/**/*.test.ts" + ] +} diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index dfed8b2fce..165a1055c9 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -10,7 +10,7 @@ import * as crypto from 'node:crypto'; import cbor from 'cbor'; import * as OTPAuth from 'otpauth'; import { loadConfig } from '@/config.js'; -import { api, signup, startServer } from '../utils.js'; +import { api, signup } from '../utils.js'; import type { AuthenticationResponseJSON, AuthenticatorAssertionResponseJSON, @@ -19,11 +19,9 @@ import type { PublicKeyCredentialRequestOptionsJSON, RegistrationResponseJSON, } from '@simplewebauthn/typescript-types'; -import type { INestApplicationContext } from '@nestjs/common'; import type * as misskey from 'misskey-js'; describe('2要素認証', () => { - let app: INestApplicationContext; let alice: misskey.entities.SignupResponse; const config = loadConfig(); @@ -185,14 +183,9 @@ describe('2要素認証', () => { }; beforeAll(async () => { - app = await startServer(); alice = await signup({ username, password }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('が設定でき、OTPでログインできる。', async () => { const registerResponse = await api('/i/2fa/register', { password, diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts index 9bac5122d4..e63722b246 100644 --- a/packages/backend/test/e2e/antennas.ts +++ b/packages/backend/test/e2e/antennas.ts @@ -6,24 +6,20 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { inspect } from 'node:util'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; import type { Packed } from '@/misc/json-schema.js'; import { - signup, - post, - userList, - page, - role, - startServer, api, - successfulApiCall, failedApiCall, - uploadFile, + post, + role, + signup, + successfulApiCall, testPaginationConsistency, + uploadFile, + userList, } from '../utils.js'; import type * as misskey from 'misskey-js'; -import type { INestApplicationContext } from '@nestjs/common'; const compareBy = (selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => { return selector(a).localeCompare(selector(b)); @@ -54,8 +50,6 @@ describe('アンテナ', () => { withReplies: false, }; - let app: INestApplicationContext; - let root: User; let alice: User; let bob: User; @@ -79,10 +73,6 @@ describe('アンテナ', () => { let userMutingAlice: User; let userMutedByAlice: User; - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - beforeAll(async () => { root = await signup({ username: 'root' }); alice = await signup({ username: 'alice' }); @@ -136,10 +126,6 @@ describe('アンテナ', () => { await api('mute/create', { userId: userMutedByAlice.id }, alice); }, 1000 * 60 * 10); - afterAll(async () => { - await app.close(); - }); - beforeEach(async () => { // テスト間で影響し合わないように毎回全部消す。 for (const user of [alice, bob]) { diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts index afe4f9c05a..89d8b42271 100644 --- a/packages/backend/test/e2e/api-visibility.ts +++ b/packages/backend/test/e2e/api-visibility.ts @@ -6,21 +6,10 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('API visibility', () => { - let app: INestApplicationContext; - - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - - afterAll(async () => { - await app.close(); - }); - describe('Note visibility', () => { //#region vars /** ヒロイン */ diff --git a/packages/backend/test/e2e/api.ts b/packages/backend/test/e2e/api.ts index ad351eebbb..25d5bdb175 100644 --- a/packages/backend/test/e2e/api.ts +++ b/packages/backend/test/e2e/api.ts @@ -7,27 +7,30 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { IncomingMessage } from 'http'; -import { signup, api, startServer, successfulApiCall, failedApiCall, uploadFile, waitFire, connectStream, relativeFetch, createAppToken } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { + api, + connectStream, + createAppToken, + failedApiCall, + relativeFetch, + signup, + successfulApiCall, + uploadFile, + waitFire, +} from '../utils.js'; import type * as misskey from 'misskey-js'; describe('API', () => { - let app: INestApplicationContext; let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe('General validation', () => { test('wrong type', async () => { const res = await api('/test', { diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts index 25ff9f11ac..1dfc87c64f 100644 --- a/packages/backend/test/e2e/block.ts +++ b/packages/backend/test/e2e/block.ts @@ -6,29 +6,21 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Block', () => { - let app: INestApplicationContext; - // alice blocks bob let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('Block作成', async () => { const res = await api('/blocking/create', { userId: bob.id, diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts index 49092fba63..b679eea8cf 100644 --- a/packages/backend/test/e2e/clips.ts +++ b/packages/backend/test/e2e/clips.ts @@ -18,25 +18,13 @@ import { paramDef as UnfavoriteParamDef } from '@/server/api/endpoints/clips/unf import { paramDef as AddNoteParamDef } from '@/server/api/endpoints/clips/add-note.js'; import { paramDef as RemoveNoteParamDef } from '@/server/api/endpoints/clips/remove-note.js'; import { paramDef as NotesParamDef } from '@/server/api/endpoints/clips/notes.js'; -import { - signup, - post, - startServer, - api, - successfulApiCall, - failedApiCall, - ApiRequest, - hiddenNote, -} from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, ApiRequest, failedApiCall, hiddenNote, post, signup, successfulApiCall } from '../utils.js'; describe('クリップ', () => { type User = Packed<'User'>; type Note = Packed<'Note'>; type Clip = Packed<'Clip'>; - let app: INestApplicationContext; - let alice: User; let bob: User; let aliceNote: Note; @@ -145,7 +133,6 @@ describe('クリップ', () => { }; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); @@ -160,10 +147,6 @@ describe('クリップ', () => { bobSpecifiedNote = await post(bob, { text: 'specified only', visibility: 'specified' }) as any; }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - afterEach(async () => { // テスト間で影響し合わないように毎回全部消す。 for (const user of [alice, bob]) { diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index d75549c816..b12b062a63 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -10,30 +10,22 @@ import * as assert from 'assert'; // https://github.com/node-fetch/node-fetch/pull/1664 import { Blob } from 'node-fetch'; import { MiUser } from '@/models/_.js'; -import { startServer, signup, post, api, uploadFile, simpleGet, initTestDb } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, initTestDb, post, signup, simpleGet, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Endpoints', () => { - let app: INestApplicationContext; - let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; let dave: misskey.entities.SignupResponse; beforeAll(async () => { - app = 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 app.close(); - }); - describe('signup', () => { test('不正なユーザー名でアカウントが作成できない', async () => { const res = await api('signup', { diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts index 9686f2b7fd..f9b59144a3 100644 --- a/packages/backend/test/e2e/exports.ts +++ b/packages/backend/test/e2e/exports.ts @@ -6,12 +6,12 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, startServer, startJobQueue, port, post } from '../utils.js'; +import { api, port, post, signup, startJobQueue } from '../utils.js'; import type { INestApplicationContext } from '@nestjs/common'; import type * as misskey from 'misskey-js'; describe('export-clips', () => { - let app: INestApplicationContext; + let queue: INestApplicationContext; let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; @@ -33,14 +33,13 @@ describe('export-clips', () => { } beforeAll(async () => { - app = await startServer(); - await startJobQueue(); + queue = await startJobQueue(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); afterAll(async () => { - await app.close(); + await queue.close(); }); beforeEach(async () => { diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index 28affe7768..0d23b4fe67 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -6,9 +6,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { startServer, channel, clip, cookie, galleryPost, signup, page, play, post, simpleGet, uploadFile } from '../utils.js'; +import { channel, clip, cookie, galleryPost, page, play, post, signup, simpleGet, uploadFile } from '../utils.js'; import type { SimpleGetResponse } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; import type * as misskey from 'misskey-js'; // Request Accept @@ -23,8 +22,6 @@ const HTML = 'text/html; charset=utf-8'; const JSON_UTF8 = 'application/json; charset=utf-8'; describe('Webリソース', () => { - let app: INestApplicationContext; - let alice: misskey.entities.SignupResponse; let aliceUploadedFile: any; let alicesPost: any; @@ -79,7 +76,6 @@ describe('Webリソース', () => { }; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); aliceUploadedFile = await uploadFile(alice); alicesPost = await post(alice, { @@ -96,10 +92,6 @@ describe('Webリソース', () => { bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe.each([ { path: '/', type: HTML }, { path: '/docs/ja-JP/about', type: HTML }, // "指定されたURLに該当するページはありませんでした。" diff --git a/packages/backend/test/e2e/ff-visibility.ts b/packages/backend/test/e2e/ff-visibility.ts index 4d323e14e7..1fe0478a18 100644 --- a/packages/backend/test/e2e/ff-visibility.ts +++ b/packages/backend/test/e2e/ff-visibility.ts @@ -6,26 +6,18 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, startServer, simpleGet } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, signup, simpleGet } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('FF visibility', () => { - let app: INestApplicationContext; - let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('followingVisibility, followersVisibility がともに public なユーザーのフォロー/フォロワーを誰でも見れる', async () => { await api('/i/update', { followingVisibility: 'public', diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts index f7da66a27c..3937203569 100644 --- a/packages/backend/test/e2e/move.ts +++ b/packages/backend/test/e2e/move.ts @@ -3,19 +3,19 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { INestApplicationContext } from '@nestjs/common'; + process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { loadConfig } from '@/config.js'; import { MiUser, UsersRepository } from '@/models/_.js'; -import { jobQueue } from '@/boot/common.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; -import { uploadFile, signup, startServer, initTestDb, api, sleep, successfulApiCall } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { jobQueue } from '@/boot/common.js'; +import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Account Move', () => { - let app: INestApplicationContext; let jq: INestApplicationContext; let url: URL; @@ -30,8 +30,8 @@ describe('Account Move', () => { let Users: UsersRepository; beforeAll(async () => { - app = await startServer(); jq = await jobQueue(); + const config = loadConfig(); url = new URL(config.url); const connection = await initTestDb(false); @@ -46,7 +46,7 @@ describe('Account Move', () => { }, 1000 * 60 * 2); afterAll(async () => { - await Promise.all([app.close(), jq.close()]); + await jq.close(); }); describe('Create Alias', () => { diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts index 3b5542dfe0..5144df5ebe 100644 --- a/packages/backend/test/e2e/mute.ts +++ b/packages/backend/test/e2e/mute.ts @@ -6,29 +6,21 @@ 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'; +import { api, post, react, signup, waitFire } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Mute', () => { - let app: INestApplicationContext; - // alice mutes carol let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('ミュート作成', async () => { const res = await api('/mute/create', { userId: carol.id, diff --git a/packages/backend/test/e2e/nodeinfo.ts b/packages/backend/test/e2e/nodeinfo.ts index 7eed39c5ed..934ef08507 100644 --- a/packages/backend/test/e2e/nodeinfo.ts +++ b/packages/backend/test/e2e/nodeinfo.ts @@ -6,20 +6,9 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { relativeFetch, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { relativeFetch } from '../utils.js'; describe('nodeinfo', () => { - let app: INestApplicationContext; - - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - - afterAll(async () => { - await app.close(); - }); - test('nodeinfo 2.1', async () => { const res = await relativeFetch('nodeinfo/2.1'); assert.ok(res.ok); diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts index 8d33c63485..0f2e08e675 100644 --- a/packages/backend/test/e2e/note.ts +++ b/packages/backend/test/e2e/note.ts @@ -8,29 +8,22 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { MiNote } from '@/models/Note.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import { signup, post, uploadUrl, startServer, initTestDb, api, uploadFile } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, initTestDb, post, signup, uploadFile, uploadUrl } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Note', () => { - let app: INestApplicationContext; let Notes: any; let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); const connection = await initTestDb(true); Notes = connection.getRepository(MiNote); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('投稿できる', async () => { const post = { text: 'test', diff --git a/packages/backend/test/e2e/oauth.ts b/packages/backend/test/e2e/oauth.ts index 3ca1f8b542..df6ff42df9 100644 --- a/packages/backend/test/e2e/oauth.ts +++ b/packages/backend/test/e2e/oauth.ts @@ -11,13 +11,18 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { AuthorizationCode, ResourceOwnerPassword, type AuthorizationTokenConfig, ClientCredentials, ModuleOptions } from 'simple-oauth2'; +import { + AuthorizationCode, + type AuthorizationTokenConfig, + ClientCredentials, + ModuleOptions, + ResourceOwnerPassword, +} from 'simple-oauth2'; import pkceChallenge from 'pkce-challenge'; import { JSDOM } from 'jsdom'; -import Fastify, { type FastifyReply, type FastifyInstance } from 'fastify'; -import { api, port, signup, startServer } from '../utils.js'; +import Fastify, { type FastifyInstance, type FastifyReply } from 'fastify'; +import { api, port, sendEnvUpdateRequest, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; -import type { INestApplicationContext } from '@nestjs/common'; const host = `http://127.0.0.1:${port}`; @@ -147,7 +152,6 @@ async function assertDirectError(response: Response, status: number, error: stri } describe('OAuth', () => { - let app: INestApplicationContext; let fastify: FastifyInstance; let alice: misskey.entities.SignupResponse; @@ -156,7 +160,6 @@ describe('OAuth', () => { let sender: (reply: FastifyReply) => void; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); @@ -168,7 +171,7 @@ describe('OAuth', () => { }, 1000 * 60 * 2); beforeEach(async () => { - process.env.MISSKEY_TEST_CHECK_IP_RANGE = ''; + await sendEnvUpdateRequest({ key: 'MISSKEY_TEST_CHECK_IP_RANGE', value: '' }); sender = (reply): void => { reply.send(` @@ -180,7 +183,6 @@ describe('OAuth', () => { afterAll(async () => { await fastify.close(); - await app.close(); }); test('Full flow', async () => { @@ -881,7 +883,7 @@ describe('OAuth', () => { }); test('Disallow loopback', async () => { - process.env.MISSKEY_TEST_CHECK_IP_RANGE = '1'; + await sendEnvUpdateRequest({ key: 'MISSKEY_TEST_CHECK_IP_RANGE', value: '1' }); const client = new AuthorizationCode(clientConfig); const response = await fetch(client.authorizeURL({ diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts index fededdff32..42cc414c3f 100644 --- a/packages/backend/test/e2e/renote-mute.ts +++ b/packages/backend/test/e2e/renote-mute.ts @@ -6,29 +6,21 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { signup, api, post, react, startServer, waitFire, sleep } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, signup, sleep, waitFire } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Renote Mute', () => { - let app: INestApplicationContext; - // alice mutes carol let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('ミュート作成', async () => { const res = await api('/renote-mute/create', { userId: carol.id, diff --git a/packages/backend/test/e2e/streaming.ts b/packages/backend/test/e2e/streaming.ts index a447ba94ae..b6f584fa70 100644 --- a/packages/backend/test/e2e/streaming.ts +++ b/packages/backend/test/e2e/streaming.ts @@ -8,12 +8,10 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { WebSocket } from 'ws'; import { MiFollowing } from '@/models/Following.js'; -import { signup, api, post, startServer, initTestDb, waitFire, createAppToken, port } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, createAppToken, initTestDb, port, post, signup, waitFire } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Streaming', () => { - let app: INestApplicationContext; let Followings: any; const follow = async (follower: any, followee: any) => { @@ -48,7 +46,6 @@ describe('Streaming', () => { let list: any; beforeAll(async () => { - app = await startServer(); const connection = await initTestDb(true); Followings = connection.getRepository(MiFollowing); @@ -95,10 +92,6 @@ describe('Streaming', () => { }, chitose); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - describe('Events', () => { test('mention event', async () => { const fired = await waitFire( diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts index 5c68e2b150..26c30d6c4c 100644 --- a/packages/backend/test/e2e/thread-mute.ts +++ b/packages/backend/test/e2e/thread-mute.ts @@ -6,28 +6,20 @@ 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'; +import { api, connectStream, post, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Note thread mute', () => { - let app: INestApplicationContext; - let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; beforeAll(async () => { - app = await startServer(); alice = await signup({ username: 'alice' }); bob = await signup({ username: 'bob' }); carol = await signup({ username: 'carol' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.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' }); diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index cb9558b416..88f89c4a6f 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -6,12 +6,8 @@ // How to run: // pnpm jest -- e2e/timelines.ts -process.env.NODE_ENV = 'test'; -process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING = 'true'; - import * as assert from 'assert'; -import { api, post, randomString, signup, sleep, startServer, uploadUrl } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { api, post, randomString, sendEnvUpdateRequest, signup, sleep, uploadUrl } from '../utils.js'; function genHost() { return randomString() + '.example.com'; @@ -21,16 +17,6 @@ function waitForPushToTl() { return sleep(500); } -let app: INestApplicationContext; - -beforeAll(async () => { - app = await startServer(); -}, 1000 * 60 * 2); - -afterAll(async () => { - await app.close(); -}); - describe('Timelines', () => { describe('Home TL', () => { test.concurrent('自分の visibility: followers なノートが含まれる', async () => { @@ -334,8 +320,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーのノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); @@ -348,8 +335,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); @@ -762,8 +750,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーのノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); @@ -776,8 +765,9 @@ describe('Timelines', () => { test.concurrent('フォローしているリモートユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); + await sendEnvUpdateRequest({ key: 'FORCE_FOLLOW_REMOTE_USER_FOR_TESTING', value: 'true' }); await api('/following/create', { userId: bob.id }, alice); - await sleep(1000); + const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts index 4f2e7c4cf3..07da0db369 100644 --- a/packages/backend/test/e2e/user-notes.ts +++ b/packages/backend/test/e2e/user-notes.ts @@ -6,20 +6,16 @@ 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'; +import { api, post, signup, uploadUrl } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('users/notes', () => { - let app: INestApplicationContext; - let alice: misskey.entities.SignupResponse; let jpgNote: any; let pngNote: any; let jpgPngNote: any; beforeAll(async () => { - app = 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'); @@ -34,10 +30,6 @@ describe('users/notes', () => { }); }, 1000 * 60 * 2); - afterAll(async() => { - await app.close(); - }); - test('withFiles', async () => { const res = await api('/users/notes', { userId: alice.id, diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 9c4cbac368..bc23c009b2 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -8,20 +8,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { inspect } from 'node:util'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; -import type { Packed } from '@/misc/json-schema.js'; -import { - signup, - post, - page, - role, - startServer, - api, - successfulApiCall, - failedApiCall, - uploadFile, -} from '../utils.js'; +import { api, page, post, role, signup, successfulApiCall, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; -import type { INestApplicationContext } from '@nestjs/common'; describe('ユーザー', () => { // エンティティとしてのユーザーを主眼においたテストを記述する @@ -185,8 +173,6 @@ describe('ユーザー', () => { }); }; - let app: INestApplicationContext; - let root: User; let alice: User; let aliceNote: misskey.entities.Note; @@ -230,10 +216,6 @@ describe('ユーザー', () => { let userFollowRequesting: User; let userFollowRequested: User; - beforeAll(async () => { - app = await startServer(); - }, 1000 * 60 * 2); - beforeAll(async () => { root = await signup({ username: 'root' }); alice = await signup({ username: 'alice' }); @@ -321,10 +303,6 @@ describe('ユーザー', () => { await api('following/create', { userId: userFollowRequested.id }, userFollowRequesting); }, 1000 * 60 * 10); - afterAll(async () => { - await app.close(); - }); - beforeEach(async () => { alice = { ...alice, diff --git a/packages/backend/test/e2e/well-known.ts b/packages/backend/test/e2e/well-known.ts index 14e32e1627..0429b7c8b2 100644 --- a/packages/backend/test/e2e/well-known.ts +++ b/packages/backend/test/e2e/well-known.ts @@ -6,24 +6,16 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { host, origin, relativeFetch, signup, startServer } from '../utils.js'; -import type { INestApplicationContext } from '@nestjs/common'; +import { host, origin, relativeFetch, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('.well-known', () => { - let app: INestApplicationContext; let alice: misskey.entities.User; beforeAll(async () => { - app = await startServer(); - alice = await signup({ username: 'alice' }); }, 1000 * 60 * 2); - afterAll(async () => { - await app.close(); - }); - test('nodeinfo', async () => { const res = await relativeFetch('.well-known/nodeinfo'); assert.ok(res.ok); diff --git a/packages/backend/test/jest.setup.ts b/packages/backend/test/jest.setup.ts new file mode 100644 index 0000000000..cf5b9bf24d --- /dev/null +++ b/packages/backend/test/jest.setup.ts @@ -0,0 +1,8 @@ +import { initTestDb, sendEnvResetRequest } from './utils.js'; + +beforeAll(async () => { + await Promise.all([ + initTestDb(false), + sendEnvResetRequest(), + ]); +}); diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index 7cba7a2aa8..7ee65d1ab0 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -15,7 +15,13 @@ import type { LoggerService } from '@/core/LoggerService.js'; import type { MetaService } from '@/core/MetaService.js'; import type { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; -import type { NoteReactionsRepository, NotesRepository, PollsRepository, UsersRepository, FollowRequestsRepository } from '@/models/_.js'; +import type { + FollowRequestsRepository, + NoteReactionsRepository, + NotesRepository, + PollsRepository, + UsersRepository, +} from '@/models/_.js'; type MockResponse = { type: string; diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts index f2aa5d35e4..f02c4e6700 100644 --- a/packages/backend/test/unit/AnnouncementService.ts +++ b/packages/backend/test/unit/AnnouncementService.ts @@ -10,7 +10,13 @@ import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import { GlobalModule } from '@/GlobalModule.js'; import { AnnouncementService } from '@/core/AnnouncementService.js'; -import type { MiAnnouncement, AnnouncementsRepository, AnnouncementReadsRepository, UsersRepository, MiUser } from '@/models/_.js'; +import type { + AnnouncementReadsRepository, + AnnouncementsRepository, + MiAnnouncement, + MiUser, + UsersRepository, +} from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { genAidx } from '@/misc/id/aidx.js'; import { CacheService } from '@/core/CacheService.js'; diff --git a/packages/backend/test/unit/DriveService.ts b/packages/backend/test/unit/DriveService.ts index 7234da2e36..64397a1a4f 100644 --- a/packages/backend/test/unit/DriveService.ts +++ b/packages/backend/test/unit/DriveService.ts @@ -6,7 +6,13 @@ process.env.NODE_ENV = 'test'; import { Test } from '@nestjs/testing'; -import { DeleteObjectCommandOutput, DeleteObjectCommand, NoSuchKey, InvalidObjectState, S3Client } from '@aws-sdk/client-s3'; +import { + DeleteObjectCommand, + DeleteObjectCommandOutput, + InvalidObjectState, + NoSuchKey, + S3Client, +} from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; import { GlobalModule } from '@/GlobalModule.js'; import { DriveService } from '@/core/DriveService.js'; diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts index 34200899d4..cddc374f9a 100644 --- a/packages/backend/test/unit/FetchInstanceMetadataService.ts +++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts @@ -55,7 +55,8 @@ describe('FetchInstanceMetadataService', () => { return { fetch: jest.fn() }; } else if (token === DI.redis) { return mockRedis; - }}) + } + }) .compile(); app.enableShutdownHooks(); diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts index de0b31488c..f3717d73cd 100644 --- a/packages/backend/test/unit/FileInfoService.ts +++ b/packages/backend/test/unit/FileInfoService.ts @@ -10,7 +10,7 @@ import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; -import { describe, beforeAll, afterAll, test } from '@jest/globals'; +import { afterAll, beforeAll, describe, test } from '@jest/globals'; import { GlobalModule } from '@/GlobalModule.js'; import { FileInfoService } from '@/core/FileInfoService.js'; //import { DI } from '@/di-symbols.js'; diff --git a/packages/backend/test/unit/MetaService.ts b/packages/backend/test/unit/MetaService.ts index ab30f48283..c4c7f21913 100644 --- a/packages/backend/test/unit/MetaService.ts +++ b/packages/backend/test/unit/MetaService.ts @@ -6,15 +6,13 @@ process.env.NODE_ENV = 'test'; import { jest } from '@jest/globals'; -import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import { GlobalModule } from '@/GlobalModule.js'; -import type { MetasRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { MetaService } from '@/core/MetaService.js'; import { CoreModule } from '@/core/CoreModule.js'; -import type { DataSource } from 'typeorm'; import type { TestingModule } from '@nestjs/testing'; +import type { DataSource } from 'typeorm'; describe('MetaService', () => { let app: TestingModule; diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index 9879eb8e3e..46613c29c8 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -11,7 +11,7 @@ import { Test } from '@nestjs/testing'; import * as lolex from '@sinonjs/fake-timers'; import { GlobalModule } from '@/GlobalModule.js'; import { RoleService } from '@/core/RoleService.js'; -import type { MiRole, RolesRepository, RoleAssignmentsRepository, UsersRepository, MiUser } from '@/models/_.js'; +import type { MiRole, MiUser, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { MetaService } from '@/core/MetaService.js'; import { genAidx } from '@/misc/id/aidx.js'; diff --git a/packages/backend/test/unit/S3Service.ts b/packages/backend/test/unit/S3Service.ts index c1eafc96b7..2ffc99380d 100644 --- a/packages/backend/test/unit/S3Service.ts +++ b/packages/backend/test/unit/S3Service.ts @@ -6,7 +6,13 @@ process.env.NODE_ENV = 'test'; import { Test } from '@nestjs/testing'; -import { UploadPartCommand, CompleteMultipartUploadCommand, CreateMultipartUploadCommand, S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; +import { + CompleteMultipartUploadCommand, + CreateMultipartUploadCommand, + PutObjectCommand, + S3Client, + UploadPartCommand, +} from '@aws-sdk/client-s3'; import { mockClient } from 'aws-sdk-client-mock'; import { GlobalModule } from '@/GlobalModule.js'; import { CoreModule } from '@/core/CoreModule.js'; diff --git a/packages/backend/test/unit/misc/id.ts b/packages/backend/test/unit/misc/id.ts index 59783a9fa1..1498c075aa 100644 --- a/packages/backend/test/unit/misc/id.ts +++ b/packages/backend/test/unit/misc/id.ts @@ -4,13 +4,13 @@ */ import { ulid } from 'ulid'; -import { describe, test, expect } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { aidRegExp, genAid, parseAid } from '@/misc/id/aid.js'; import { aidxRegExp, genAidx, parseAidx } from '@/misc/id/aidx.js'; import { genMeid, meidRegExp, parseMeid } from '@/misc/id/meid.js'; import { genMeidg, meidgRegExp, parseMeidg } from '@/misc/id/meidg.js'; import { genObjectId, objectIdRegExp, parseObjectId } from '@/misc/id/object-id.js'; -import { ulidRegExp, parseUlid } from '@/misc/id/ulid.js'; +import { parseUlid, ulidRegExp } from '@/misc/id/ulid.js'; describe('misc:id', () => { test('aid', () => { diff --git a/packages/backend/test/unit/misc/others.ts b/packages/backend/test/unit/misc/others.ts index b16d26d866..caa815b3df 100644 --- a/packages/backend/test/unit/misc/others.ts +++ b/packages/backend/test/unit/misc/others.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { describe, test, expect } from '@jest/globals'; +import { describe, expect, test } from '@jest/globals'; import { contentDisposition } from '@/misc/content-disposition.js'; describe('misc:content-disposition', () => { diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 7c9428d476..2b232a0a5d 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -5,7 +5,7 @@ import * as assert from 'node:assert'; import { readFile } from 'node:fs/promises'; -import { isAbsolute, basename } from 'node:path'; +import { basename, isAbsolute } from 'node:path'; import { randomUUID } from 'node:crypto'; import { inspect } from 'node:util'; import WebSocket, { ClientOptions } from 'ws'; @@ -68,7 +68,11 @@ export const failedApiCall = async (request: ApiRequest, assertion: { return res.body; }; -const request = async (path: string, params: any, me?: UserToken): Promise<{ status: number, headers: Headers, body: any }> => { +const request = async (path: string, params: any, me?: UserToken): Promise<{ + status: number, + headers: Headers, + body: any +}> => { const bodyAuth: Record = {}; const headers: Record = { 'Content-Type': 'application/json', @@ -275,7 +279,11 @@ interface UploadOptions { * Upload file * @param user User */ -export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{ status: number, headers: Headers, body: misskey.Endpoints['drive/files/create']['res'] | null }> => { +export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadOptions = {}): Promise<{ + status: number, + headers: Headers, + body: misskey.Endpoints['drive/files/create']['res'] | null +}> => { const absPath = path == null ? new URL('resources/Lenna.jpg', import.meta.url) : isAbsolute(path.toString()) @@ -426,8 +434,8 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde ]; const body = - jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : - htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : + jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : + htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : null; return { @@ -557,3 +565,34 @@ export function sleep(msec: number) { }, msec); }); } + +export async function sendEnvUpdateRequest(params: { key: string, value?: string }) { + const res = await fetch( + `http://localhost:${port + 1000}/env`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(params), + }, + ); + + if (res.status !== 200) { + throw new Error('server env update failed.'); + } +} + +export async function sendEnvResetRequest() { + const res = await fetch( + `http://localhost:${port + 1000}/env-reset`, + { + method: 'POST', + body: JSON.stringify({}), + }, + ); + + if (res.status !== 200) { + throw new Error('server env update failed.'); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28cfe3222f..d0f74de843 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -112,10 +112,10 @@ importers: version: 10.2.10(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/core': specifier: 10.2.10 - version: 10.2.10(@nestjs/common@10.2.10)(reflect-metadata@0.1.14)(rxjs@7.8.1) + version: 10.2.10(@nestjs/common@10.2.10)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) '@nestjs/testing': specifier: 10.2.10 - version: 10.2.10(@nestjs/common@10.2.10)(@nestjs/core@10.2.10) + version: 10.2.10(@nestjs/common@10.2.10)(@nestjs/core@10.2.10)(@nestjs/platform-express@10.3.0) '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 @@ -496,6 +496,9 @@ importers: '@misskey-dev/eslint-plugin': specifier: ^1.0.0 version: 1.0.0(@typescript-eslint/eslint-plugin@6.14.0)(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.1)(eslint@8.56.0) + '@nestjs/platform-express': + specifier: ^10.3.0 + version: 10.3.0(@nestjs/common@10.2.10)(@nestjs/core@10.2.10) '@simplewebauthn/typescript-types': specifier: 8.3.4 version: 8.3.4 @@ -640,6 +643,9 @@ importers: execa: specifier: 8.0.1 version: 8.0.1 + fkill: + specifier: ^9.0.0 + version: 9.0.0 jest: specifier: 29.7.0 version: 29.7.0(@types/node@20.10.5) @@ -649,6 +655,9 @@ importers: nodemon: specifier: 3.0.2 version: 3.0.2 + pid-port: + specifier: ^1.0.0 + version: 1.0.0 simple-oauth2: specifier: 5.0.0 version: 5.0.0 @@ -4878,7 +4887,6 @@ packages: /@lukeed/csprng@1.0.1: resolution: {integrity: sha512-uSvJdwQU5nK+Vdf6zxcWAY2A8r7uqe+gePwLWzJ+fsQehq18pc0I2hJKwypZ2aLM90+Er9u1xn4iLJPZ+xlL4g==} engines: {node: '>=8'} - dev: false /@lukeed/ms@2.0.1: resolution: {integrity: sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA==} @@ -5132,9 +5140,8 @@ packages: rxjs: 7.8.1 tslib: 2.6.2 uid: 2.0.2 - dev: false - /@nestjs/core@10.2.10(@nestjs/common@10.2.10)(reflect-metadata@0.1.14)(rxjs@7.8.1): + /@nestjs/core@10.2.10(@nestjs/common@10.2.10)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1): resolution: {integrity: sha512-+ckOI6BPi2ZMHikT9MCG4ctHDc4OnjhoIytrn7f2AYMMXI4bnutJhqyQKc30VDka5x3Wq6QAD57pgSP7y+JjJg==} requiresBuild: true peerDependencies: @@ -5153,6 +5160,7 @@ packages: optional: true dependencies: '@nestjs/common': 10.2.10(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/platform-express': 10.3.0(@nestjs/common@10.2.10)(@nestjs/core@10.2.10) '@nuxtjs/opencollective': 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -5163,9 +5171,24 @@ packages: uid: 2.0.2 transitivePeerDependencies: - encoding - dev: false - /@nestjs/testing@10.2.10(@nestjs/common@10.2.10)(@nestjs/core@10.2.10): + /@nestjs/platform-express@10.3.0(@nestjs/common@10.2.10)(@nestjs/core@10.2.10): + resolution: {integrity: sha512-E4hUW48bYv8OHbP9XQg6deefmXb0pDSSuE38SdhA0mJ37zGY7C5EqqBUdlQk4ttfD+OdnbIgJ1zOokT6dd2d7A==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + dependencies: + '@nestjs/common': 10.2.10(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/core': 10.2.10(@nestjs/common@10.2.10)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) + body-parser: 1.20.2 + cors: 2.8.5 + express: 4.18.2 + multer: 1.4.4-lts.1 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + + /@nestjs/testing@10.2.10(@nestjs/common@10.2.10)(@nestjs/core@10.2.10)(@nestjs/platform-express@10.3.0): resolution: {integrity: sha512-IVLUnPz/+fkBtPATYfqTIP+phN9yjkXejmj+JyhmcfPJZpxBmD1i9VSMqa4u54l37j0xkGPscQ0IXpbhqMYUKw==} peerDependencies: '@nestjs/common': ^10.0.0 @@ -5179,7 +5202,8 @@ packages: optional: true dependencies: '@nestjs/common': 10.2.10(reflect-metadata@0.1.14)(rxjs@7.8.1) - '@nestjs/core': 10.2.10(@nestjs/common@10.2.10)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/core': 10.2.10(@nestjs/common@10.2.10)(@nestjs/platform-express@10.3.0)(reflect-metadata@0.1.14)(rxjs@7.8.1) + '@nestjs/platform-express': 10.3.0(@nestjs/common@10.2.10)(@nestjs/core@10.2.10) tslib: 2.6.2 dev: false @@ -5249,7 +5273,6 @@ packages: node-fetch: 2.7.0 transitivePeerDependencies: - encoding - dev: false /@one-ini/wasm@0.1.1: resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} @@ -9164,6 +9187,14 @@ packages: clean-stack: 2.2.0 indent-string: 4.0.0 + /aggregate-error@5.0.0: + resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} + engines: {node: '>=18'} + dependencies: + clean-stack: 5.2.0 + indent-string: 5.0.0 + dev: true + /ajv-draft-04@1.0.0(ajv@8.12.0): resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -9268,6 +9299,9 @@ packages: engines: {node: '>= 6.0.0'} dev: false + /append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + /aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} requiresBuild: true @@ -9806,7 +9840,6 @@ packages: unpipe: 1.0.0 transitivePeerDependencies: - supports-color - dev: false /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -9952,7 +9985,6 @@ packages: engines: {node: '>=10.16.0'} dependencies: streamsearch: 1.1.0 - dev: false /bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} @@ -10290,6 +10322,13 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + /clean-stack@5.2.0: + resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==} + engines: {node: '>=14.16'} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -10534,7 +10573,6 @@ packages: inherits: 2.0.4 readable-stream: 2.3.7 typedarray: 0.0.6 - dev: true /config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -10545,7 +10583,6 @@ packages: /consola@2.15.3: resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} - dev: false /console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} @@ -10611,6 +10648,13 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + /cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + /crc-32@1.2.2: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} @@ -11636,7 +11680,6 @@ packages: /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - dev: false /escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} @@ -12058,6 +12101,21 @@ packages: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + /execa@6.1.0: + resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 3.0.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + /execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -12252,7 +12310,6 @@ packages: /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - dev: false /fast-uri@2.2.0: resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==} @@ -12470,6 +12527,18 @@ packages: semver-regex: 4.0.5 dev: false + /fkill@9.0.0: + resolution: {integrity: sha512-MdYSsbdCaIRjzo5edthZtWmEZVMfr1qrtYZUHIdO3swCE+CoZA8S5l0s4jDsYlTa9ZiXv0pTgpzE7s4N8NeUOA==} + engines: {node: '>=18'} + dependencies: + aggregate-error: 5.0.0 + execa: 8.0.1 + pid-port: 1.0.0 + process-exists: 5.0.0 + ps-list: 8.1.1 + taskkill: 5.0.0 + dev: true + /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -13298,6 +13367,11 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + /human-signals@3.0.1: + resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} + engines: {node: '>=12.20.0'} + dev: true + /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -13362,6 +13436,11 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -13893,7 +13972,6 @@ packages: /iterare@1.2.1: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} - dev: false /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} @@ -15437,6 +15515,18 @@ packages: resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} dev: true + /multer@1.4.4-lts.1: + resolution: {integrity: sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==} + engines: {node: '>= 6.0.0'} + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + /multi-integer-range@3.0.0: resolution: {integrity: sha512-uQzynjVJ8F7x5wjaK0g4Ybhy2TvO/pk96+YHyS5g1W4GuUEV6HMebZ8HcRwWgKIRCUT2MLbM5uCKwYcAqkS+8Q==} dev: false @@ -16230,7 +16320,6 @@ packages: /path-to-regexp@3.2.0: resolution: {integrity: sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==} - dev: false /path-to-regexp@6.2.1: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} @@ -16366,6 +16455,13 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + /pid-port@1.0.0: + resolution: {integrity: sha512-LSNBeKChRPA4Xlrs6+zV588G1hSrFvANtPV5rt/5MPfSPK3V9XPWxx1d29svsrOjngT9ifLisXWCLS7DvO9ZhQ==} + engines: {node: '>=18'} + dependencies: + execa: 8.0.1 + dev: true + /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -16922,6 +17018,13 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: false + /process-exists@5.0.0: + resolution: {integrity: sha512-6QPRh5fyHD8MaXr4GYML8K/YY0Sq5dKHGIOrAKS3cYpHQdmygFCcijIu1dVoNKAZ0TWAMoeh8KDK9dF8auBkJA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + ps-list: 8.1.1 + dev: true + /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -16993,6 +17096,11 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true + /ps-list@8.1.1: + resolution: {integrity: sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /ps-tree@1.2.0: resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} engines: {node: '>= 0.10'} @@ -17258,7 +17366,6 @@ packages: http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - dev: false /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} @@ -17563,7 +17670,6 @@ packages: /reflect-metadata@0.1.14: resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} - dev: false /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} @@ -18546,7 +18652,6 @@ packages: /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - dev: false /streamx@2.15.0: resolution: {integrity: sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==} @@ -18855,6 +18960,13 @@ packages: mkdirp: 1.0.4 yallist: 4.0.0 + /taskkill@5.0.0: + resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==} + engines: {node: '>=14.16'} + dependencies: + execa: 6.1.0 + dev: true + /telejson@7.2.0: resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==} dependencies: @@ -19288,7 +19400,6 @@ packages: /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - dev: true /typeorm@0.3.17(ioredis@5.3.2)(pg@8.11.3): resolution: {integrity: sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==} @@ -19401,7 +19512,6 @@ packages: engines: {node: '>=8'} dependencies: '@lukeed/csprng': 1.0.1 - dev: false /ulid@2.3.0: resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==}