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-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, ], }, "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, ], }, "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, ], }, "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, ], }, "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-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, ], }, "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-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; }