mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
ci: standardize E2E naming across workflows and scripts
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
name: E2E - App Smoke
|
||||
run-name: ${{ format('E2E - App Smoke - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "server/src/**"
|
||||
- "server/test/app-smoke.e2e-spec.ts"
|
||||
- "server/src/db/schema/**"
|
||||
- "packages/types/src/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/src/**"
|
||||
- "server/test/app-smoke.e2e-spec.ts"
|
||||
- "server/src/db/schema/**"
|
||||
- "packages/types/src/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
app-smoke:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: app-smoke
|
||||
check-name: E2E - App Smoke
|
||||
artifact-name: e2e-app-smoke-report
|
||||
job-timeout-minutes: 30
|
||||
@@ -0,0 +1,48 @@
|
||||
name: E2E - Auth Recovery OIDC Logout
|
||||
run-name: ${{ format('E2E - Auth Recovery OIDC Logout - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "server/src/modules/auth/**"
|
||||
- "server/src/modules/user/**"
|
||||
- "server/src/modules/email/**"
|
||||
- "server/src/modules/metadata/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "server/test/auth-recovery-oidc-logout.e2e-spec.ts"
|
||||
- "server/test/e2e/app-harness.ts"
|
||||
- "packages/types/src/auth.ts"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/src/modules/auth/**"
|
||||
- "server/src/modules/user/**"
|
||||
- "server/src/modules/email/**"
|
||||
- "server/src/modules/metadata/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "server/test/auth-recovery-oidc-logout.e2e-spec.ts"
|
||||
- "server/test/e2e/app-harness.ts"
|
||||
- "packages/types/src/auth.ts"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
auth-recovery-oidc-logout:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: auth-recovery-oidc-logout
|
||||
check-name: E2E - Auth Recovery OIDC Logout
|
||||
artifact-name: e2e-auth-recovery-oidc-logout-report
|
||||
job-timeout-minutes: 50
|
||||
@@ -0,0 +1,54 @@
|
||||
name: E2E - Auth Session Security
|
||||
run-name: ${{ format('E2E - Auth Session Security - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "server/src/modules/auth/**"
|
||||
- "server/src/modules/user/**"
|
||||
- "server/src/modules/role/**"
|
||||
- "server/src/common/guards/**"
|
||||
- "server/src/common/decorators/**"
|
||||
- "server/src/common/types/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "server/test/auth-session-security.e2e-spec.ts"
|
||||
- "server/test/e2e/app-harness.ts"
|
||||
- "packages/types/src/auth.ts"
|
||||
- "packages/types/src/permissions.ts"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/src/modules/auth/**"
|
||||
- "server/src/modules/user/**"
|
||||
- "server/src/modules/role/**"
|
||||
- "server/src/common/guards/**"
|
||||
- "server/src/common/decorators/**"
|
||||
- "server/src/common/types/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "server/test/auth-session-security.e2e-spec.ts"
|
||||
- "server/test/e2e/app-harness.ts"
|
||||
- "packages/types/src/auth.ts"
|
||||
- "packages/types/src/permissions.ts"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
auth-session-security:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: auth-session-security
|
||||
check-name: E2E - Auth Session Security
|
||||
artifact-name: e2e-auth-session-security-report
|
||||
job-timeout-minutes: 50
|
||||
@@ -0,0 +1,42 @@
|
||||
name: E2E - Authorization Matrix
|
||||
run-name: ${{ format('E2E - Authorization Matrix - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "server/src/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "server/test/authorization-matrix.e2e-spec.ts"
|
||||
- "server/test/e2e/authorization-matrix/**"
|
||||
- "packages/types/src/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/src/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "server/test/authorization-matrix.e2e-spec.ts"
|
||||
- "server/test/e2e/authorization-matrix/**"
|
||||
- "packages/types/src/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
authorization-matrix:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: authorization-matrix
|
||||
check-name: E2E - Authorization Matrix
|
||||
artifact-name: e2e-authorization-matrix-report
|
||||
job-timeout-minutes: 60
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Email Lifecycle E2E
|
||||
run-name: ${{ format('Email Lifecycle E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Email Lifecycle
|
||||
run-name: ${{ format('E2E - Email Lifecycle - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -61,10 +61,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
email-lifecycle-e2e:
|
||||
email-lifecycle:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: email-lifecycle
|
||||
check-name: Server Email Lifecycle E2E
|
||||
artifact-name: email-lifecycle-e2e-report
|
||||
check-name: E2E - Email Lifecycle
|
||||
artifact-name: e2e-email-lifecycle-report
|
||||
job-timeout-minutes: 45
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
name: Metadata Write E2E
|
||||
run-name: ${{ format('Metadata Write E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Metadata Write
|
||||
run-name: ${{ format('E2E - Metadata Write - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
vitest-args:
|
||||
description: "Optional vitest args (examples: --shard=1/2, --testNamePattern=\"concurrency hardening\")"
|
||||
description: 'Optional vitest args (examples: --shard=1/2, --testNamePattern="concurrency hardening")'
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
@@ -45,11 +45,11 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
metadata-write-e2e:
|
||||
metadata-write:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: metadata-write
|
||||
check-name: Server Metadata Write E2E
|
||||
artifact-name: metadata-write-e2e-report
|
||||
check-name: E2E - Metadata Write
|
||||
artifact-name: e2e-metadata-write-report
|
||||
job-timeout-minutes: 60
|
||||
vitest-args: ${{ github.event_name == 'workflow_dispatch' && inputs.vitest-args || '' }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: OPDS Auth Catalog E2E
|
||||
run-name: ${{ format('OPDS Auth Catalog E2E - {0}', github.ref_name) }}
|
||||
name: E2E - OPDS Auth Catalog
|
||||
run-name: ${{ format('E2E - OPDS Auth Catalog - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -47,10 +47,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
opds-auth-catalog-e2e:
|
||||
opds-auth-catalog:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: opds-auth-catalog
|
||||
check-name: Server OPDS Auth Catalog E2E
|
||||
artifact-name: opds-auth-catalog-e2e-report
|
||||
check-name: E2E - OPDS Auth Catalog
|
||||
artifact-name: e2e-opds-auth-catalog-report
|
||||
job-timeout-minutes: 45
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Reader State Isolation E2E
|
||||
run-name: ${{ format('Reader State Isolation E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Reader State Isolation
|
||||
run-name: ${{ format('E2E - Reader State Isolation - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -47,10 +47,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
reader-state-isolation-e2e:
|
||||
reader-state-isolation:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: reader-state-isolation
|
||||
check-name: Server Reader State Isolation E2E
|
||||
artifact-name: reader-state-isolation-e2e-report
|
||||
check-name: E2E - Reader State Isolation
|
||||
artifact-name: e2e-reader-state-isolation-report
|
||||
job-timeout-minutes: 45
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
suite-id:
|
||||
description: "E2E suite id from scripts/test/e2e-suites.mjs (e.g. scanner)"
|
||||
description: "E2E suite id from scripts/test/e2e-suites.mjs (e.g. scanner-scenarios)"
|
||||
required: true
|
||||
type: string
|
||||
check-name:
|
||||
@@ -72,9 +72,9 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ inputs.vitest-args }}" ]; then
|
||||
pnpm run test:e2e -- ${{ inputs.suite-id }} ${{ inputs.vitest-args }}
|
||||
pnpm run e2e:run -- ${{ inputs.suite-id }} ${{ inputs.vitest-args }}
|
||||
else
|
||||
pnpm run test:e2e -- ${{ inputs.suite-id }}
|
||||
pnpm run e2e:run -- ${{ inputs.suite-id }}
|
||||
fi
|
||||
|
||||
- name: Publish test report annotations
|
||||
|
||||
+12
-10
@@ -1,5 +1,5 @@
|
||||
name: Scanner File Ops E2E
|
||||
run-name: ${{ format('Scanner File Ops E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Scanner File Operations
|
||||
run-name: ${{ format('E2E - Scanner File Operations - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -8,19 +8,21 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- "server/src/modules/scanner/**"
|
||||
- "server/test/scanner*"
|
||||
- "server/test/e2e/**"
|
||||
- "server/test/scanner-file-operations.e2e-spec.ts"
|
||||
- "server/test/e2e/scanner/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/src/modules/scanner/**"
|
||||
- "server/test/scanner*"
|
||||
- "server/test/e2e/**"
|
||||
- "server/test/scanner-file-operations.e2e-spec.ts"
|
||||
- "server/test/e2e/scanner/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -31,10 +33,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
scanner-file-ops-e2e:
|
||||
scanner-file-operations:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: scanner-file-ops
|
||||
check-name: Server Scanner File Ops E2E
|
||||
artifact-name: scanner-file-ops-e2e-report
|
||||
suite-id: scanner-file-operations
|
||||
check-name: E2E - Scanner File Operations
|
||||
artifact-name: e2e-scanner-file-operations-report
|
||||
job-timeout-minutes: 60
|
||||
@@ -1,24 +1,26 @@
|
||||
name: Scanner E2E
|
||||
run-name: ${{ format('Scanner E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Scanner Scenarios
|
||||
run-name: ${{ format('E2E - Scanner Scenarios - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "server/src/modules/scanner/**"
|
||||
- "server/test/scanner*"
|
||||
- "server/test/e2e/**"
|
||||
- "server/test/scanner-scenarios.e2e-spec.ts"
|
||||
- "server/test/e2e/scanner/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "server/src/modules/scanner/**"
|
||||
- "server/test/scanner*"
|
||||
- "server/test/e2e/**"
|
||||
- "server/test/scanner-scenarios.e2e-spec.ts"
|
||||
- "server/test/e2e/scanner/**"
|
||||
- "server/src/db/schema/**"
|
||||
- "scripts/test/**"
|
||||
- "scripts/db/**"
|
||||
- ".github/workflows/e2e-runner.yml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -29,10 +31,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
scanner-e2e:
|
||||
scanner-scenarios:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: scanner
|
||||
check-name: Server Scanner E2E
|
||||
artifact-name: scanner-e2e-report
|
||||
suite-id: scanner-scenarios
|
||||
check-name: E2E - Scanner Scenarios
|
||||
artifact-name: e2e-scanner-scenarios-report
|
||||
job-timeout-minutes: 45
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Staging Ingest Finalize E2E
|
||||
run-name: ${{ format('Staging Ingest Finalize E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Staging Ingest Finalize
|
||||
run-name: ${{ format('E2E - Staging Ingest Finalize - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -33,10 +33,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
staging-ingest-finalize-e2e:
|
||||
staging-ingest-finalize:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: staging-ingest-finalize
|
||||
check-name: Server Staging Ingest Finalize E2E
|
||||
artifact-name: staging-ingest-finalize-e2e-report
|
||||
check-name: E2E - Staging Ingest Finalize
|
||||
artifact-name: e2e-staging-ingest-finalize-report
|
||||
job-timeout-minutes: 45
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Users Admin Lifecycle E2E
|
||||
run-name: ${{ format('Users Admin Lifecycle E2E - {0}', github.ref_name) }}
|
||||
name: E2E - Users Admin Lifecycle
|
||||
run-name: ${{ format('E2E - Users Admin Lifecycle - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -43,10 +43,10 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
users-admin-lifecycle-e2e:
|
||||
users-admin-lifecycle:
|
||||
uses: ./.github/workflows/e2e-runner.yml
|
||||
with:
|
||||
suite-id: users-admin-lifecycle
|
||||
check-name: Server Users Admin Lifecycle E2E
|
||||
artifact-name: users-admin-lifecycle-e2e-report
|
||||
check-name: E2E - Users Admin Lifecycle
|
||||
artifact-name: e2e-users-admin-lifecycle-report
|
||||
job-timeout-minutes: 50
|
||||
|
||||
+5
-5
@@ -118,9 +118,9 @@ pnpm verify # run all checks before pushing
|
||||
Other useful commands:
|
||||
|
||||
```bash
|
||||
pnpm quick # faster checks while coding
|
||||
pnpm verify:fast # lint + typecheck + tests (pre-push gate)
|
||||
pnpm db:reset # wipe and reseed local database
|
||||
pnpm doctor # environment health check
|
||||
pnpm e2e:list # list available e2e suite ids
|
||||
```
|
||||
|
||||
---
|
||||
@@ -205,9 +205,9 @@ Use a **draft PR** early if you want feedback on direction before the work is do
|
||||
The project has two automatic gates you should be aware of:
|
||||
|
||||
- **pre-commit:** runs `lint-staged` on your staged files. ESLint and Prettier are applied automatically. You do not need to format or lint manually before committing.
|
||||
- **pre-push:** runs `pnpm quick` (lint + typecheck + tests). If this fails, the push is blocked. Fix the errors before pushing.
|
||||
- **pre-push:** runs `pnpm verify:fast` (lint + typecheck + tests). If this fails, the push is blocked. Fix the errors before pushing.
|
||||
|
||||
`pnpm quick` is a fast check but does not include the e2e smoke suite. Before opening a PR, run the full gate:
|
||||
`pnpm verify:fast` is a fast check but does not include the `app-smoke` e2e suite. Before opening a PR, run the full gate:
|
||||
|
||||
```bash
|
||||
pnpm verify
|
||||
@@ -216,7 +216,7 @@ pnpm verify
|
||||
Before marking your PR ready for review:
|
||||
|
||||
- [ ] Linked to an approved issue
|
||||
- [ ] `pnpm verify` passes locally (includes e2e smoke, stricter than pre-push)
|
||||
- [ ] `pnpm verify` passes locally (includes `app-smoke`, stricter than pre-push)
|
||||
- [ ] You ran the full stack and manually verified the change works
|
||||
- [ ] UI changes include a screenshot or screen recording
|
||||
- [ ] Tests are included per the expectations above
|
||||
|
||||
+52
-84
@@ -114,21 +114,21 @@ Opens Drizzle Studio in your browser for browsing and editing tables directly.
|
||||
pnpm run test # all tests (server + client)
|
||||
pnpm run test:server # server unit tests only
|
||||
pnpm run test:client # client unit tests only
|
||||
pnpm run test:e2e -- all # run all e2e suites sequentially
|
||||
pnpm run test:e2e -- smoke # e2e smoke suite (default DB)
|
||||
pnpm run test:e2e -- scanner # scanner e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e -- scanner-file-ops # scanner file operation e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e -- staging-ingest-finalize # staging ingest/finalize e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e -- opds-auth-catalog # OPDS auth/catalog e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e -- reader-state-isolation # reader state isolation e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e -- email-lifecycle # email lifecycle e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e -- users-admin-lifecycle # users admin lifecycle e2e suite (dedicated projectx_e2e DB)
|
||||
pnpm run test:e2e:all # alias for "pnpm run test:e2e -- all"
|
||||
pnpm run test:e2e:opds-auth-catalog # alias for "pnpm run test:e2e -- opds-auth-catalog"
|
||||
pnpm run test:e2e:reader-state-isolation # alias for "pnpm run test:e2e -- reader-state-isolation"
|
||||
pnpm run test:e2e:email-lifecycle # alias for "pnpm run test:e2e -- email-lifecycle"
|
||||
pnpm run test:e2e:users-admin-lifecycle # alias for "pnpm run test:e2e -- users-admin-lifecycle"
|
||||
pnpm run test:e2e:list # list all supported e2e suite ids
|
||||
pnpm run e2e:run -- all # run all e2e suites sequentially
|
||||
pnpm run e2e:run -- app-smoke # app smoke suite (default DB)
|
||||
pnpm run e2e:run -- scanner-scenarios # scanner scenario suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- scanner-file-operations # scanner file operation suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- auth-session-security # auth session security suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- auth-recovery-oidc-logout # auth recovery and OIDC logout suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- staging-ingest-finalize # staging ingest/finalize suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- metadata-write # metadata write suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- authorization-matrix # authorization matrix suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- opds-auth-catalog # OPDS auth/catalog suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- reader-state-isolation # reader state isolation suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- email-lifecycle # email lifecycle suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:run -- users-admin-lifecycle # users admin lifecycle suite (dedicated projectx_e2e DB)
|
||||
pnpm run e2e:all # shortcut for running all suites
|
||||
pnpm run e2e:list # list supported suite ids
|
||||
```
|
||||
|
||||
Watch mode while working on a specific area:
|
||||
@@ -140,95 +140,63 @@ cd server && pnpm test:watch
|
||||
Run a focused scanner scenario:
|
||||
|
||||
```bash
|
||||
pnpm run test:e2e -- scanner --testNamePattern=book-per-folder-disc-folder-flattening
|
||||
pnpm run e2e:run -- scanner-scenarios --testNamePattern=book-per-folder-disc-folder-flattening
|
||||
```
|
||||
|
||||
### E2E runner architecture
|
||||
|
||||
- All suite metadata lives in `scripts/test/e2e-suites.mjs` (suite id, spec file, JUnit output, DB prep mode).
|
||||
- Local and CI use the same command: `pnpm run test:e2e -- <suite-id>`.
|
||||
- Use `all` as a composite suite id to run every configured suite in order.
|
||||
- Dedicated-db suites auto-start local PostgreSQL when `CI != true`, then reset and migrate the e2e database through `pnpm run db:prepare:e2e`.
|
||||
- Local and CI use the same command: `pnpm run e2e:run -- <suite-id>`.
|
||||
- Use `all` as a composite suite id to run every configured suite in order, or use `pnpm run e2e:all`.
|
||||
- Dedicated-db suites auto-start local PostgreSQL when `CI != true`, then reset and migrate the e2e database through `pnpm run e2e:db:prepare`.
|
||||
- JUnit outputs are written to `test-results/server/`.
|
||||
|
||||
### Scanner e2e details
|
||||
### E2E suite details
|
||||
|
||||
- `pnpm run test:e2e -- scanner` prepares and migrates a dedicated e2e database (`projectx_e2e`) on each run.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `scanner-e2e-junit.xml`
|
||||
- `scanner-e2e-scenarios.json`
|
||||
All suites write JUnit XML to `test-results/server/`. Dedicated-db suites also auto-start PostgreSQL locally (when needed) and use the `projectx_e2e` database.
|
||||
|
||||
### Scanner file operation e2e details
|
||||
|
||||
- `pnpm run test:e2e -- scanner-file-ops` prepares and migrates the same dedicated e2e database (`projectx_e2e`) before running.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `scanner-file-ops-e2e-junit.xml`
|
||||
- `scanner-file-ops-e2e-scenarios.json`
|
||||
|
||||
### Staging ingest/finalize e2e details
|
||||
|
||||
- `pnpm run test:e2e -- staging-ingest-finalize` prepares and migrates the dedicated e2e database (`projectx_e2e`) before running.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `staging-ingest-finalize-e2e-junit.xml`
|
||||
- `staging-ingest-finalize-e2e-scenarios.json`
|
||||
|
||||
### OPDS auth/catalog e2e details
|
||||
|
||||
- `pnpm run test:e2e -- opds-auth-catalog` prepares and migrates the dedicated e2e database (`projectx_e2e`) before running.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `opds-auth-catalog-e2e-junit.xml`
|
||||
- `opds-auth-catalog-e2e-scenarios.json`
|
||||
|
||||
### Reader state isolation e2e details
|
||||
|
||||
- `pnpm run test:e2e -- reader-state-isolation` prepares and migrates the dedicated e2e database (`projectx_e2e`) before running.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `reader-state-isolation-e2e-junit.xml`
|
||||
- `reader-state-isolation-e2e-scenarios.json`
|
||||
|
||||
### Email lifecycle e2e details
|
||||
|
||||
- `pnpm run test:e2e -- email-lifecycle` prepares and migrates the dedicated e2e database (`projectx_e2e`) before running.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `email-lifecycle-e2e-junit.xml`
|
||||
- `email-lifecycle-e2e-scenarios.json`
|
||||
|
||||
### Users admin lifecycle e2e details
|
||||
|
||||
- `pnpm run test:e2e -- users-admin-lifecycle` prepares and migrates the dedicated e2e database (`projectx_e2e`) before running.
|
||||
- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed.
|
||||
- Results are written to `test-results/server/`:
|
||||
- `users-admin-lifecycle-e2e-junit.xml`
|
||||
- `users-admin-lifecycle-e2e-scenarios.json`
|
||||
| Suite id | DB mode | JUnit output | Extra artifacts |
|
||||
| --------------------------- | ------------ | ----------------------------------------- | -------------------------------------------- |
|
||||
| `app-smoke` | default-db | `app-smoke-e2e-junit.xml` | none |
|
||||
| `scanner-scenarios` | dedicated-db | `scanner-scenarios-e2e-junit.xml` | `scanner-scenarios-e2e-scenarios.json` |
|
||||
| `scanner-file-operations` | dedicated-db | `scanner-file-operations-e2e-junit.xml` | `scanner-file-operations-e2e-scenarios.json` |
|
||||
| `auth-session-security` | dedicated-db | `auth-session-security-e2e-junit.xml` | none |
|
||||
| `auth-recovery-oidc-logout` | dedicated-db | `auth-recovery-oidc-logout-e2e-junit.xml` | none |
|
||||
| `staging-ingest-finalize` | dedicated-db | `staging-ingest-finalize-e2e-junit.xml` | `staging-ingest-finalize-e2e-scenarios.json` |
|
||||
| `metadata-write` | dedicated-db | `metadata-write-e2e-junit.xml` | `metadata-write-e2e-scenarios.json` |
|
||||
| `authorization-matrix` | dedicated-db | `authorization-matrix-e2e-junit.xml` | none |
|
||||
| `opds-auth-catalog` | dedicated-db | `opds-auth-catalog-e2e-junit.xml` | `opds-auth-catalog-e2e-scenarios.json` |
|
||||
| `reader-state-isolation` | dedicated-db | `reader-state-isolation-e2e-junit.xml` | `reader-state-isolation-e2e-scenarios.json` |
|
||||
| `email-lifecycle` | dedicated-db | `email-lifecycle-e2e-junit.xml` | `email-lifecycle-e2e-scenarios.json` |
|
||||
| `users-admin-lifecycle` | dedicated-db | `users-admin-lifecycle-e2e-junit.xml` | `users-admin-lifecycle-e2e-scenarios.json` |
|
||||
|
||||
### E2E in CI (how to trigger)
|
||||
|
||||
All suite workflows call the reusable `E2E Runner (reusable)` workflow, which runs:
|
||||
|
||||
```bash
|
||||
pnpm run test:e2e -- <suite-id>
|
||||
pnpm run e2e:run -- <suite-id>
|
||||
```
|
||||
|
||||
| Workflow | Suite id | Triggered by |
|
||||
| --------------------------- | ------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| Scanner E2E | `scanner` | `workflow_dispatch`, `push` (scanner-related paths), `pull_request` (same paths) |
|
||||
| Scanner File Ops E2E | `scanner-file-ops` | `workflow_dispatch`, nightly schedule (`0 4 * * *`), `push`, `pull_request` |
|
||||
| Staging Ingest Finalize E2E | `staging-ingest-finalize` | `workflow_dispatch`, `push` (staging-related paths), `pull_request` (same paths) |
|
||||
| OPDS Auth Catalog E2E | `opds-auth-catalog` | `workflow_dispatch`, `push` (opds-related paths), `pull_request` (same paths) |
|
||||
| Reader State Isolation E2E | `reader-state-isolation` | `workflow_dispatch`, `push` (reader-state-related paths), `pull_request` (same paths) |
|
||||
| Email Lifecycle E2E | `email-lifecycle` | `workflow_dispatch`, `push` (email-related paths), `pull_request` (same paths) |
|
||||
| Users Admin Lifecycle E2E | `users-admin-lifecycle` | `workflow_dispatch`, `push` (users/auth-related paths), `pull_request` (same paths) |
|
||||
| Workflow name | Suite id | Triggered by |
|
||||
| --------------------------------- | --------------------------- | --------------------------------------------------------------------------- |
|
||||
| `E2E - App Smoke` | `app-smoke` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Scanner Scenarios` | `scanner-scenarios` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Scanner File Operations` | `scanner-file-operations` | `workflow_dispatch`, nightly schedule (`0 4 * * *`), `push`, `pull_request` |
|
||||
| `E2E - Auth Session Security` | `auth-session-security` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Auth Recovery OIDC Logout` | `auth-recovery-oidc-logout` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Staging Ingest Finalize` | `staging-ingest-finalize` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Metadata Write` | `metadata-write` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Authorization Matrix` | `authorization-matrix` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - OPDS Auth Catalog` | `opds-auth-catalog` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Reader State Isolation` | `reader-state-isolation` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Email Lifecycle` | `email-lifecycle` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
| `E2E - Users Admin Lifecycle` | `users-admin-lifecycle` | `workflow_dispatch`, `push`, `pull_request` |
|
||||
|
||||
Manual trigger steps:
|
||||
|
||||
1. Open GitHub Actions.
|
||||
2. Select **Scanner E2E**, **Scanner File Ops E2E**, **Staging Ingest Finalize E2E**, **OPDS Auth Catalog E2E**, **Reader State Isolation E2E**, **Email Lifecycle E2E**, or **Users Admin Lifecycle E2E**.
|
||||
2. Select any `E2E - ...` workflow for the suite you want to run.
|
||||
3. Click **Run workflow**.
|
||||
|
||||
Each run uploads `test-results/server/` as an artifact and publishes JUnit annotations from `test-results/server/*-e2e-junit.xml`.
|
||||
@@ -241,7 +209,7 @@ Run before pushing:
|
||||
|
||||
```bash
|
||||
pnpm run verify:fast # lint + typecheck + tests (same as pre-push hook)
|
||||
pnpm run verify # above + e2e smoke (run before opening a PR)
|
||||
pnpm run verify # above + e2e app-smoke suite (run before opening a PR)
|
||||
```
|
||||
|
||||
Individual checks:
|
||||
|
||||
+7
-13
@@ -7,8 +7,8 @@
|
||||
"dev:client": "cd client && npm run dev -- --host",
|
||||
"dev:server": "cd server && npm run start:dev",
|
||||
"verify:fast": "pnpm run lint:check && pnpm run typecheck && pnpm run test",
|
||||
"verify": "pnpm run lint:check && pnpm run typecheck && pnpm run test && pnpm run test:e2e -- smoke",
|
||||
"verify:strict": "pnpm run format:check && pnpm run lint:check && pnpm run typecheck:full && pnpm run test && pnpm run test:e2e -- smoke",
|
||||
"verify": "pnpm run lint:check && pnpm run typecheck && pnpm run test && pnpm run e2e:run -- app-smoke",
|
||||
"verify:strict": "pnpm run format:check && pnpm run lint:check && pnpm run typecheck:full && pnpm run test && pnpm run e2e:run -- app-smoke",
|
||||
"build:client": "pnpm --filter client build",
|
||||
"build:server": "pnpm --filter server build",
|
||||
"typecheck": "pnpm run typecheck:server && pnpm run typecheck:client",
|
||||
@@ -22,16 +22,9 @@
|
||||
"test": "pnpm run test:server && pnpm run test:client",
|
||||
"test:server": "pnpm --filter server test",
|
||||
"test:client": "pnpm --filter client test:unit --run",
|
||||
"test:e2e": "node ./scripts/test/run-e2e-suite.mjs",
|
||||
"test:e2e:all": "node ./scripts/test/run-e2e-suite.mjs all",
|
||||
"test:e2e:metadata-write": "node ./scripts/test/run-e2e-suite.mjs metadata-write",
|
||||
"test:e2e:opds-auth-catalog": "node ./scripts/test/run-e2e-suite.mjs opds-auth-catalog",
|
||||
"test:e2e:metadata-write:atomicity": "node ./scripts/test/run-e2e-suite.mjs metadata-write --testNamePattern=\"atomicity failpoints\"",
|
||||
"test:e2e:metadata-write:concurrency": "node ./scripts/test/run-e2e-suite.mjs metadata-write --testNamePattern=\"concurrency hardening\"",
|
||||
"test:e2e:reader-state-isolation": "node ./scripts/test/run-e2e-suite.mjs reader-state-isolation",
|
||||
"test:e2e:email-lifecycle": "node ./scripts/test/run-e2e-suite.mjs email-lifecycle",
|
||||
"test:e2e:users-admin-lifecycle": "node ./scripts/test/run-e2e-suite.mjs users-admin-lifecycle",
|
||||
"test:e2e:list": "node ./scripts/test/run-e2e-suite.mjs --list",
|
||||
"e2e:run": "node ./scripts/test/run-e2e-suite.mjs",
|
||||
"e2e:all": "node ./scripts/test/run-e2e-suite.mjs all",
|
||||
"e2e:list": "node ./scripts/test/run-e2e-suite.mjs --list",
|
||||
"coverage": "pnpm run coverage:server && pnpm run coverage:client",
|
||||
"coverage:server": "pnpm --filter server test:cov",
|
||||
"coverage:client": "pnpm --filter client test:cov --run",
|
||||
@@ -41,7 +34,8 @@
|
||||
"db:migrate": "pnpm --filter server db:migrate",
|
||||
"db:reset": "bash ./scripts/db/reset.sh",
|
||||
"db:seed": "bash ./scripts/db/seed.sh",
|
||||
"db:prepare:e2e": "bash ./scripts/db/prepare-e2e.sh",
|
||||
"e2e:db:prepare": "bash ./scripts/db/prepare-e2e.sh",
|
||||
"e2e:db:migrate": "pnpm --filter server e2e:db:migrate",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -7,7 +7,7 @@ cd "$ROOT_DIR"
|
||||
E2E_DATABASE_URL="${E2E_DATABASE_URL:-postgres://projectx:projectx@localhost:5432/projectx_e2e}"
|
||||
|
||||
echo "Preparing dedicated e2e database..."
|
||||
DATABASE_URL="$E2E_DATABASE_URL" pnpm --filter server db:prepare:e2e
|
||||
DATABASE_URL="$E2E_DATABASE_URL" pnpm --filter server e2e:db:prepare
|
||||
|
||||
echo "Applying migrations to e2e database..."
|
||||
DATABASE_URL="$E2E_DATABASE_URL" pnpm --filter server db:migrate
|
||||
DATABASE_URL="$E2E_DATABASE_URL" pnpm --filter server e2e:db:migrate
|
||||
|
||||
+13
-13
@@ -1,27 +1,27 @@
|
||||
const TEST_RESULTS_DIR = "../test-results/server";
|
||||
|
||||
export const E2E_SUITES = Object.freeze({
|
||||
smoke: {
|
||||
id: "smoke",
|
||||
description: "Server smoke suite",
|
||||
vitestTarget: "test/app.e2e-spec.ts",
|
||||
junitOutput: `${TEST_RESULTS_DIR}/smoke-e2e-junit.xml`,
|
||||
"app-smoke": {
|
||||
id: "app-smoke",
|
||||
description: "App smoke suite",
|
||||
vitestTarget: "test/app-smoke.e2e-spec.ts",
|
||||
junitOutput: `${TEST_RESULTS_DIR}/app-smoke-e2e-junit.xml`,
|
||||
prepareDedicatedDatabase: false,
|
||||
useDedicatedDatabase: false,
|
||||
},
|
||||
scanner: {
|
||||
id: "scanner",
|
||||
"scanner-scenarios": {
|
||||
id: "scanner-scenarios",
|
||||
description: "Scanner scenario matrix",
|
||||
vitestTarget: "test/scanner.e2e-spec.ts",
|
||||
junitOutput: `${TEST_RESULTS_DIR}/scanner-e2e-junit.xml`,
|
||||
vitestTarget: "test/scanner-scenarios.e2e-spec.ts",
|
||||
junitOutput: `${TEST_RESULTS_DIR}/scanner-scenarios-e2e-junit.xml`,
|
||||
prepareDedicatedDatabase: true,
|
||||
useDedicatedDatabase: true,
|
||||
},
|
||||
"scanner-file-ops": {
|
||||
id: "scanner-file-ops",
|
||||
"scanner-file-operations": {
|
||||
id: "scanner-file-operations",
|
||||
description: "Scanner file operation matrix",
|
||||
vitestTarget: "test/scanner-file-ops.e2e-spec.ts",
|
||||
junitOutput: `${TEST_RESULTS_DIR}/scanner-file-ops-e2e-junit.xml`,
|
||||
vitestTarget: "test/scanner-file-operations.e2e-spec.ts",
|
||||
junitOutput: `${TEST_RESULTS_DIR}/scanner-file-operations-e2e-junit.xml`,
|
||||
prepareDedicatedDatabase: true,
|
||||
useDedicatedDatabase: true,
|
||||
},
|
||||
|
||||
@@ -28,17 +28,17 @@ function trimLeadingSeparator(args) {
|
||||
function printUsage() {
|
||||
const usage = [
|
||||
"Usage:",
|
||||
" pnpm run test:e2e -- <suite-id> [vitest args...]",
|
||||
" pnpm run e2e:run -- <suite-id> [vitest args...]",
|
||||
"",
|
||||
"Examples:",
|
||||
" pnpm run test:e2e -- smoke",
|
||||
" pnpm run test:e2e -- all",
|
||||
" pnpm run test:e2e -- metadata-write",
|
||||
" pnpm run test:e2e -- metadata-write --testNamePattern=\"concurrency hardening\"",
|
||||
" pnpm run test:e2e -- metadata-write --shard=1/2",
|
||||
" pnpm run test:e2e -- scanner --testNamePattern=book-per-folder-disc-folder-flattening",
|
||||
" pnpm run test:e2e -- --list",
|
||||
" pnpm run test:e2e:list",
|
||||
" pnpm run e2e:run -- app-smoke",
|
||||
" pnpm run e2e:run -- all",
|
||||
" pnpm run e2e:run -- metadata-write",
|
||||
' pnpm run e2e:run -- metadata-write --testNamePattern="concurrency hardening"',
|
||||
" pnpm run e2e:run -- metadata-write --shard=1/2",
|
||||
" pnpm run e2e:run -- scanner-scenarios --testNamePattern=book-per-folder-disc-folder-flattening",
|
||||
" pnpm run e2e:run -- --list",
|
||||
" pnpm run e2e:list",
|
||||
];
|
||||
console.log(usage.join("\n"));
|
||||
}
|
||||
@@ -122,7 +122,7 @@ async function main() {
|
||||
|
||||
if (suite.prepareDedicatedDatabase) {
|
||||
console.log(`Resetting and migrating dedicated e2e database for suite ${suite.id}...`);
|
||||
await runCommand("pnpm", ["run", "db:prepare:e2e"], { E2E_DATABASE_URL: e2eDatabaseUrl });
|
||||
await runCommand("pnpm", ["run", "e2e:db:prepare"], { E2E_DATABASE_URL: e2eDatabaseUrl });
|
||||
}
|
||||
|
||||
const junitOutput = process.env.JUNIT_OUTPUT ?? suite.junitOutput;
|
||||
|
||||
+5
-5
@@ -50,16 +50,16 @@ pnpm db:studio # open Drizzle Studio (DB browser)
|
||||
```bash
|
||||
pnpm test # unit tests
|
||||
pnpm test:watch # unit tests in watch mode
|
||||
pnpm test:e2e # smoke end-to-end test from server package
|
||||
pnpm e2e:run # app-smoke end-to-end test from server package
|
||||
pnpm test:cov # unit tests with coverage
|
||||
```
|
||||
|
||||
For suite-based e2e runs (scanner, scanner-file-ops, auth suites), run from the repository root:
|
||||
For suite-based e2e runs, run from the repository root:
|
||||
|
||||
```bash
|
||||
pnpm run test:e2e:list
|
||||
pnpm run test:e2e -- all
|
||||
pnpm run test:e2e -- scanner
|
||||
pnpm run e2e:list
|
||||
pnpm run e2e:all
|
||||
pnpm run e2e:run -- scanner-scenarios
|
||||
```
|
||||
|
||||
## Quality
|
||||
|
||||
+8
-8
@@ -16,9 +16,9 @@
|
||||
"start:prod": "node dist/main",
|
||||
"db:generate": "drizzle-kit generate --name",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:migrate:e2e": "DATABASE_URL=postgres://projectx:projectx@localhost:5432/projectx_e2e pnpm db:migrate",
|
||||
"e2e:db:migrate": "DATABASE_URL=postgres://projectx:projectx@localhost:5432/projectx_e2e pnpm db:migrate",
|
||||
"db:migrate:runtime": "node dist/scripts/migrate.js",
|
||||
"db:prepare:e2e": "tsx src/scripts/db-prepare-e2e.ts",
|
||||
"e2e:db:prepare": "tsx src/scripts/db-prepare-e2e.ts",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
"db:seed": "tsx src/scripts/db-seed.ts",
|
||||
"pretype-check": "pnpm --filter @projectx/types build",
|
||||
@@ -26,10 +26,10 @@
|
||||
"lint": "pnpm run lint:check",
|
||||
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\"",
|
||||
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "vitest run --exclude test/scanner.e2e-spec.ts --exclude test/scanner-file-ops.e2e-spec.ts",
|
||||
"test": "vitest run --exclude test/scanner-scenarios.e2e-spec.ts --exclude test/scanner-file-operations.e2e-spec.ts",
|
||||
"test:watch": "vitest",
|
||||
"test:cov": "vitest run --coverage",
|
||||
"test:e2e": "vitest run test/app.e2e-spec.ts"
|
||||
"e2e:run": "vitest run test/app-smoke.e2e-spec.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"7z-wasm": "^1.2.0",
|
||||
@@ -84,10 +84,10 @@
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.5",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@nestjs/cli": "^11.0.16",
|
||||
"@nestjs/schematics": "^11.0.9",
|
||||
"@nestjs/cli": "^11.0.17",
|
||||
"@nestjs/schematics": "^11.0.10",
|
||||
"@nestjs/testing": "^11.1.17",
|
||||
"@swc/cli": "^0.8.0",
|
||||
"@swc/cli": "^0.8.1",
|
||||
"@swc/core": "^1.15.21",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/express": "^5.0.6",
|
||||
@@ -112,7 +112,7 @@
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.57.2",
|
||||
"typescript-eslint": "^8.58.0",
|
||||
"vitest": "^4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user