Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

144 lines
4.0 KiB
TypeScript

import { sql } from "kysely";
import { afterEach, beforeEach, expect, it } from "vitest";
import {
describeEachDialect,
setupForDialect,
teardownForDialect,
type DialectTestContext,
} from "../../utils/test-db.js";
const EXPECTED_INDEXES = [
"idx__emdash_media_usage_sources_content",
"idx__emdash_media_usage_sources_variant",
"idx__emdash_media_usage_sources_locale",
"idx__emdash_media_usage_sources_deleted",
"idx__emdash_media_usage_sources_translation_group",
"idx__emdash_media_usage_media_id",
"idx__emdash_media_usage_provider_asset",
"idx__emdash_media_usage_source_generation",
"idx__emdash_media_usage_unique_occurrence",
] as const;
describeEachDialect("media usage index migration", (dialect) => {
let ctx: DialectTestContext;
beforeEach(async () => {
ctx = await setupForDialect(dialect);
});
afterEach(async () => {
await teardownForDialect(ctx);
});
it("creates usage source and occurrence tables through registered migrations", async () => {
const sources = await ctx.db
.selectFrom("_emdash_media_usage_sources")
.select("source_key")
.execute();
const usage = await ctx.db.selectFrom("_emdash_media_usage").select("id").execute();
expect(Array.isArray(sources)).toBe(true);
expect(Array.isArray(usage)).toBe(true);
});
it("accepts a content usage source and one occurrence", async () => {
const sourceKey = "content:posts:entry1:columns";
const generation = "gen1";
await ctx.db
.insertInto("_emdash_media_usage_sources")
.values({
source_key: sourceKey,
source_type: "content",
collection_slug: "posts",
content_id: "entry1",
source_variant: "columns",
content_slug: "hello-world",
content_title: "Hello World",
locale: "en",
translation_group: "tg1",
content_status: "published",
content_scheduled_at: null,
content_deleted_at: null,
revision_id: "rev1",
current_generation: generation,
schema_version: 1,
})
.execute();
await ctx.db
.insertInto("_emdash_media_usage")
.values({
id: "usage1",
source_key: sourceKey,
generation,
field_slug: "hero",
field_path: "hero",
occurrence_index: 0,
reference_type: "image_field",
media_id: "media1",
provider: "local",
provider_asset_id: "media1",
media_kind: "image",
mime_type: "image/jpeg",
})
.execute();
const rows = await ctx.db
.selectFrom("_emdash_media_usage")
.select(["source_key", "media_id", "provider", "provider_asset_id", "field_path"])
.where("media_id", "=", "media1")
.execute();
expect(rows).toEqual([
{
source_key: sourceKey,
media_id: "media1",
provider: "local",
provider_asset_id: "media1",
field_path: "hero",
},
]);
});
it("creates expected indexes", async () => {
const indexNames = await listIndexNames(ctx);
for (const indexName of EXPECTED_INDEXES) {
expect(indexNames.has(indexName), `missing index ${indexName}`).toBe(true);
}
});
it("down() drops tables and up() recreates them", async () => {
const migration = await import("../../../src/database/migrations/046_media_usage_index.js");
await migration.down(ctx.db);
await expect(sql`SELECT 1 FROM _emdash_media_usage`.execute(ctx.db)).rejects.toThrow();
await expect(sql`SELECT 1 FROM _emdash_media_usage_sources`.execute(ctx.db)).rejects.toThrow();
await migration.up(ctx.db);
const sources = await ctx.db
.selectFrom("_emdash_media_usage_sources")
.select("source_key")
.execute();
expect(Array.isArray(sources)).toBe(true);
});
});
async function listIndexNames(ctx: DialectTestContext): Promise<Set<string>> {
if (ctx.dialect === "sqlite") {
const result = await sql<{ name: string }>`
SELECT name FROM sqlite_master WHERE type = 'index'
`.execute(ctx.db);
return new Set(result.rows.map((row) => row.name));
}
const result = await sql<{ name: string }>`
SELECT indexname AS name FROM pg_indexes WHERE schemaname = current_schema()
`.execute(ctx.db);
return new Set(result.rows.map((row) => row.name));
}