Files
bookorbit/scripts/e2e/suite-registry.mjs
T
neon 58756565fc fix(kobo): preserve koreader matching for converted downloads
Register the identity of delivered bytes so Kobo conversions and audio
removal continue matching their source books in KOReader. Keep download
registration recoverable without allowing database lock waits to stall it.

Preserve manual corrections across cached device identities, make review
semantics explicit, and keep cache invalidation bounded for large libraries.
Add unit, database, lifecycle and scale regressions with one generated migration.

Closes #1697
2026-10-07 00:07:50 +00:00

1038 lines
38 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({
"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,
],
},
"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-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,
],
},
"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;
}