@@ -54,6 +54,27 @@ test("imports CSV headings and exports an inspectable model", async ({
|
||||
expect((await pending).suggestedFilename()).toBe("fixture-model.json");
|
||||
});
|
||||
|
||||
test("imports composite constraints and exposes topological coverage", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/deep/nested/fixture/");
|
||||
await page.getByLabel("Fixture model source").fill(`CREATE TABLE tenants (
|
||||
region VARCHAR(8), tenant_id INTEGER, PRIMARY KEY (region, tenant_id)
|
||||
);
|
||||
CREATE TABLE events (
|
||||
region VARCHAR(8), tenant_id INTEGER,
|
||||
FOREIGN KEY (region, tenant_id) REFERENCES tenants(region, tenant_id)
|
||||
);`);
|
||||
await page.getByRole("button", { name: "Import model" }).click();
|
||||
await page.getByRole("button", { name: "Generate fixtures" }).click();
|
||||
await page.getByRole("button", { name: "Coverage" }).click();
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "Constraint coverage matrix" }),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText("tenants → events")).toBeVisible();
|
||||
await expect(page.getByText(/foreignKey\(region,tenant_id\)/u)).toBeVisible();
|
||||
});
|
||||
|
||||
test("retains results after a failed import and downloads output", async ({
|
||||
page,
|
||||
}) => {
|
||||
@@ -97,7 +118,7 @@ test("integrates help, themes, PWA identity and hardened headers", async ({
|
||||
const manifest = await request.get("/deep/nested/fixture/toolbox-app.json");
|
||||
await expect(manifest.json()).resolves.toMatchObject({
|
||||
id: "de.add-ideas.fixture-tools",
|
||||
version: "0.1.0",
|
||||
version: "0.2.0",
|
||||
privacy: { processing: "local", telemetry: false },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("keeps the primary workspace inside a narrow viewport", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/deep/nested/fixture/");
|
||||
await expect(page.locator("main").first()).toBeVisible();
|
||||
await expect(
|
||||
page.locator("main .loading, main .workbench-loading"),
|
||||
).toHaveCount(0);
|
||||
|
||||
const widths = await page.evaluate(() => ({
|
||||
content: document.documentElement.scrollWidth,
|
||||
viewport: document.documentElement.clientWidth,
|
||||
}));
|
||||
expect(widths.viewport).toBeLessThanOrEqual(430);
|
||||
expect(widths.content).toBeLessThanOrEqual(widths.viewport + 1);
|
||||
});
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
generateFixtures,
|
||||
constraintCoverageMatrix,
|
||||
modelJson,
|
||||
parseFixtureModel,
|
||||
serializeDataset,
|
||||
topologicalTableOrder,
|
||||
type GeneratedDataset,
|
||||
} from "../../src/fixture/model";
|
||||
|
||||
@@ -175,4 +177,104 @@ describe("fixture model", () => {
|
||||
}),
|
||||
).toThrow(/100,000 field values/u);
|
||||
});
|
||||
|
||||
it("imports and generates composite relational constraints topologically", () => {
|
||||
const sql = `CREATE TABLE tenants (
|
||||
region VARCHAR(8) NOT NULL,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (region, tenant_id)
|
||||
);
|
||||
CREATE TABLE events (
|
||||
region VARCHAR(8) NOT NULL,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
sequence INTEGER NOT NULL,
|
||||
UNIQUE (region, tenant_id, sequence),
|
||||
FOREIGN KEY (region, tenant_id) REFERENCES tenants(region, tenant_id)
|
||||
);`;
|
||||
const model = parseFixtureModel(sql, "sql").model;
|
||||
expect(model.tables[1]?.constraints).toEqual([
|
||||
{ kind: "unique", fields: ["region", "tenant_id", "sequence"] },
|
||||
{
|
||||
kind: "foreignKey",
|
||||
fields: ["region", "tenant_id"],
|
||||
references: { table: "tenants", fields: ["region", "tenant_id"] },
|
||||
},
|
||||
]);
|
||||
expect(topologicalTableOrder(model)).toEqual(["tenants", "events"]);
|
||||
const dataset = generateFixtures(model, {
|
||||
seed: "composite",
|
||||
rows: 12,
|
||||
boundaryPercent: 10,
|
||||
invalidPercent: 0,
|
||||
providerProfile: "auto",
|
||||
});
|
||||
const targets = new Set(
|
||||
dataset.tables.tenants?.map((row) => `${row.region}:${row.tenant_id}`),
|
||||
);
|
||||
expect(
|
||||
dataset.tables.events?.every((row) =>
|
||||
targets.has(`${row.region}:${row.tenant_id}`),
|
||||
),
|
||||
).toBe(true);
|
||||
expect(dataset.generationOrder).toEqual(["tenants", "events"]);
|
||||
expect(
|
||||
constraintCoverageMatrix(model, dataset).some(
|
||||
(entry) =>
|
||||
entry.table === "events" &&
|
||||
entry.constraint.startsWith("foreignKey(region,tenant_id)"),
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts scalar table-level primary and foreign-key constraints", () => {
|
||||
const sql = `CREATE TABLE accounts (
|
||||
account_id INTEGER NOT NULL,
|
||||
PRIMARY KEY (account_id)
|
||||
);
|
||||
CREATE TABLE entries (
|
||||
account_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (account_id) REFERENCES accounts(account_id)
|
||||
);`;
|
||||
const model = parseFixtureModel(sql, "sql").model;
|
||||
expect(model.tables[0]?.constraints).toEqual([
|
||||
{ kind: "unique", fields: ["account_id"] },
|
||||
]);
|
||||
expect(model.tables[1]?.constraints).toEqual([
|
||||
{
|
||||
kind: "foreignKey",
|
||||
fields: ["account_id"],
|
||||
references: { table: "accounts", fields: ["account_id"] },
|
||||
},
|
||||
]);
|
||||
const dataset = generateFixtures(model, {
|
||||
seed: "scalar-table-constraints",
|
||||
rows: 8,
|
||||
boundaryPercent: 0,
|
||||
invalidPercent: 0,
|
||||
});
|
||||
const accounts = new Set(
|
||||
dataset.tables.accounts?.map((row) => row.account_id),
|
||||
);
|
||||
expect(
|
||||
dataset.tables.entries?.every((row) => accounts.has(row.account_id)),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("supports deterministic built-in and custom provider profiles", () => {
|
||||
const model = parseFixtureModel("display_name,host,sku\n", "csv").model;
|
||||
const options = {
|
||||
seed: "providers",
|
||||
rows: 4,
|
||||
boundaryPercent: 0,
|
||||
invalidPercent: 0,
|
||||
providerProfile: "auto",
|
||||
};
|
||||
const generated = generateFixtures(model, options);
|
||||
expect(generated).toEqual(generateFixtures(model, options));
|
||||
expect(generated.tables.records?.[0]).toMatchObject({
|
||||
display_name: expect.stringMatching(/ /u),
|
||||
host: expect.stringMatching(/\.example\.test$/u),
|
||||
sku: "SKU-000001",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user