test: reorganize flat test files into purpose-based subdirectories (phase 6)

Group 245 flat integration tests and 25 loose unit tests into
discoverable subdirectories per spec section 6:

  integration/tools/{image,video,audio,document,data}/  (156 files)
  integration/platform/                                  (64 files)
  integration/generated/                                 (14 files)
  integration/security/                                  (10 files)

  unit/security/     (8 files, new subdir)
  unit/api/          (7 files moved in)
  unit/web/          (3 files moved in)
  unit/shared/       (6 files moved in)
  unit/image-engine/ (1 file moved in)

All moves via git mv (history preserved). Relative imports repaired
for both depth levels (platform/generated/security = +1, tools/ = +2):
static from-imports, dynamic import() calls, vi.mock() paths,
import.meta.dirname joins, and __dirname joins.

Vitest discovery unchanged (no test.include in config, recursive glob
matches subdirs, shard-by-hash unaffected). test-server.ts and
tool-route-drift.test.ts stay at integration root. fixtures/ untouched.

Parity gate: 13189 passing test names before = 13189 after (0 dropped).
This commit is contained in:
SnapOtter
2026-06-20 05:07:46 +08:00
parent 257f030c09
commit 1727a7a73e
269 changed files with 1553 additions and 619 deletions
@@ -17,10 +17,10 @@
import { TOOLS } from "@snapotter/shared"; import { TOOLS } from "@snapotter/shared";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { getRegisteredToolIds } from "../../apps/api/src/routes/tool-factory.js"; import { getRegisteredToolIds } from "../../../apps/api/src/routes/tool-factory.js";
import { TOOL_DISPLAY_MODES } from "../../apps/web/src/lib/tool-display-modes.js"; import { TOOL_DISPLAY_MODES } from "../../../apps/web/src/lib/tool-display-modes.js";
import { toolRegistry } from "../../apps/web/src/lib/tool-registry.js"; import { toolRegistry } from "../../../apps/web/src/lib/tool-registry.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
/** /**
* Tools whose contract does not fit the single-buffer process fn (multi-file, * Tools whose contract does not fit the single-buffer process fn (multi-file,
@@ -12,8 +12,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// All output formats accepted by the convert tool // All output formats accepted by the convert tool
const OUTPUT_FORMATS = [ const OUTPUT_FORMATS = [
@@ -20,8 +20,13 @@
import { existsSync, readFileSync } from "node:fs"; import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtureDir, fixtures } from "../fixtures/index.js"; import { fixtureDir, fixtures } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Format sample definitions (matches format-matrix.test.ts) // Format sample definitions (matches format-matrix.test.ts)
@@ -28,8 +28,13 @@
import { existsSync, readFileSync } from "node:fs"; import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { fixtureDir } from "../fixtures/index.js"; import { fixtureDir } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
vi.setConfig({ testTimeout: 60_000 }); vi.setConfig({ testTimeout: 60_000 });
@@ -20,8 +20,13 @@ import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtureDir, fixtures } from "../fixtures/index.js"; import { fixtureDir, fixtures } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Format definitions // Format definitions
@@ -34,8 +34,13 @@
import { existsSync, readFileSync } from "node:fs"; import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtureDir, fixtures } from "../fixtures/index.js"; import { fixtureDir, fixtures } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Format sample definitions (subset relevant to the expanded tools) // Format sample definitions (subset relevant to the expanded tools)
@@ -3,10 +3,18 @@ import { join } from "node:path";
import { TOOLS } from "@snapotter/shared"; import { TOOLS } from "@snapotter/shared";
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { getRegisteredToolIds, getToolConfig } from "../../apps/api/src/routes/tool-factory.js"; import { getRegisteredToolIds, getToolConfig } from "../../../apps/api/src/routes/tool-factory.js";
import { fixtureDir } from "../fixtures/index.js"; import { fixtureDir } from "../../fixtures/index.js";
import { defaultSettingsFor, TOOL_SETTINGS_OVERRIDES } from "../helpers/tool-default-settings.js"; import {
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; defaultSettingsFor,
TOOL_SETTINGS_OVERRIDES,
} from "../../helpers/tool-default-settings.js";
import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
/** /**
* Registry-generated tool x format matrix. * Registry-generated tool x format matrix.
@@ -2,9 +2,14 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
import { extname, join } from "node:path"; import { extname, join } from "node:path";
import { TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared"; import { TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtureDir } from "../fixtures/index.js"; import { fixtureDir } from "../../fixtures/index.js";
import { defaultSettingsFor } from "../helpers/tool-default-settings.js"; import { defaultSettingsFor } from "../../helpers/tool-default-settings.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
/** /**
* Multi-modality tool x format matrix. * Multi-modality tool x format matrix.
@@ -19,8 +19,13 @@
import { existsSync, readFileSync } from "node:fs"; import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtureDir, fixtures } from "../fixtures/index.js"; import { fixtureDir, fixtures } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Format sample definitions // Format sample definitions
@@ -3,10 +3,10 @@ import fc from "fast-check";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import type { z } from "zod"; import type { z } from "zod";
import { ZodFastCheck } from "zod-fast-check"; import { ZodFastCheck } from "zod-fast-check";
import { getToolConfig } from "../../apps/api/src/routes/tool-factory.js"; import { getToolConfig } from "../../../apps/api/src/routes/tool-factory.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { collectRegexStringSchemas } from "../helpers/zod-pict.js"; import { collectRegexStringSchemas } from "../../helpers/zod-pict.js";
import { buildTestApp, type TestApp } from "./test-server.js"; import { buildTestApp, type TestApp } from "../test-server.js";
/** /**
* Property-based settings fuzz: random VALID settings (derived from each * Property-based settings fuzz: random VALID settings (derived from each
@@ -9,8 +9,13 @@
import { existsSync, readFileSync } from "node:fs"; import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtureDir, fixtures, readFixture } from "../fixtures/index.js"; import { fixtureDir, fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
function isAsyncFallback(res: { statusCode: number; body: string }): boolean { function isAsyncFallback(res: { statusCode: number; body: string }): boolean {
if (res.statusCode !== 202) return false; if (res.statusCode !== 202) return false;
@@ -1,6 +1,11 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures -- one canonical file per modality // Fixtures -- one canonical file per modality
@@ -1,11 +1,11 @@
import { TOOLS } from "@snapotter/shared"; import { TOOLS } from "@snapotter/shared";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { getToolConfig } from "../../apps/api/src/routes/tool-factory.js"; import { getToolConfig } from "../../../apps/api/src/routes/tool-factory.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { pairwise } from "../helpers/pairwise.js"; import { pairwise } from "../../helpers/pairwise.js";
import { defaultSettingsFor } from "../helpers/tool-default-settings.js"; import { defaultSettingsFor } from "../../helpers/tool-default-settings.js";
import { compactCase, deriveAxes } from "../helpers/zod-pict.js"; import { compactCase, deriveAxes } from "../../helpers/zod-pict.js";
import { buildTestApp, type TestApp } from "./test-server.js"; import { buildTestApp, type TestApp } from "../test-server.js";
/** /**
* Pairwise settings matrix: a covering array over each tool's settings schema * Pairwise settings matrix: a covering array over each tool's settings schema
@@ -7,7 +7,7 @@
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -1,5 +1,5 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let token: string; let token: string;
@@ -1,9 +1,9 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { ensureAnonymousUser, hashPassword } from "../../apps/api/src/plugins/auth.js"; import { ensureAnonymousUser, hashPassword } from "../../../apps/api/src/plugins/auth.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -4,8 +4,8 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -8,8 +8,13 @@
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -1,5 +1,5 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -6,9 +6,14 @@
* is disabled (the default). * is disabled (the default).
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
const PNG = readFixture(fixtures.image.edge.px1); const PNG = readFixture(fixtures.image.edge.px1);
@@ -5,8 +5,8 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -12,10 +12,15 @@ import { join } from "node:path";
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import AdmZip from "adm-zip"; import AdmZip from "adm-zip";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { sharedRedis } from "../../apps/api/src/jobs/connection.js"; import { sharedRedis } from "../../../apps/api/src/jobs/connection.js";
import { bullPrefix } from "../../apps/api/src/jobs/types.js"; import { bullPrefix } from "../../../apps/api/src/jobs/types.js";
import { fixtureDir, fixtures, readFixture } from "../fixtures/index.js"; import { fixtureDir, fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
const PNG = readFixture(fixtures.image.base.png200); const PNG = readFixture(fixtures.image.base.png200);
const JPG = readFixture(fixtures.image.base.jpg100); const JPG = readFixture(fixtures.image.base.jpg100);
@@ -1,8 +1,8 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterEach, beforeAll, describe, expect, it } from "vitest"; import { afterEach, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { runMigrations } from "../../apps/api/src/db/migrate.js"; import { runMigrations } from "../../../apps/api/src/db/migrate.js";
import { getMaxAgeMs, shouldRunStartupCleanup } from "../../apps/api/src/lib/cleanup.js"; import { getMaxAgeMs, shouldRunStartupCleanup } from "../../../apps/api/src/lib/cleanup.js";
beforeAll(async () => { beforeAll(async () => {
await runMigrations(); await runMigrations();
@@ -6,8 +6,13 @@
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -71,9 +71,9 @@ describe("config export with enterprise license", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["config_export_import"]); mockEnterpriseFeatures(["config_export_import"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
licensedApp = await buildTestApp(); licensedApp = await buildTestApp();
licensedToken = await loginAsAdmin(licensedApp.app); licensedToken = await loginAsAdmin(licensedApp.app);
}, 30_000); }, 30_000);
@@ -154,9 +154,9 @@ describe("config import with enterprise license", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["config_export_import"]); mockEnterpriseFeatures(["config_export_import"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
licensedApp = await buildTestApp(); licensedApp = await buildTestApp();
licensedToken = await loginAsAdmin(licensedApp.app); licensedToken = await loginAsAdmin(licensedApp.app);
}, 30_000); }, 30_000);
@@ -294,9 +294,9 @@ describe("config round-trip", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["config_export_import"]); mockEnterpriseFeatures(["config_export_import"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
licensedApp = await buildTestApp(); licensedApp = await buildTestApp();
licensedToken = await loginAsAdmin(licensedApp.app); licensedToken = await loginAsAdmin(licensedApp.app);
}, 30_000); }, 30_000);
@@ -16,8 +16,13 @@
import { spawnSync } from "node:child_process"; import { spawnSync } from "node:child_process";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// ── Binary gates ────────────────────────────────────────────────────── // ── Binary gates ──────────────────────────────────────────────────────
function hasBinary(name: string): boolean { function hasBinary(name: string): boolean {
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -20,7 +20,7 @@ import {
qpdfSplitRanges, qpdfSplitRanges,
} from "@snapotter/doc-engine"; } from "@snapotter/doc-engine";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { fixtures } from "../fixtures/index.js"; import { fixtures } from "../../fixtures/index.js";
const PDF = fixtures.document.pdf3; const PDF = fixtures.document.pdf3;
@@ -10,7 +10,7 @@ import {
pdfcpuTextStamp, pdfcpuTextStamp,
} from "@snapotter/doc-engine"; } from "@snapotter/doc-engine";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { fixtures } from "../fixtures/index.js"; import { fixtures } from "../../fixtures/index.js";
const PDF = fixtures.document.pdf3; const PDF = fixtures.document.pdf3;
@@ -10,7 +10,7 @@ import {
sofficeAvailable, sofficeAvailable,
} from "@snapotter/doc-engine"; } from "@snapotter/doc-engine";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { fixtures } from "../fixtures/index.js"; import { fixtures } from "../../fixtures/index.js";
const PDF = fixtures.document.pdf3; const PDF = fixtures.document.pdf3;
const DOCX = fixtures.document.tiny("docx"); const DOCX = fixtures.document.tiny("docx");
@@ -10,8 +10,8 @@ import {
pdfTextPy, pdfTextPy,
} from "@snapotter/doc-engine"; } from "@snapotter/doc-engine";
import { afterAll, describe, expect, it } from "vitest"; import { afterAll, describe, expect, it } from "vitest";
import { fixtures } from "../fixtures/index.js"; import { fixtures } from "../../fixtures/index.js";
import { hasFitz, hasPikepdf, hasPython } from "../helpers/python-gate.js"; import { hasFitz, hasPikepdf, hasPython } from "../../helpers/python-gate.js";
// Ensure the bridge uses a reachable Python; set PYTHON_VENV_PATH before // Ensure the bridge uses a reachable Python; set PYTHON_VENV_PATH before
// any import triggers a dispatcher spawn. // any import triggers a dispatcher spawn.
@@ -1,5 +1,5 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildTestApp, type TestApp } from "./test-server"; import { buildTestApp, type TestApp } from "../test-server";
describe("API docs", () => { describe("API docs", () => {
let testApp: TestApp; let testApp: TestApp;
@@ -1,6 +1,6 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { deletePrefix, putObject } from "../../apps/api/src/lib/object-storage.js"; import { deletePrefix, putObject } from "../../../apps/api/src/lib/object-storage.js";
import { buildTestApp, type TestApp } from "./test-server.js"; import { buildTestApp, type TestApp } from "../test-server.js";
describe("download endpoint (object storage + Range)", () => { describe("download endpoint (object storage + Range)", () => {
let testApp: TestApp; let testApp: TestApp;
@@ -6,8 +6,13 @@
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -8,16 +8,16 @@
import { TOOLS } from "@snapotter/shared"; import { TOOLS } from "@snapotter/shared";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { createToolRoute } from "../../apps/api/src/routes/tool-factory.js"; import { createToolRoute } from "../../../apps/api/src/routes/tool-factory.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { import {
buildTestApp, buildTestApp,
createMultipartPayload, createMultipartPayload,
loginAsAdmin, loginAsAdmin,
preReadyHooks, preReadyHooks,
type TestApp, type TestApp,
} from "./test-server.js"; } from "../test-server.js";
const PNG = readFixture(fixtures.image.edge.px1); const PNG = readFixture(fixtures.image.edge.px1);
const PNG_A = readFixture(fixtures.image.edge.px1); const PNG_A = readFixture(fixtures.image.edge.px1);
@@ -47,10 +47,10 @@ const {
invalidateCache, invalidateCache,
ImportLockError, ImportLockError,
ImportValidationError, ImportValidationError,
} = await import("../../apps/api/src/lib/feature-status.js"); } = await import("../../../apps/api/src/lib/feature-status.js");
// Test helpers from test-server // Test helpers from test-server
const { createMultipartPayload, loginAsAdmin } = await import("./test-server.js"); const { createMultipartPayload, loginAsAdmin } = await import("../test-server.js");
// Use face-detection as smallest bundle from the manifest // Use face-detection as smallest bundle from the manifest
const testBundleId = "face-detection"; const testBundleId = "face-detection";
@@ -347,7 +347,7 @@ describe("POST /api/v1/admin/features/import", () => {
await app.register(cookie, { secret: "test-cookie-secret", hook: "onRequest" }); await app.register(cookie, { secret: "test-cookie-secret", hook: "onRequest" });
const { authMiddleware, authRoutes, ensureBuiltinRoles, ensureDefaultAdmin } = await import( const { authMiddleware, authRoutes, ensureBuiltinRoles, ensureDefaultAdmin } = await import(
"../../apps/api/src/plugins/auth.js" "../../../apps/api/src/plugins/auth.js"
); );
await authMiddleware(app); await authMiddleware(app);
await authRoutes(app); await authRoutes(app);
@@ -355,14 +355,14 @@ describe("POST /api/v1/admin/features/import", () => {
await ensureDefaultAdmin(); await ensureDefaultAdmin();
// Clear mustChangePassword for admin // Clear mustChangePassword for admin
const { db, schema } = await import("../../apps/api/src/db/index.js"); const { db, schema } = await import("../../../apps/api/src/db/index.js");
const { eq } = await import("drizzle-orm"); const { eq } = await import("drizzle-orm");
await db await db
.update(schema.users) .update(schema.users)
.set({ mustChangePassword: false }) .set({ mustChangePassword: false })
.where(eq(schema.users.username, "admin")); .where(eq(schema.users.username, "admin"));
const { registerFeatureRoutes } = await import("../../apps/api/src/routes/features.js"); const { registerFeatureRoutes } = await import("../../../apps/api/src/routes/features.js");
await registerFeatureRoutes(app); await registerFeatureRoutes(app);
token = await loginAsAdmin(app); token = await loginAsAdmin(app);
@@ -8,8 +8,8 @@
*/ */
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
const JPG = readFixture(fixtures.image.base.jpg100); const JPG = readFixture(fixtures.image.base.jpg100);
const TIFF = readFixture(fixtures.image.formats("tiff")); const TIFF = readFixture(fixtures.image.formats("tiff"));
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -64,9 +64,9 @@ describe("IP allowlist with enterprise license", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["ip_allowlist"]); mockEnterpriseFeatures(["ip_allowlist"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
enterpriseApp = await buildTestApp(); enterpriseApp = await buildTestApp();
entAdminToken = await loginAsAdmin(enterpriseApp.app); entAdminToken = await loginAsAdmin(enterpriseApp.app);
@@ -7,17 +7,17 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { requestCancel } from "../../apps/api/src/jobs/cancel.js"; import { requestCancel } from "../../../apps/api/src/jobs/cancel.js";
import { sharedRedis } from "../../apps/api/src/jobs/connection.js"; import { sharedRedis } from "../../../apps/api/src/jobs/connection.js";
import { enqueueToolJob, waitForJob } from "../../apps/api/src/jobs/enqueue.js"; import { enqueueToolJob, waitForJob } from "../../../apps/api/src/jobs/enqueue.js";
import { bullPrefix, type ToolJobData } from "../../apps/api/src/jobs/types.js"; import { bullPrefix, type ToolJobData } from "../../../apps/api/src/jobs/types.js";
import { putObject } from "../../apps/api/src/lib/object-storage.js"; import { putObject } from "../../../apps/api/src/lib/object-storage.js";
import { import {
registerToolProcessFn, registerToolProcessFn,
type ToolProcessCtx, type ToolProcessCtx,
} from "../../apps/api/src/routes/tool-factory.js"; } from "../../../apps/api/src/routes/tool-factory.js";
import { buildTestApp, type TestApp } from "./test-server.js"; import { buildTestApp, type TestApp } from "../test-server.js";
// Register test-only tools for the spine tests // Register test-only tools for the spine tests
registerToolProcessFn({ registerToolProcessFn({
@@ -1,6 +1,6 @@
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { db } from "../../apps/api/src/db/index.js"; import { db } from "../../../apps/api/src/db/index.js";
describe("jobs table (phase 2 spine)", () => { describe("jobs table (phase 2 spine)", () => {
it("has the spine columns and canceled status", async () => { it("has the spine columns and canceled status", async () => {
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -3,7 +3,7 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia, runFfmpeg } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia, runFfmpeg } from "@snapotter/media-engine";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { fixtures } from "../fixtures/index.js"; import { fixtures } from "../../fixtures/index.js";
const FIXTURE = fixtures.video.tiny("mp4"); const FIXTURE = fixtures.video.tiny("mp4");
@@ -3,13 +3,13 @@ import * as OTPAuth from "otpauth";
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["mfa"]); mockEnterpriseFeatures(["mfa"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
const { db, schema } = await import("../../apps/api/src/db/index.js"); const { db, schema } = await import("../../../apps/api/src/db/index.js");
import type { TestApp } from "./test-server.js"; import type { TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -4,8 +4,8 @@ import { join } from "node:path";
import Database from "better-sqlite3"; import Database from "better-sqlite3";
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db } from "../../apps/api/src/db/index.js"; import { db } from "../../../apps/api/src/db/index.js";
import { migrateFromSqlite } from "../../apps/api/src/db/migrate-from-sqlite.js"; import { migrateFromSqlite } from "../../../apps/api/src/db/migrate-from-sqlite.js";
function buildFixtureSqlite(path: string): void { function buildFixtureSqlite(path: string): void {
const s = new Database(path); const s = new Database(path);
@@ -5,10 +5,10 @@ import { join } from "node:path";
import { qpdfAvailable } from "@snapotter/doc-engine"; import { qpdfAvailable } from "@snapotter/doc-engine";
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { afterAll, describe, expect, it } from "vitest"; import { afterAll, describe, expect, it } from "vitest";
import { InputValidationError } from "../../apps/api/src/modality/contract.js"; import { InputValidationError } from "../../../apps/api/src/modality/contract.js";
import { DocumentInputHandler } from "../../apps/api/src/modality/document-input.js"; import { DocumentInputHandler } from "../../../apps/api/src/modality/document-input.js";
import { MediaInputHandler } from "../../apps/api/src/modality/media-input.js"; import { MediaInputHandler } from "../../../apps/api/src/modality/media-input.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
const scratchDir = mkdtempSync(join(tmpdir(), "modality-input-")); const scratchDir = mkdtempSync(join(tmpdir(), "modality-input-"));
afterAll(() => rmSync(scratchDir, { recursive: true, force: true })); afterAll(() => rmSync(scratchDir, { recursive: true, force: true }));
@@ -41,7 +41,7 @@ describe.skipIf(!ffmpegAvailable())("MediaInputHandler (requires ffmpeg)", () =>
}); });
it("enforces the duration cap", async () => { it("enforces the duration cap", async () => {
const { env } = await import("../../apps/api/src/config.js"); const { env } = await import("../../../apps/api/src/config.js");
const original = env.MAX_AUDIO_DURATION_S; const original = env.MAX_AUDIO_DURATION_S;
(env as Record<string, unknown>).MAX_AUDIO_DURATION_S = 0.5; (env as Record<string, unknown>).MAX_AUDIO_DURATION_S = 0.5;
try { try {
@@ -66,7 +66,7 @@ describe("DocumentInputHandler", () => {
const buf = readFixture(fixtures.document.pdf3); const buf = readFixture(fixtures.document.pdf3);
const out = await new DocumentInputHandler().prepare(buf, "test.pdf", { scratchDir }); const out = await new DocumentInputHandler().prepare(buf, "test.pdf", { scratchDir });
expect(out.buffer).toBe(buf); expect(out.buffer).toBe(buf);
const { env } = await import("../../apps/api/src/config.js"); const { env } = await import("../../../apps/api/src/config.js");
const original = env.MAX_PDF_PAGES; const original = env.MAX_PDF_PAGES;
(env as Record<string, unknown>).MAX_PDF_PAGES = 2; (env as Record<string, unknown>).MAX_PDF_PAGES = 2;
try { try {
@@ -3,8 +3,8 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { MediaInputHandler } from "../../apps/api/src/modality/media-input.js"; import { MediaInputHandler } from "../../../apps/api/src/modality/media-input.js";
import { fixtureRoot } from "../fixtures/index.js"; import { fixtureRoot } from "../../fixtures/index.js";
const FIX = fixtureRoot; const FIX = fixtureRoot;
const MP4 = readFileSync(join(FIX, "media", "tiny.mp4")); const MP4 = readFileSync(join(FIX, "media", "tiny.mp4"));
@@ -4,7 +4,7 @@
* - GET/POST /api/v1/admin/log-level (runtime log level) * - GET/POST /api/v1/admin/log-level (runtime log level)
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -13,9 +13,9 @@ import { randomUUID } from "node:crypto";
import { createServer, type Server } from "node:http"; import { createServer, type Server } from "node:http";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { env } from "../../apps/api/src/config.js"; import { env } from "../../../apps/api/src/config.js";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
// ── Helpers ────────────────────────────────────────────────────────── // ── Helpers ──────────────────────────────────────────────────────────
@@ -440,7 +440,7 @@ describe("OIDC login redirect", () => {
(env as any).OIDC_CLIENT_SECRET = "test-client-secret"; (env as any).OIDC_CLIENT_SECRET = "test-client-secret";
// Clear the cached OIDC config so discovery hits our mock // Clear the cached OIDC config so discovery hits our mock
const _oidcModule = await import("../../apps/api/src/plugins/oidc.js"); const _oidcModule = await import("../../../apps/api/src/plugins/oidc.js");
// The module caches config in a module-level variable; rebuild app to get fresh routes // The module caches config in a module-level variable; rebuild app to get fresh routes
oidcApp = await buildTestApp(); oidcApp = await buildTestApp();
}, 30_000); }, 30_000);
@@ -9,8 +9,13 @@ import { readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -30,7 +35,9 @@ let userAFileId: string;
let userAPipelineId: string; let userAPipelineId: string;
// Load test fixture // Load test fixture
const fixtureBuffer = readFileSync(join(import.meta.dirname, "..", "fixtures", "test-1x1.png")); const fixtureBuffer = readFileSync(
join(import.meta.dirname, "..", "..", "fixtures", "test-1x1.png"),
);
/** Register a user, clear mustChangePassword, log in, return token. */ /** Register a user, clear mustChangePassword, log in, return token. */
async function createAndLogin( async function createAndLogin(
@@ -2,8 +2,13 @@ import { readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -249,7 +254,7 @@ describe("permission enforcement on routes", () => {
}); });
describe("tool and pipeline permission enforcement", () => { describe("tool and pipeline permission enforcement", () => {
const fixturePath = join(import.meta.dirname, "..", "fixtures", "test-200x150.png"); const fixturePath = join(import.meta.dirname, "..", "..", "fixtures", "test-200x150.png");
const fixtureBuffer = readFileSync(fixturePath); const fixtureBuffer = readFileSync(fixturePath);
it("unauthenticated user cannot use tools", async () => { it("unauthenticated user cannot use tools", async () => {
@@ -443,7 +448,9 @@ describe("file ownership scoping", () => {
it("user A cannot access user B's file by ID", async () => { it("user A cannot access user B's file by ID", async () => {
// Upload as user A // Upload as user A
const testImage = readFileSync(join(import.meta.dirname, "..", "fixtures", "test-200x150.png")); const testImage = readFileSync(
join(import.meta.dirname, "..", "..", "fixtures", "test-200x150.png"),
);
const { body: uploadBody, contentType } = createMultipartPayload([ const { body: uploadBody, contentType } = createMultipartPayload([
{ name: "file", filename: "test.png", contentType: "image/png", content: testImage }, { name: "file", filename: "test.png", contentType: "image/png", content: testImage },
]); ]);
@@ -7,8 +7,13 @@
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { resolveToolPool, shouldSkipSyncWindow } from "../../apps/api/src/lib/pool.js"; import { resolveToolPool, shouldSkipSyncWindow } from "../../../apps/api/src/lib/pool.js";
describe("pool routing", () => { describe("pool routing", () => {
it("image tools stay on the image pool", () => { it("image tools stay on the image pool", () => {
@@ -2,8 +2,8 @@ import { readFile } from "node:fs/promises";
import { resolveGs } from "@snapotter/doc-engine"; import { resolveGs } from "@snapotter/doc-engine";
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { pdfFirstPagePreview, videoPosterPreview } from "../../apps/api/src/modality/preview.js"; import { pdfFirstPagePreview, videoPosterPreview } from "../../../apps/api/src/modality/preview.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
describe.skipIf(!ffmpegAvailable())("video poster preview (requires ffmpeg)", () => { describe.skipIf(!ffmpegAvailable())("video poster preview (requires ffmpeg)", () => {
it("renders a webp poster", async () => { it("renders a webp poster", async () => {
@@ -11,12 +11,12 @@ import { writeFile } from "node:fs/promises";
import { join } from "node:path"; import { join } from "node:path";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { enqueueToolJob, waitForJob } from "../../apps/api/src/jobs/enqueue.js"; import { enqueueToolJob, waitForJob } from "../../../apps/api/src/jobs/enqueue.js";
import type { ToolJobData } from "../../apps/api/src/jobs/types.js"; import type { ToolJobData } from "../../../apps/api/src/jobs/types.js";
import { getObjectBuffer, putObject } from "../../apps/api/src/lib/object-storage.js"; import { getObjectBuffer, putObject } from "../../../apps/api/src/lib/object-storage.js";
import { registerToolProcessFn } from "../../apps/api/src/routes/tool-factory.js"; import { registerToolProcessFn } from "../../../apps/api/src/routes/tool-factory.js";
import { buildTestApp, type TestApp } from "./test-server.js"; import { buildTestApp, type TestApp } from "../test-server.js";
// Register a native-v2 test tool that concatenates two inputs via scratchPath // Register a native-v2 test tool that concatenates two inputs via scratchPath
registerToolProcessFn({ registerToolProcessFn({
@@ -14,9 +14,9 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { updateSingleFileProgress } from "../../apps/api/src/routes/progress.js"; import { updateSingleFileProgress } from "../../../apps/api/src/routes/progress.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -95,7 +95,7 @@ describe("Redis progress transport", () => {
const jobId = `tp-batch-${randomUUID()}`; const jobId = `tp-batch-${randomUUID()}`;
// Use the updateJobProgress export (imported indirectly via the module) // Use the updateJobProgress export (imported indirectly via the module)
const { updateJobProgress } = await import("../../apps/api/src/routes/progress.js"); const { updateJobProgress } = await import("../../../apps/api/src/routes/progress.js");
updateJobProgress({ updateJobProgress({
jobId, jobId,
status: "completed", status: "completed",
@@ -17,10 +17,18 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { updateJobProgress, updateSingleFileProgress } from "../../apps/api/src/routes/progress.js"; import {
import { fixtures, readFixture } from "../fixtures/index.js"; updateJobProgress,
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; updateSingleFileProgress,
} from "../../../apps/api/src/routes/progress.js";
import { fixtures, readFixture } from "../../fixtures/index.js";
import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
const PNG = readFixture(fixtures.image.base.png200); const PNG = readFixture(fixtures.image.base.png200);
const JPG = readFixture(fixtures.image.base.jpg100); const JPG = readFixture(fixtures.image.base.jpg100);
@@ -7,8 +7,8 @@
*/ */
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -19,8 +19,8 @@ import {
} from "@aws-sdk/client-s3"; } from "@aws-sdk/client-s3";
import { loadS3Storage, type S3StorageModule } from "@snapotter/enterprise"; import { loadS3Storage, type S3StorageModule } from "@snapotter/enterprise";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { env } from "../../apps/api/src/config.js"; import { env } from "../../../apps/api/src/config.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
const PNG = readFixture(fixtures.image.base.png200); const PNG = readFixture(fixtures.image.base.png200);
@@ -108,7 +108,7 @@ describe.skipIf(!minioAvailable)("S3 storage backend", () => {
}, 15_000); }, 15_000);
it("saveFile writes object to S3", async () => { it("saveFile writes object to S3", async () => {
const { saveFile } = await import("../../apps/api/src/lib/file-storage.js"); const { saveFile } = await import("../../../apps/api/src/lib/file-storage.js");
storedName = await saveFile(PNG, "test-upload.png"); storedName = await saveFile(PNG, "test-upload.png");
expect(storedName).toMatch(/^[a-f0-9-]+\.png$/); expect(storedName).toMatch(/^[a-f0-9-]+\.png$/);
@@ -116,13 +116,13 @@ describe.skipIf(!minioAvailable)("S3 storage backend", () => {
}); });
it("readStoredFile returns the correct buffer", async () => { it("readStoredFile returns the correct buffer", async () => {
const { readStoredFile } = await import("../../apps/api/src/lib/file-storage.js"); const { readStoredFile } = await import("../../../apps/api/src/lib/file-storage.js");
const buffer = await readStoredFile(storedName); const buffer = await readStoredFile(storedName);
expect(Buffer.compare(buffer, PNG)).toBe(0); expect(Buffer.compare(buffer, PNG)).toBe(0);
}); });
it("streamStoredFile returns a readable stream", async () => { it("streamStoredFile returns a readable stream", async () => {
const { streamStoredFile } = await import("../../apps/api/src/lib/file-storage.js"); const { streamStoredFile } = await import("../../../apps/api/src/lib/file-storage.js");
const stream = await streamStoredFile(storedName); const stream = await streamStoredFile(storedName);
const chunks: Buffer[] = []; const chunks: Buffer[] = [];
@@ -134,7 +134,7 @@ describe.skipIf(!minioAvailable)("S3 storage backend", () => {
it("saveThumbnail stores in S3, getCachedThumbnail retrieves it", async () => { it("saveThumbnail stores in S3, getCachedThumbnail retrieves it", async () => {
const { saveThumbnail, getCachedThumbnail } = await import( const { saveThumbnail, getCachedThumbnail } = await import(
"../../apps/api/src/lib/file-storage.js" "../../../apps/api/src/lib/file-storage.js"
); );
const thumbData = Buffer.from("fake-thumbnail-data"); const thumbData = Buffer.from("fake-thumbnail-data");
@@ -147,29 +147,31 @@ describe.skipIf(!minioAvailable)("S3 storage backend", () => {
}); });
it("deleteThumbnail removes thumbnail from S3", async () => { it("deleteThumbnail removes thumbnail from S3", async () => {
const { deleteThumbnail } = await import("../../apps/api/src/lib/file-storage.js"); const { deleteThumbnail } = await import("../../../apps/api/src/lib/file-storage.js");
await deleteThumbnail(storedName); await deleteThumbnail(storedName);
expect(await objectExists(`thumbs/${storedName}.thumb.jpg`)).toBe(false); expect(await objectExists(`thumbs/${storedName}.thumb.jpg`)).toBe(false);
}); });
it("deleteStoredFile removes file from S3", async () => { it("deleteStoredFile removes file from S3", async () => {
const { deleteStoredFile } = await import("../../apps/api/src/lib/file-storage.js"); const { deleteStoredFile } = await import("../../../apps/api/src/lib/file-storage.js");
await deleteStoredFile(storedName); await deleteStoredFile(storedName);
expect(await objectExists(`files/${storedName}`)).toBe(false); expect(await objectExists(`files/${storedName}`)).toBe(false);
}); });
it("deleteStoredFile is idempotent (no error for missing key)", async () => { it("deleteStoredFile is idempotent (no error for missing key)", async () => {
const { deleteStoredFile } = await import("../../apps/api/src/lib/file-storage.js"); const { deleteStoredFile } = await import("../../../apps/api/src/lib/file-storage.js");
await expect(deleteStoredFile("nonexistent-file.png")).resolves.toBeUndefined(); await expect(deleteStoredFile("nonexistent-file.png")).resolves.toBeUndefined();
}); });
it("getCachedThumbnail returns null for missing thumbnail", async () => { it("getCachedThumbnail returns null for missing thumbnail", async () => {
const { getCachedThumbnail } = await import("../../apps/api/src/lib/file-storage.js"); const { getCachedThumbnail } = await import("../../../apps/api/src/lib/file-storage.js");
expect(await getCachedThumbnail("nonexistent.png")).toBeNull(); expect(await getCachedThumbnail("nonexistent.png")).toBeNull();
}); });
it("S3_PREFIX scopes all object keys under a tenant prefix", async () => { it("S3_PREFIX scopes all object keys under a tenant prefix", async () => {
const { saveFile, deleteStoredFile } = await import("../../apps/api/src/lib/file-storage.js"); const { saveFile, deleteStoredFile } = await import(
"../../../apps/api/src/lib/file-storage.js"
);
(env as Record<string, unknown>).S3_PREFIX = "tenant-123"; (env as Record<string, unknown>).S3_PREFIX = "tenant-123";
s3Storage.configureS3({ s3Storage.configureS3({
@@ -1,7 +1,7 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { hashPassword } from "../../apps/api/src/plugins/auth.js"; import { hashPassword } from "../../../apps/api/src/plugins/auth.js";
import { buildTestApp, type TestApp } from "./test-server.js"; import { buildTestApp, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
const SCIM_TOKEN = "test-scim-token-abc123"; const SCIM_TOKEN = "test-scim-token-abc123";
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -72,9 +72,9 @@ describe("SIEM config with enterprise license", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["siem_forwarding"]); mockEnterpriseFeatures(["siem_forwarding"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
enterpriseApp = await buildTestApp(); enterpriseApp = await buildTestApp();
entAdminToken = await loginAsAdmin(enterpriseApp.app); entAdminToken = await loginAsAdmin(enterpriseApp.app);
@@ -1,5 +1,5 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -7,9 +7,9 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import AdmZip from "adm-zip"; import AdmZip from "adm-zip";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { env } from "../../apps/api/src/config.js"; import { env } from "../../../apps/api/src/config.js";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -8,18 +8,18 @@ import { join } from "node:path";
import type { Job } from "bullmq"; import type { Job } from "bullmq";
import { eq, sql } from "drizzle-orm"; import { eq, sql } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { env } from "../../apps/api/src/config.js"; import { env } from "../../../apps/api/src/config.js";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { runMigrations } from "../../apps/api/src/db/migrate.js"; import { runMigrations } from "../../../apps/api/src/db/migrate.js";
import { closeQueues, getQueue } from "../../apps/api/src/jobs/queues.js"; import { closeQueues, getQueue } from "../../../apps/api/src/jobs/queues.js";
import { import {
decideExpiry, decideExpiry,
runSystemJob, runSystemJob,
SYSTEM_JOBS, SYSTEM_JOBS,
scheduleSystemJobs, scheduleSystemJobs,
} from "../../apps/api/src/jobs/system-jobs.js"; } from "../../../apps/api/src/jobs/system-jobs.js";
import type { ObjectInfo } from "../../apps/api/src/lib/object-storage.js"; import type { ObjectInfo } from "../../../apps/api/src/lib/object-storage.js";
import * as objectStorage from "../../apps/api/src/lib/object-storage.js"; import * as objectStorage from "../../../apps/api/src/lib/object-storage.js";
beforeAll(async () => { beforeAll(async () => {
await runMigrations(); await runMigrations();
@@ -8,8 +8,8 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { eq, sql } from "drizzle-orm"; import { eq, sql } from "drizzle-orm";
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -7,10 +7,15 @@
*/ */
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { sharedRedis } from "../../apps/api/src/jobs/connection.js"; import { sharedRedis } from "../../../apps/api/src/jobs/connection.js";
import { bullPrefix } from "../../apps/api/src/jobs/types.js"; import { bullPrefix } from "../../../apps/api/src/jobs/types.js";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
const PNG = readFixture(fixtures.image.base.png200); const PNG = readFixture(fixtures.image.base.png200);
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -80,9 +80,9 @@ describe("upgrade management - with enterprise license", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["upgrade_management"]); mockEnterpriseFeatures(["upgrade_management"]);
const { buildTestApp, loginAsAdmin } = await import("./test-server.js"); const { buildTestApp, loginAsAdmin } = await import("../test-server.js");
entApp = await buildTestApp(); entApp = await buildTestApp();
entAdminToken = await loginAsAdmin(entApp.app); entAdminToken = await loginAsAdmin(entApp.app);
}, 30_000); }, 30_000);
@@ -7,8 +7,8 @@
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let app: TestApp["app"]; let app: TestApp["app"];
@@ -7,8 +7,13 @@
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
const PNG = readFixture(fixtures.image.base.png200); const PNG = readFixture(fixtures.image.base.png200);
const JPG = readFixture(fixtures.image.base.jpg100); const JPG = readFixture(fixtures.image.base.jpg100);
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
describe("webhook management", () => { describe("webhook management", () => {
describe("without enterprise license", () => { describe("without enterprise license", () => {
@@ -96,9 +96,9 @@ describe("webhook management", () => {
beforeAll(async () => { beforeAll(async () => {
vi.resetModules(); vi.resetModules();
const { mockEnterpriseFeatures } = await import("../helpers/enterprise-mock.js"); const { mockEnterpriseFeatures } = await import("../../helpers/enterprise-mock.js");
mockEnterpriseFeatures(["admin_alerts", "webhooks"]); mockEnterpriseFeatures(["admin_alerts", "webhooks"]);
const testServer = await import("./test-server.js"); const testServer = await import("../test-server.js");
testApp = await testServer.buildTestApp(); testApp = await testServer.buildTestApp();
adminToken = await testServer.loginAsAdmin(testApp.app); adminToken = await testServer.loginAsAdmin(testApp.app);
}, 30_000); }, 30_000);
@@ -15,17 +15,17 @@ process.env.JOB_TIMEOUT_FAST_S = "1";
// Dynamic imports so config.ts picks up the 1-second timeout. // Dynamic imports so config.ts picks up the 1-second timeout.
const { eq } = await import("drizzle-orm"); const { eq } = await import("drizzle-orm");
const { db, schema } = await import("../../apps/api/src/db/index.js"); const { db, schema } = await import("../../../apps/api/src/db/index.js");
const { startCancelListener, stopCancelListener } = await import( const { startCancelListener, stopCancelListener } = await import(
"../../apps/api/src/jobs/cancel.js" "../../../apps/api/src/jobs/cancel.js"
); );
const { sharedRedis } = await import("../../apps/api/src/jobs/connection.js"); const { sharedRedis } = await import("../../../apps/api/src/jobs/connection.js");
const { enqueueToolJob } = await import("../../apps/api/src/jobs/enqueue.js"); const { enqueueToolJob } = await import("../../../apps/api/src/jobs/enqueue.js");
const { bullPrefix } = await import("../../apps/api/src/jobs/types.js"); const { bullPrefix } = await import("../../../apps/api/src/jobs/types.js");
const { closeWorkers, startWorkers } = await import("../../apps/api/src/jobs/worker.js"); const { closeWorkers, startWorkers } = await import("../../../apps/api/src/jobs/worker.js");
const { putObject } = await import("../../apps/api/src/lib/object-storage.js"); const { putObject } = await import("../../../apps/api/src/lib/object-storage.js");
const { registerToolProcessFn } = await import("../../apps/api/src/routes/tool-factory.js"); const { registerToolProcessFn } = await import("../../../apps/api/src/routes/tool-factory.js");
const { env } = await import("../../apps/api/src/config.js"); const { env } = await import("../../../apps/api/src/config.js");
// Sanity: the env override must have taken effect. // Sanity: the env override must have taken effect.
if (env.JOB_TIMEOUT_FAST_S !== 1) { if (env.JOB_TIMEOUT_FAST_S !== 1) {
@@ -42,7 +42,7 @@ registerToolProcessFn({
inputBuffer: Buffer, inputBuffer: Buffer,
_settings: unknown, _settings: unknown,
filename: string, filename: string,
ctx?: import("../../apps/api/src/routes/tool-factory.js").ToolProcessCtx, ctx?: import("../../../apps/api/src/routes/tool-factory.js").ToolProcessCtx,
) => { ) => {
// Loop for up to 30s, checking signal every 100ms. // Loop for up to 30s, checking signal every 100ms.
for (let i = 0; i < 300; i++) { for (let i = 0; i < 300; i++) {
@@ -62,7 +62,7 @@ const wsPath = process.env.WORKSPACE_PATH ?? "";
mkdirSync(wsPath, { recursive: true }); mkdirSync(wsPath, { recursive: true });
// Run migrations so the jobs table exists in this fork's DB. // Run migrations so the jobs table exists in this fork's DB.
const { runMigrations } = await import("../../apps/api/src/db/migrate.js"); const { runMigrations } = await import("../../../apps/api/src/db/migrate.js");
await runMigrations(); await runMigrations();
beforeAll(async () => { beforeAll(async () => {
@@ -18,8 +18,13 @@
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -19,8 +19,13 @@
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -10,8 +10,13 @@
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -18,8 +18,13 @@
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -16,8 +16,13 @@
*/ */
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -16,8 +16,13 @@
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -8,8 +8,13 @@
import sharp from "sharp"; import sharp from "sharp";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fixtures // Fixtures
@@ -2,9 +2,14 @@ import { readFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import { TOOLS } from "@snapotter/shared"; import { TOOLS } from "@snapotter/shared";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { TOOL_DISPLAY_MODES } from "../../apps/web/src/lib/tool-display-modes.js"; import { TOOL_DISPLAY_MODES } from "../../../apps/web/src/lib/tool-display-modes.js";
import { fixtureDir } from "../fixtures/index.js"; import { fixtureDir } from "../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
/** /**
* Hostile-input matrix: every tool route must reject malformed, truncated, * Hostile-input matrix: every tool route must reject malformed, truncated,
@@ -5,8 +5,8 @@
*/ */
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, loginAsAdmin, type TestApp } from "./test-server.js"; import { buildTestApp, loginAsAdmin, type TestApp } from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -10,8 +10,13 @@
*/ */
import { eq, sql } from "drizzle-orm"; import { eq, sql } from "drizzle-orm";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { db, schema } from "../../apps/api/src/db/index.js"; import { db, schema } from "../../../apps/api/src/db/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../test-server.js";
let testApp: TestApp; let testApp: TestApp;
let adminToken: string; let adminToken: string;
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const STEREO = readFixture(fixtures.audio.stereo); const STEREO = readFixture(fixtures.audio.stereo);
const MONO_MP3 = readFixture(fixtures.audio.tiny("mp3")); const MONO_MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -1,7 +1,12 @@
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const WAV = readFixture(fixtures.audio.tiny("wav")); const WAV = readFixture(fixtures.audio.tiny("wav"));
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -1,7 +1,12 @@
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
const WAV = readFixture(fixtures.audio.tiny("wav")); const WAV = readFixture(fixtures.audio.tiny("wav"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -1,7 +1,12 @@
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const WAV = readFixture(fixtures.audio.tiny("wav")); const WAV = readFixture(fixtures.audio.tiny("wav"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -1,7 +1,12 @@
import { ffmpegAvailable } from "@snapotter/media-engine"; import { ffmpegAvailable } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const MP3 = readFixture(fixtures.audio.tiny("mp3")); const MP3 = readFixture(fixtures.audio.tiny("mp3"));
@@ -3,8 +3,13 @@ import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine"; import { ffmpegAvailable, probeMedia } from "@snapotter/media-engine";
import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { fixtures, readFixture } from "../fixtures/index.js"; import { fixtures, readFixture } from "../../../fixtures/index.js";
import { buildTestApp, createMultipartPayload, loginAsAdmin, type TestApp } from "./test-server.js"; import {
buildTestApp,
createMultipartPayload,
loginAsAdmin,
type TestApp,
} from "../../test-server.js";
const TONE_GAP = readFixture(fixtures.audio.gap); const TONE_GAP = readFixture(fixtures.audio.gap);

Some files were not shown because too many files have changed in this diff Show More