Files
bookorbit/scripts/e2e/suite-registry.mjs
T
neon b50b8da56c feat(metadata): add external HTTP metadata providers
Register book-metadata-provider services by address, with no code change per
provider; Settings lists ready-made ones to install. Ranking prefers a record of
the book's own medium. LubimyCzytac moves out to its own provider and Aladin,
whose API closes, is retired; their ids stay. Adds migrations 0129 and 0130.
See docs/METADATA_PROVIDERS.md.

Ref #1405
2026-10-23 06:11:04 +00:00

1363 lines
50 KiB
JavaScript

const TEST_RESULTS_DIR = "../test-results/server";
export const E2E_GLOBAL_CHANGE_PATHS = Object.freeze([
".github/workflows/ci.yml",
".github/workflows/e2e.yml",
".github/workflows/e2e-runner.yml",
"Dockerfile",
"docker-compose*.yml",
"docker/**",
]);
const SHARED_DB_AND_HELPER_PATHS = Object.freeze(["server/src/db/schema/**", "scripts/e2e/**", "scripts/db/**"]);
const SHARED_AUTH_TYPE_PATHS = Object.freeze(["packages/types/src/auth.ts", "packages/types/src/permissions.ts"]);
const SHARED_TYPES_PATHS = Object.freeze(["packages/types/src/**"]);
export const E2E_SUITES = Object.freeze({
"djvu-reader": {
id: "djvu-reader",
name: "DjVuLibre Reader",
timeout: 30,
lane: "full",
description: "Native decoding, OCR, authenticated cache revalidation, paged progress and reader preference isolation",
vitestTarget: "test/djvu-reader.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/djvu-reader-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/reader/djvu/**",
"server/src/modules/djvu/**",
"client/src/features/reader/**",
"server/test/djvu-reader.e2e-spec.ts",
"server/test/e2e/djvu-fixture.ts",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"read-aloud-delivery": {
id: "read-aloud-delivery",
name: "Read-aloud Delivery",
timeout: 30,
lane: "full",
description: "Variant byte stability, profile isolation, Kobo artifacts and replacement, and released-client settings semantics",
vitestTarget: "test/read-aloud-delivery.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/read-aloud-delivery-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book/delivery*",
"server/src/modules/kobo/**",
"server/src/modules/koreader/**",
"server/src/modules/opds/**",
"server/src/modules/email/**",
"server/test/read-aloud-delivery.e2e-spec.ts",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"guard-mechanics": {
id: "guard-mechanics",
name: "Guard Mechanics",
timeout: 30,
lane: "smoke",
description: "Guard mechanics suite - verifies @Public/@RequirePermission wiring without a real DB",
vitestTarget: "test/guard-mechanics.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/guard-mechanics-e2e-junit.xml`,
prepareDedicatedDatabase: false,
useDedicatedDatabase: false,
changedPaths: [
"server/src/common/guards/**",
"server/src/common/decorators/**",
"server/src/common/types/**",
"server/src/modules/auth/**",
"server/src/modules/user/**",
"server/src/modules/role/**",
"server/src/**",
"server/test/guard-mechanics.e2e-spec.ts",
"server/test/e2e/**",
...SHARED_AUTH_TYPE_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"scanner-scenarios": {
id: "scanner-scenarios",
name: "Scanner Scenarios",
timeout: 45,
lane: "full",
description: "Scanner scenario matrix",
vitestTarget: "test/scanner-scenarios.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/scanner-scenarios-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-cover-store/**",
"server/src/modules/metadata/cover-slot-reconciler.service.ts",
"server/src/modules/scanner/**",
"server/test/scanner-scenarios.e2e-spec.ts",
"server/test/e2e/scanner/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"scanner-file-operations": {
id: "scanner-file-operations",
name: "Scanner File Operations",
timeout: 60,
lane: "full",
description: "Scanner file operation matrix",
vitestTarget: "test/scanner-file-operations.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/scanner-file-operations-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-cover-store/**",
"server/src/modules/metadata/cover-slot-reconciler.service.ts",
"server/src/modules/scanner/**",
"server/test/scanner-file-operations.e2e-spec.ts",
"server/test/e2e/scanner/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"audiobook-track-order": {
id: "audiobook-track-order",
name: "Audiobook Track Order",
timeout: 45,
lane: "full",
description: "Audiobook playback order matches file names after overlapping scans and added tracks",
vitestTarget: "test/audiobook-track-order.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/audiobook-track-order-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/common/utils/audio-track-order.utils.ts",
"server/src/common/utils/book-media.utils.ts",
"server/src/db/audio-track-order.ts",
"server/src/modules/audiobook/**",
"server/src/modules/scanner/**",
"server/src/modules/upload/**",
"server/test/audiobook-track-order.e2e-spec.ts",
"server/test/e2e/scanner/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"auth-session-security": {
id: "auth-session-security",
name: "Auth Session Security",
timeout: 50,
lane: "full",
description: "Auth session security suite",
vitestTarget: "test/auth-session-security.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/auth-session-security-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"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/test/auth-session-security.e2e-spec.ts",
"server/test/e2e/app-harness.ts",
".github/workflows/e2e-runner.yml",
...SHARED_AUTH_TYPE_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"auth-recovery-oidc-logout": {
id: "auth-recovery-oidc-logout",
name: "Auth Recovery OIDC Logout",
timeout: 50,
lane: "full",
description: "Auth recovery and OIDC logout suite",
vitestTarget: "test/auth-recovery-oidc-logout.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/auth-recovery-oidc-logout-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/auth/**",
"server/src/modules/user/**",
"server/src/modules/email/**",
"server/src/modules/metadata/**",
"server/test/auth-recovery-oidc-logout.e2e-spec.ts",
"server/test/e2e/app-harness.ts",
".github/workflows/e2e-runner.yml",
"packages/types/src/auth.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"book-dock-ingest-finalize": {
id: "book-dock-ingest-finalize",
name: "Book Dock Ingest Finalize",
timeout: 45,
lane: "full",
description: "Book Dock ingest and finalize suite",
vitestTarget: "test/book-dock-ingest-finalize.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/book-dock-ingest-finalize-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-cover-store/**",
"server/src/modules/book-dock/**",
"server/src/modules/upload/**",
"server/src/modules/metadata/**",
"server/test/book-dock-ingest-finalize.e2e-spec.ts",
"server/test/e2e/book-dock/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"metadata-write": {
id: "metadata-write",
name: "Metadata Write",
timeout: 60,
lane: "full",
description: "Metadata write operations suite",
vitestTarget: "test/metadata-write.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/metadata-write-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-cover-store/**",
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/src/modules/file-write/**",
"server/src/modules/metadata/**",
"server/src/modules/app-settings/**",
"server/test/metadata-write.e2e-spec.ts",
"server/test/e2e/metadata-write/**",
"packages/types/src/file-write.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"metadata-cache": {
id: "metadata-cache",
name: "Metadata Cache",
timeout: 60,
lane: "full",
description: "Metadata provider cache repository, executor and admin API suite",
vitestTarget: "test/metadata-cache.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/metadata-cache-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/metadata-cache/**",
"server/src/common/provider-cache/**",
"server/src/modules/metadata-fetch/**",
"server/src/modules/authors/metadata/**",
"server/src/modules/app-info/**",
"server/test/metadata-cache.e2e-spec.ts",
".github/workflows/e2e-runner.yml",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"metadata-http-providers": {
id: "metadata-http-providers",
name: "External Metadata Providers",
timeout: 90,
lane: "full",
description: "External HTTP metadata providers: registration, search, refresh, ids, ratings and purge",
vitestTarget: "test/metadata-http-providers.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/metadata-http-providers-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/metadata-http-provider/**",
"server/src/modules/metadata-fetch/**",
"server/src/modules/metadata-preferences/**",
"server/src/modules/book/**",
"server/src/modules/book-dock/**",
"server/src/modules/book-metadata-fetch/**",
"server/test/metadata-http-providers.e2e-spec.ts",
".github/workflows/e2e-runner.yml",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"metadata-lock": {
id: "metadata-lock",
name: "Metadata Lock",
timeout: 60,
lane: "full",
description: "Metadata lock end-to-end suite",
vitestTarget: "test/metadata-lock.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/metadata-lock-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book/**",
"server/src/modules/book-metadata-lock/**",
"server/src/modules/book-metadata-fetch/**",
"server/src/modules/metadata-fetch/**",
"server/src/modules/metadata-preferences/**",
"server/src/modules/cover/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/scanner/**",
"server/src/modules/library/**",
"server/src/modules/auth/**",
"server/src/modules/app-settings/**",
"server/test/metadata-lock.e2e-spec.ts",
"server/test/e2e/metadata-lock/**",
".github/workflows/e2e-runner.yml",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"migration-booklore": {
id: "migration-booklore",
name: "Migration Booklore",
timeout: 70,
lane: "full",
description: "Booklore migration end-to-end suite",
vitestTarget: "test/migration-booklore.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/migration-booklore-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/migration/**",
"server/src/modules/book-cover-store/**",
"server/test/migration-booklore.e2e-spec.ts",
"server/test/e2e/migration-booklore/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"migration-audiobookshelf": {
id: "migration-audiobookshelf",
name: "Migration Audiobookshelf",
timeout: 90,
lane: "full",
description: "Audiobookshelf live API and real-backup migration end-to-end suite",
vitestTarget: "test/migration-audiobookshelf.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/migration-audiobookshelf-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
requiresDocker: true,
changedPaths: [
"server/src/modules/migration/**",
"server/test/migration-audiobookshelf.e2e-spec.ts",
"server/test/e2e/migration-audiobookshelf/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"migration-calibre-web-automated": {
id: "migration-calibre-web-automated",
name: "Migration Calibre-Web Automated",
timeout: 120,
lane: "full",
description: "Calibre-Web Automated stopped-snapshot migration end-to-end suite",
vitestTarget: "test/migration-calibre-web-automated.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/migration-calibre-web-automated-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
requiresDocker: true,
changedPaths: [
"server/src/modules/migration/**",
"server/test/migration-calibre-web-automated.e2e-spec.ts",
"server/test/e2e/migration-calibre-web-automated/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"authorization-matrix": {
id: "authorization-matrix",
name: "Authorization Matrix",
timeout: 60,
lane: "full",
description: "Authorization matrix suite",
vitestTarget: "test/authorization-matrix.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/authorization-matrix-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/**",
"server/src/modules/book-cover-store/**",
"server/test/authorization-matrix.e2e-spec.ts",
"server/test/e2e/slot-cover-artifacts.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"catalog-visibility": {
id: "catalog-visibility",
name: "Catalog Visibility",
timeout: 60,
lane: "full",
description: "Catalog metadata library and content-filter visibility suite",
vitestTarget: "test/catalog-visibility.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/catalog-visibility-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/catalog/**",
"server/src/modules/library/**",
"server/src/common/utils/content-filter-sql.utils.ts",
"server/test/catalog-visibility.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"dashboard-random": {
id: "dashboard-random",
name: "Dashboard Random Scroller",
timeout: 60,
lane: "full",
description: "Dashboard random scroller repository integration suite",
vitestTarget: "test/dashboard-random.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/dashboard-random-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/dashboard/**",
"server/test/dashboard-random.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/dashboard.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"audiobook-chapter-revision": {
id: "audiobook-chapter-revision",
name: "Audiobook Chapter Revision",
timeout: 60,
lane: "full",
description: "Audiobook chapter edits keep released-client playback writes and locks working",
vitestTarget: "test/audiobook-chapter-revision.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/audiobook-chapter-revision-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/audiobook/**",
"server/src/modules/audiobook-chapters/**",
"server/src/modules/chapter-editor/**",
"server/src/modules/metadata/metadata.service.ts",
"server/src/modules/book/**",
"server/src/modules/book-metadata-lock/**",
"server/src/common/utils/audiobook-chapters.utils.ts",
"server/test/audiobook-chapter-revision.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/audiobook.ts",
"packages/types/src/metadata-lock.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"audiobook-chapter-write": {
id: "audiobook-chapter-write",
name: "Audiobook Chapter Write",
timeout: 120,
lane: "full",
description: "Edited audiobook chapters are written into real audio files and read back unchanged",
vitestTarget: "test/audiobook-chapter-write.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/audiobook-chapter-write-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/chapter-editor/**",
"server/src/modules/file-write/**",
"server/src/modules/metadata/extractors/audio-chapter-merge.ts",
"server/src/common/utils/audiobook-chapters.utils.ts",
"server/test/audiobook-chapter-write.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/audiobook.ts",
"packages/types/src/file-write.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"chapter-health": {
id: "chapter-health",
name: "Chapter Health",
timeout: 60,
lane: "full",
description: "Chapter health categories, library scoping, and the bulk Audible lookup queue and worker",
vitestTarget: "test/chapter-health.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/chapter-health-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/chapter-health/**",
"server/src/modules/chapter-editor/**",
"server/src/modules/audiobook-chapters/**",
"server/src/modules/book-metadata-lock/**",
"server/src/modules/library/**",
"server/src/common/utils/audiobook-chapters.utils.ts",
"server/test/chapter-health.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/chapter-health.ts",
"packages/types/src/audiobook.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"dashboard-continue-listening": {
id: "dashboard-continue-listening",
name: "Dashboard Continue Listening",
timeout: 60,
lane: "full",
description: "Dashboard continue-listening completion regression suite",
vitestTarget: "test/dashboard-continue-listening.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/dashboard-continue-listening-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/dashboard/**",
"server/src/modules/book/**",
"server/src/modules/user-book-status/**",
"server/test/dashboard-continue-listening.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/dashboard.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"book-requests": {
id: "book-requests",
name: "Book Requests",
timeout: 90,
lane: "full",
description: "Book request lifecycle, dedupe, ownership, and plugin-route authorization suite",
vitestTarget: "test/book-requests.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/book-requests-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-request/**",
"server/src/modules/book-dock/**",
"server/src/modules/library/**",
"server/test/book-requests.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/book-request.ts",
"packages/types/src/book-request-automation.ts",
"packages/types/src/book-request-destination.ts",
"packages/types/src/indexer.ts",
"packages/types/src/download-client.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"author-books-collapse": {
id: "author-books-collapse",
name: "Author Books Collapse",
timeout: 60,
lane: "full",
description: "Author page series collapsing, and the row and book counts it reports",
vitestTarget: "test/author-books-collapse.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/author-books-collapse-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/authors/**",
"server/src/modules/book/book.repository.ts",
"server/src/modules/book/book-read.service.ts",
"server/test/author-books-collapse.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/author.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"achievement-hints": {
id: "achievement-hints",
name: "Achievement Hints",
timeout: 60,
lane: "full",
description: "Achievement how-to-get-it hints: real queries, library scoping, and per-user isolation",
vitestTarget: "test/achievement-hints.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/achievement-hints-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/achievement/**",
"server/test/achievement-hints.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/achievement.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"series-next-book": {
id: "series-next-book",
name: "Series Next Book",
timeout: 60,
lane: "full",
description: "Series next-readable-book resolution suite",
vitestTarget: "test/series-next-book.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/series-next-book-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/series/**",
"server/test/series-next-book.e2e-spec.ts",
"server/test/e2e/authorization-matrix/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/series.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"series-index-migration": {
id: "series-index-migration",
name: "Series Index Migration",
timeout: 60,
lane: "full",
description: "Legacy series index upgrade compatibility suite",
vitestTarget: "test/series-index-migration.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/series-index-migration-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/db/migrations/**",
"server/src/scripts/migrate.ts",
"server/src/scripts/series-index-migration-compatibility.ts",
"server/test/series-index-migration.e2e-spec.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"reading-attempts": {
id: "reading-attempts",
name: "Reading Attempts",
timeout: 120,
lane: "full",
description: "Reading attempt lifecycle, external read identity, and Hardcover read ownership suite",
vitestTarget: "test/reading-attempts.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/reading-attempts-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/user-book-status/**",
"server/src/modules/hardcover/**",
"server/src/modules/dashboard/**",
"server/test/reading-attempts.e2e-spec.ts",
"server/test/e2e/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/book.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"reading-history": {
id: "reading-history",
name: "Reading History",
timeout: 120,
lane: "full",
description: "Reading history ordering, rereads, ratings, deleted-book retention and ownership suite",
vitestTarget: "test/reading-history.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/reading-history-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/reading-history/**",
"server/src/modules/user-book-status/**",
"server/src/modules/dashboard/**",
"server/src/db/reading-attempt-retention.ts",
"server/src/db/book-file-hash-history.ts",
"server/test/reading-history.e2e-spec.ts",
"server/test/e2e/**",
".github/workflows/e2e-runner.yml",
"packages/types/src/reading-history.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"book-api-contract": {
id: "book-api-contract",
name: "Book API Contract",
timeout: 60,
lane: "full",
description: "Book API contract suite",
vitestTarget: "test/book-api-contract.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/book-api-contract-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/library/**",
"server/src/modules/collection/**",
"server/src/modules/auth/**",
"server/src/modules/user/**",
"server/test/book-api-contract.e2e-spec.ts",
"server/test/e2e/slot-cover-artifacts.ts",
"server/test/e2e/book-api-contract/**",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"jump-buckets-invariant": {
id: "jump-buckets-invariant",
name: "Jump Buckets Invariant",
timeout: 45,
lane: "full",
description: "Asserts jump-bucket indexes match real listing offsets for every eligible sort, direction, and collapse mode",
vitestTarget: "test/jump-buckets-invariant.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/jump-buckets-invariant-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/src/db/book-author-sort-key.ts",
"server/test/jump-buckets-invariant.e2e-spec.ts",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"browse-facets-invariant": {
id: "browse-facets-invariant",
name: "Browse Facets Invariant",
timeout: 45,
lane: "full",
description: "Asserts library browse facet counts match the listing totals for the same filter, search, and format",
vitestTarget: "test/browse-facets-invariant.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/browse-facets-invariant-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/test/browse-facets-invariant.e2e-spec.ts",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"server-connection-identity": {
id: "server-connection-identity",
name: "Server Connection Identity",
timeout: 60,
lane: "full",
description: "Public installation identity and concurrent singleton persistence",
vitestTarget: "test/server-connection-identity.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/server-connection-identity-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/server-identity/**",
"server/src/modules/app-info/**",
"server/test/server-connection-identity.e2e-spec.ts",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"app-settings-oidc-contract": {
id: "app-settings-oidc-contract",
name: "App Settings OIDC Contract",
timeout: 60,
lane: "full",
description: "App settings OIDC contract suite",
vitestTarget: "test/app-settings-oidc-contract.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/app-settings-oidc-contract-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/app-settings/**",
"server/src/modules/auth/**",
"server/src/modules/user/**",
"server/src/modules/metadata/**",
"server/test/app-settings-oidc-contract.e2e-spec.ts",
"server/test/e2e/app-settings/**",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"library-admin-workflows": {
id: "library-admin-workflows",
name: "Library Admin Workflows",
timeout: 60,
lane: "full",
description: "Library admin workflows suite",
vitestTarget: "test/library-admin-workflows.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/library-admin-workflows-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/library/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/auth/**",
"server/src/modules/user/**",
"server/src/modules/role/**",
"server/test/library-admin-workflows.e2e-spec.ts",
"server/test/e2e/slot-cover-artifacts.ts",
"server/test/e2e/library/**",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"missing-resources": {
id: "missing-resources",
name: "Missing Resources",
timeout: 60,
lane: "full",
description: "Missing Resources cover sweep and cleanup suite",
vitestTarget: "test/missing-resources.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/missing-resources-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/maintenance/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/test/missing-resources.e2e-spec.ts",
"server/test/e2e/metadata-write/**",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"reader-format-delivery": {
id: "reader-format-delivery",
name: "Reader Format Delivery",
timeout: 60,
lane: "full",
description: "Reader format delivery suite",
vitestTarget: "test/reader-format-delivery.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/reader-format-delivery-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/src/modules/reader-preferences/**",
"server/src/modules/annotation/**",
"server/src/modules/bookmark/**",
"server/test/reader-format-delivery.e2e-spec.ts",
"server/test/e2e/reader-format-delivery/**",
"packages/types/src/reader-settings.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"opds-auth-catalog": {
id: "opds-auth-catalog",
name: "OPDS Auth Catalog",
timeout: 45,
lane: "full",
description: "OPDS auth and catalog suite",
vitestTarget: "test/opds-auth-catalog.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/opds-auth-catalog-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/opds/**",
"server/src/modules/book/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/library/**",
"server/src/modules/collection/**",
"server/src/modules/lens/**",
"server/src/modules/user/**",
"server/src/modules/auth/**",
"server/src/modules/app-settings/**",
"server/test/opds-auth-catalog.e2e-spec.ts",
"server/test/e2e/opds/**",
"server/test/e2e/**",
".github/workflows/e2e-runner.yml",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"email-lifecycle": {
id: "email-lifecycle",
name: "Email Lifecycle",
timeout: 45,
lane: "full",
description: "Email lifecycle suite",
vitestTarget: "test/email-lifecycle.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/email-lifecycle-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/email/**",
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/src/modules/auth/**",
"server/src/modules/cover/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/scanner/**",
"server/src/modules/seed/**",
"server/test/email-lifecycle.e2e-spec.ts",
"server/test/e2e/email/**",
"server/test/e2e/**",
"client/src/features/email/**",
"client/src/router/index.ts",
"client/src/features/settings/SettingsHeader.vue",
"client/src/views/HomeView.vue",
"client/src/views/CollectionView.vue",
"client/src/views/LensView.vue",
"client/src/features/book/components/BookCoverCard.vue",
"client/src/features/book/components/BookListRow.vue",
...SHARED_TYPES_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"reader-state-isolation": {
id: "reader-state-isolation",
name: "Reader State Isolation",
timeout: 45,
lane: "full",
description: "Reader state isolation suite",
vitestTarget: "test/reader-state-isolation.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/reader-state-isolation-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/bookmark/**",
"server/src/modules/annotation/**",
"server/src/modules/reader-preferences/**",
"server/src/modules/reading-session/**",
"server/src/modules/book/**",
"server/src/modules/library/**",
"server/src/modules/scanner/**",
"server/src/modules/user-book-status/**",
"server/src/scripts/db-prepare-e2e.ts",
"server/test/reader-state-isolation.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
"packages/types/src/reader-settings.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-annotation-exchange": {
id: "koreader-annotation-exchange",
name: "KOReader Annotation Exchange",
timeout: 45,
lane: "full",
description: "KOReader annotation exchange suite",
vitestTarget: "test/koreader-annotation-exchange.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-annotation-exchange-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/annotation/**",
"server/src/modules/koreader/**",
"server/src/modules/position-converter/**",
"server/test/koreader-annotation-exchange.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-bookmark-exchange": {
id: "koreader-bookmark-exchange",
name: "KOReader Bookmark Exchange",
timeout: 45,
lane: "full",
description: "KOReader two-way bookmark (dogear) exchange suite",
vitestTarget: "test/koreader-bookmark-exchange.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-bookmark-exchange-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/bookmark/**",
"server/src/modules/koreader/**",
"server/src/modules/position-converter/**",
"server/test/koreader-bookmark-exchange.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-bulk-manifest": {
id: "koreader-bulk-manifest",
name: "KOReader Bulk Manifest Scale",
timeout: 45,
lane: "full",
description: "KOReader bulk manifest pagination and index support at 25,000 books",
vitestTarget: "test/koreader-bulk-manifest.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-bulk-manifest-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/src/modules/opds/opds-book.service.ts",
"server/src/db/schema/books.ts",
"server/test/koreader-bulk-manifest.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-audio-only-catalog": {
id: "koreader-audio-only-catalog",
name: "KOReader Audiobook-Only Catalog",
timeout: 20,
lane: "full",
description: "KOReader catalog setting that hides books whose only content files are audio",
vitestTarget: "test/koreader-audio-only-catalog.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-audio-only-catalog-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/src/modules/opds/**",
"server/src/modules/dashboard/dashboard.repository.ts",
"server/src/modules/dashboard/dashboard.service.ts",
"server/src/modules/smart-scope/smart-scope.service.ts",
"server/src/common/utils/audio-only-book-sql.utils.ts",
"server/test/koreader-audio-only-catalog.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-page-stats": {
id: "koreader-page-stats",
name: "KOReader Page Stats Derivation",
timeout: 45,
lane: "full",
description: "KOReader incremental page-stat derivation suite",
vitestTarget: "test/koreader-page-stats.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-page-stats-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/src/common/utils/reading-daily-stats.utils.ts",
"server/test/koreader-page-stats.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-progress-reset": {
id: "koreader-progress-reset",
name: "KOReader Progress Reset Propagation",
timeout: 45,
lane: "full",
description: "KOReader reset propagation: a cleared position survives a device replaying its old one",
vitestTarget: "test/koreader-progress-reset.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-progress-reset-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/src/modules/book/book.repository.ts",
"server/src/modules/reading-state/**",
"server/src/db/schema/koreader.ts",
"server/test/koreader-progress-reset.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-progress-position": {
id: "koreader-progress-position",
name: "KOReader Progress Position Routing",
timeout: 45,
lane: "full",
description: "KOReader progress position routing into cfi or pageNumber per book format",
vitestTarget: "test/koreader-progress-position.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-progress-position-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/src/modules/book/book.service.ts",
"server/src/db/schema/reader.ts",
"server/test/koreader-progress-position.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-readaloud-progress": {
id: "koreader-readaloud-progress",
name: "KOReader Read-Along Sibling Progress",
timeout: 45,
lane: "full",
description: "KOReader and web reader positions carried between an EPUB and its Storyteller read-along copy",
vitestTarget: "test/koreader-readaloud-progress.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-readaloud-progress-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/src/modules/book/audiobook-ebook-progress-sync.service.ts",
"server/src/modules/book/book.repository.ts",
"server/src/modules/book/book.service.ts",
"server/src/modules/position-converter/**",
"server/src/modules/reader/epub/**",
"server/src/common/utils/primary-file-selection.utils.ts",
"server/test/koreader-readaloud-progress.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"read-aloud-jobs": {
id: "read-aloud-jobs",
name: "Read-Aloud Jobs",
timeout: 60,
lane: "full",
description:
"Read-along generation lifecycle against a fake worker: publish, review and re-sync, replace in place, ownership, retry, cancel, resume",
vitestTarget: "test/read-aloud-jobs.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/read-aloud-jobs-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/read-aloud/**",
"server/src/modules/upload/generated-book-file.service.ts",
"server/src/modules/upload/upload.service.ts",
"server/src/db/schema/read-aloud.ts",
"server/test/read-aloud-jobs.e2e-spec.ts",
"server/test/e2e/read-aloud/**",
"server/test/e2e/reader-state-isolation/**",
"packages/types/src/read-aloud.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"koreader-file-naming": {
id: "koreader-file-naming",
name: "KOReader File Naming",
timeout: 30,
lane: "full",
description: "KOReader file naming persistence and authorization suite",
vitestTarget: "test/koreader-file-naming.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/koreader-file-naming-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/koreader/**",
"server/test/koreader-file-naming.e2e-spec.ts",
"packages/types/src/pattern-resolver.ts",
...SHARED_AUTH_TYPE_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"annotations-hub": {
id: "annotations-hub",
name: "Annotations Hub",
timeout: 45,
lane: "full",
description: "Annotations hub suite",
vitestTarget: "test/annotations-hub.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/annotations-hub-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/annotation/**",
"server/src/modules/position-converter/**",
"server/test/annotations-hub.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"book-notebook": {
id: "book-notebook",
name: "Book Notebook",
timeout: 45,
lane: "full",
description: "Book journal, annotation stars and reading order, bookmark edits and colour names suite",
vitestTarget: "test/book-notebook.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/book-notebook-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-journal/**",
"server/src/modules/annotation/**",
"server/src/modules/bookmark/**",
"server/src/modules/user-preferences/**",
"server/src/modules/app-info/**",
"server/test/book-notebook.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
...SHARED_TYPES_PATHS,
],
},
"notebook-hub": {
id: "notebook-hub",
name: "Notebook Hub",
timeout: 45,
lane: "full",
description: "Library-wide notebook: entries, overview, books, review decks, on this day and trash suite",
vitestTarget: "test/notebook-hub.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/notebook-hub-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/notebook/**",
"server/src/modules/annotation/**",
"server/src/modules/book-journal/**",
"server/src/modules/bookmark/**",
"server/src/modules/user-book-note/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/library/**",
"server/src/common/utils/content-filter-sql.utils.ts",
"server/src/common/utils/accent-insensitive-search.utils.ts",
"server/test/notebook-hub.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
...SHARED_TYPES_PATHS,
],
},
"kobo-annotation-sync": {
id: "kobo-annotation-sync",
name: "Kobo Annotation Sync",
timeout: 60,
lane: "full",
description: "Kobo annotation three-way sync suite",
vitestTarget: "test/kobo-annotation-sync.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/kobo-annotation-sync-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/annotation/**",
"server/src/modules/kobo/**",
"server/src/modules/koreader/**",
"server/src/modules/position-converter/**",
"server/test/kobo-annotation-sync.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
"packages/types/src/kobo.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"kobo-multi-device-sync": {
id: "kobo-multi-device-sync",
name: "Kobo Multi-Device Sync",
timeout: 60,
lane: "full",
description: "Kobo device-owned library snapshot suite",
vitestTarget: "test/kobo-multi-device-sync.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/kobo-multi-device-sync-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/kobo/**",
"server/src/modules/book/**",
"server/src/modules/file-write/**",
"server/test/kobo-multi-device-sync.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
"packages/types/src/book.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"kobo-koreader-download": {
id: "kobo-koreader-download",
name: "Kobo KOReader Download Identity",
timeout: 60,
lane: "full",
description: "Kobo delivered hashes, KOReader matching, cache recovery and access isolation",
vitestTarget: "test/kobo-koreader-download.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/kobo-koreader-download-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/kobo/**",
"server/src/modules/koreader/**",
"server/src/common/utils/file-hash.utils.ts",
"server/test/kobo-koreader-download.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"kobo-reading-time-reconciliation": {
id: "kobo-reading-time-reconciliation",
name: "Kobo Reading Time Reconciliation",
timeout: 45,
lane: "full",
description: "Kobo counter-derived estimate and measured session reconciliation suite",
vitestTarget: "test/kobo-reading-time-reconciliation.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/kobo-reading-time-reconciliation-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/kobo/**",
"server/src/modules/reading-session/**",
"server/src/common/utils/reading-daily-stats.utils.ts",
"server/test/kobo-reading-time-reconciliation.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"kobo-cover-identity": {
id: "kobo-cover-identity",
name: "Kobo Cover Identity",
timeout: 60,
lane: "full",
description: "Kobo CoverImageId stability across metadata edits and cover changes",
vitestTarget: "test/kobo-cover-identity.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/kobo-cover-identity-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/kobo/**",
"server/src/modules/cover/**",
"server/src/modules/book-cover-store/**",
"server/src/modules/metadata/**",
"server/test/kobo-cover-identity.e2e-spec.ts",
"server/test/e2e/reader-state-isolation/**",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"users-admin-lifecycle": {
id: "users-admin-lifecycle",
name: "Users Admin Lifecycle",
timeout: 50,
lane: "full",
description: "Users admin lifecycle suite",
vitestTarget: "test/users-admin-lifecycle.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/users-admin-lifecycle-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/user/**",
"server/src/modules/auth/**",
"server/src/common/guards/**",
"server/src/common/decorators/**",
"server/src/common/types/**",
"server/test/users-admin-lifecycle.e2e-spec.ts",
"server/test/e2e/users-admin-lifecycle/**",
".github/workflows/e2e-runner.yml",
...SHARED_AUTH_TYPE_PATHS,
...SHARED_DB_AND_HELPER_PATHS,
],
},
"file-rename": {
id: "file-rename",
name: "File Rename",
timeout: 120,
lane: "full",
description: "Bulk file rename end-to-end suite covering all library/file structure permutations",
vitestTarget: "test/file-rename.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/file-rename-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-cover-store/**",
"server/src/modules/metadata/cover-slot-reconciler.service.ts",
"server/src/modules/library/**",
"server/src/modules/file-write/**",
"server/src/modules/scanner/**",
"server/src/modules/app-settings/**",
"server/test/file-rename.e2e-spec.ts",
"server/test/e2e/file-rename/**",
"packages/types/src/file-write.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
"book-move": {
id: "book-move",
name: "Book Move",
timeout: 120,
lane: "full",
description: "Cross-library book move suite covering preview classification, collision policies, and file relocation",
vitestTarget: "test/book-move.e2e-spec.ts",
junitOutput: `${TEST_RESULTS_DIR}/book-move-e2e-junit.xml`,
prepareDedicatedDatabase: true,
useDedicatedDatabase: true,
changedPaths: [
"server/src/modules/book-move/**",
"server/src/modules/scanner/**",
"server/src/modules/app-settings/**",
"server/test/book-move.e2e-spec.ts",
"server/test/e2e/metadata-write/**",
"packages/types/src/book-move.ts",
"packages/types/src/book-selection.ts",
...SHARED_DB_AND_HELPER_PATHS,
],
},
});
export function listE2ESuites() {
return Object.values(E2E_SUITES);
}
export function getE2ESuite(suiteId) {
return E2E_SUITES[suiteId] ?? null;
}