|
|
|
@@ -286,10 +286,13 @@ test("discloses bounded transient source samples in database-wide and selected g
|
|
|
|
|
name: "Metadata generation source data disclosure",
|
|
|
|
|
});
|
|
|
|
|
expect(within(disclosure).getByText(
|
|
|
|
|
"Description generation may send up to five real source rows and up to five representative non-null example values to the selected model provider.",
|
|
|
|
|
"Description generation may send up to five source rows and up to five representative non-null example values to the selected model provider. Values from columns marked sensitive are replaced with plausible synthetic values before the request.",
|
|
|
|
|
)).toBeVisible();
|
|
|
|
|
expect(within(disclosure).getByText(
|
|
|
|
|
"Samples are transient and are not stored in run logs or catalog metadata. Automated Sensitive Data Policy filtering and anonymization are not currently provided; they are planned for future work.",
|
|
|
|
|
"Values from unmarked columns may be sent unchanged. Samples are transient and are not stored in run logs or catalog metadata.",
|
|
|
|
|
)).toBeVisible();
|
|
|
|
|
expect(within(disclosure).getByText(
|
|
|
|
|
"Sensitive-field suggestions use structural metadata only and remain unsaved until you choose Save sensitive fields.",
|
|
|
|
|
)).toBeVisible();
|
|
|
|
|
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
@@ -333,7 +336,7 @@ test.each(synchronizationScopes)(
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: synchronizationScopes[0].label })).toBeEnabled();
|
|
|
|
@@ -365,7 +368,7 @@ test("starts Generate Missing for one configured database without confirmation",
|
|
|
|
|
renderPage({ rows: [makeDatabase()] });
|
|
|
|
|
|
|
|
|
|
const databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate Missing" }));
|
|
|
|
|
|
|
|
|
@@ -396,7 +399,7 @@ test("confirms Generate All replacement, supports cancel, and sends the database
|
|
|
|
|
renderPage({ rows: [makeDatabase()] });
|
|
|
|
|
|
|
|
|
|
const databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate All" }));
|
|
|
|
|
|
|
|
|
@@ -434,7 +437,7 @@ test("keeps the database selected and safely explains when no descriptions are e
|
|
|
|
|
renderPage({ rows: [makeDatabase()] });
|
|
|
|
|
|
|
|
|
|
const databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate Missing" }));
|
|
|
|
|
|
|
|
|
@@ -493,7 +496,7 @@ test.each([
|
|
|
|
|
]) client.setQueryData(queryKey, []);
|
|
|
|
|
|
|
|
|
|
const databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", {
|
|
|
|
|
name: scope === "all" ? "Generate All" : "Generate Missing",
|
|
|
|
@@ -568,7 +571,7 @@ test.each([
|
|
|
|
|
|
|
|
|
|
for (const database of rows.slice(0, selectedRows)) {
|
|
|
|
|
const row = await screen.findByRole("row", { name: new RegExp(database.workspaceName) });
|
|
|
|
|
await user.click(within(row).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(row).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
}
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
|
|
|
|
@@ -599,13 +602,13 @@ test("disables database-wide generation while a description generation is active
|
|
|
|
|
renderPage({ rows: [makeDatabase()] });
|
|
|
|
|
|
|
|
|
|
let databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate Missing" }));
|
|
|
|
|
expect(await screen.findByRole("complementary", { name: "Description generation" })).toBeVisible();
|
|
|
|
|
|
|
|
|
|
databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: "Generate All" }))
|
|
|
|
|
.toHaveAttribute("aria-disabled", "true");
|
|
|
|
@@ -630,8 +633,8 @@ test("selected database Actions confirms and deletes catalog tables for the full
|
|
|
|
|
|
|
|
|
|
const firstRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
const secondRow = await screen.findByRole("row", { name: /Radiology/ });
|
|
|
|
|
await user.click(within(firstRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(secondRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(firstRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(secondRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: "Delete all tables" })).toBeEnabled();
|
|
|
|
@@ -642,10 +645,10 @@ test("selected database Actions confirms and deletes catalog tables for the full
|
|
|
|
|
expect(screen.getByText(/database configurations and source databases are unchanged/i)).toBeVisible();
|
|
|
|
|
expect(cleanupBody).toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await user.click(within(secondRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(secondRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
expect(screen.queryByText(/Delete all catalog tables for/)).not.toBeInTheDocument();
|
|
|
|
|
expect(cleanupBody).toBeUndefined();
|
|
|
|
|
await user.click(within(secondRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(secondRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Delete all tables" }));
|
|
|
|
|
await waitFor(() => expect(screen.getByRole("button", { name: "Delete catalog tables" })).toHaveFocus());
|
|
|
|
@@ -681,7 +684,7 @@ test("presents completed synchronization steps as success and skips unneeded con
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const databaseRow = await screen.findByRole("row", { name: /Policlinico San Donato/ });
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(databaseRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Synchronize all columns" }));
|
|
|
|
|
|
|
|
|
@@ -1047,6 +1050,7 @@ const patientIdColumn: CatalogColumn = {
|
|
|
|
|
sourceComment: "Patient identifier",
|
|
|
|
|
description: null,
|
|
|
|
|
generatedDescription: null,
|
|
|
|
|
sensitive: false,
|
|
|
|
|
lastSyncedDatabaseVersion: 3,
|
|
|
|
|
lastSyncedAt: "2026-08-27T10:00:00Z",
|
|
|
|
|
version: 1,
|
|
|
|
@@ -1106,7 +1110,7 @@ test("selected table Actions exposes cleanup commands and sends synchronization
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
const tableRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
const synchronizeColumns = await screen.findByRole("menuitem", { name: "Synchronize columns" });
|
|
|
|
@@ -1413,8 +1417,8 @@ test("moves selected generated table descriptions and reports copied and skipped
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
const patientsRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
const visitsRow = await screen.findByRole("row", { name: /visits/ });
|
|
|
|
|
await user.click(within(patientsRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(visitsRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(patientsRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(visitsRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", {
|
|
|
|
|
name: "Move generated description to Description",
|
|
|
|
@@ -1451,6 +1455,7 @@ test("selects columns, moves generated descriptions, and refreshes only the affe
|
|
|
|
|
sourceComment: "Patient identifier",
|
|
|
|
|
description: "Old identifier",
|
|
|
|
|
generatedDescription: "Generated identifier",
|
|
|
|
|
sensitive: false,
|
|
|
|
|
lastSyncedDatabaseVersion: 3,
|
|
|
|
|
lastSyncedAt: "2026-08-27T10:00:00Z",
|
|
|
|
|
version: 1,
|
|
|
|
@@ -1491,7 +1496,7 @@ test("selects columns, moves generated descriptions, and refreshes only the affe
|
|
|
|
|
const tableQuery = ["catalog-tables", patientsTable.databaseId] as const;
|
|
|
|
|
const selectableRow = async (name: RegExp) => {
|
|
|
|
|
const rows = await screen.findAllByRole("row", { name });
|
|
|
|
|
const row = rows.find((candidate) => within(candidate).queryByRole("checkbox"));
|
|
|
|
|
const row = rows.find((candidate) => within(candidate).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
expect(row).toBeDefined();
|
|
|
|
|
return row!;
|
|
|
|
|
};
|
|
|
|
@@ -1501,8 +1506,8 @@ test("selects columns, moves generated descriptions, and refreshes only the affe
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const idRow = await selectableRow(/Patient identifier/);
|
|
|
|
|
const nameRow = await selectableRow(/Keep curated patient name/);
|
|
|
|
|
await user.click(within(idRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(nameRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(idRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(nameRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", {
|
|
|
|
|
name: "Move generated description to Description",
|
|
|
|
@@ -1549,9 +1554,9 @@ test("starts one selected column with the configured default model", async () =>
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
expect(columnRow).toBeDefined();
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate description" }));
|
|
|
|
|
|
|
|
|
@@ -1566,6 +1571,101 @@ test("starts one selected column with the configured default model", async () =>
|
|
|
|
|
expect(await screen.findByText("Description generation started for 1 column")).toBeVisible();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("reviews AI-sensitive-field suggestions as an editable draft and saves only changed columns", async () => {
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
|
const idColumn = { ...patientIdColumn, sensitive: false };
|
|
|
|
|
const nameColumn = {
|
|
|
|
|
...patientIdColumn,
|
|
|
|
|
id: "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
|
|
|
|
|
name: "name",
|
|
|
|
|
ordinalPosition: 2,
|
|
|
|
|
primaryKeyPosition: null,
|
|
|
|
|
isPrimaryKey: false,
|
|
|
|
|
description: "Patient name",
|
|
|
|
|
generatedDescription: "Name of the patient",
|
|
|
|
|
sensitive: false,
|
|
|
|
|
};
|
|
|
|
|
let columns = [idColumn, nameColumn];
|
|
|
|
|
let suggestionBody: unknown;
|
|
|
|
|
const patches: Array<{ columnId: string; body: unknown }> = [];
|
|
|
|
|
server.use(
|
|
|
|
|
http.get("/api/catalog/metadata-generation/models", () => HttpResponse.json({
|
|
|
|
|
models: [{ id: "local-qwen", label: "Local Qwen" }],
|
|
|
|
|
default: "local-qwen",
|
|
|
|
|
})),
|
|
|
|
|
http.get("/api/catalog/databases/:databaseId/tables", () => HttpResponse.json([patientsTable])),
|
|
|
|
|
http.get(
|
|
|
|
|
"/api/catalog/databases/:databaseId/tables/:tableId/columns",
|
|
|
|
|
() => HttpResponse.json(columns),
|
|
|
|
|
),
|
|
|
|
|
http.post(
|
|
|
|
|
"/api/catalog/databases/:databaseId/sensitive-data-suggestions",
|
|
|
|
|
async ({ request }) => {
|
|
|
|
|
suggestionBody = await request.json();
|
|
|
|
|
return HttpResponse.json({
|
|
|
|
|
suggestions: [
|
|
|
|
|
{ columnId: idColumn.id, sensitive: true },
|
|
|
|
|
{ columnId: nameColumn.id, sensitive: true },
|
|
|
|
|
{ columnId: "ffffffff-ffff-4fff-8fff-ffffffffffff", sensitive: true },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
http.patch(
|
|
|
|
|
"/api/catalog/databases/:databaseId/tables/:tableId/columns/:columnId",
|
|
|
|
|
async ({ params, request }) => {
|
|
|
|
|
const body = await request.json() as {
|
|
|
|
|
version: number;
|
|
|
|
|
description: string | null;
|
|
|
|
|
generatedDescription: string | null;
|
|
|
|
|
sensitive: boolean;
|
|
|
|
|
};
|
|
|
|
|
patches.push({ columnId: String(params.columnId), body });
|
|
|
|
|
const current = columns.find((column) => column.id === params.columnId)!;
|
|
|
|
|
const updated = { ...current, ...body, version: current.version + 1 };
|
|
|
|
|
columns = columns.map((column) => column.id === updated.id ? updated : column);
|
|
|
|
|
return HttpResponse.json(updated);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
renderPage({ rows: [makeDatabase({ connectionStatus: "reachable", testedVersion: 3 })] });
|
|
|
|
|
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
|
|
|
|
|
const idSensitive = await screen.findByRole("checkbox", { name: "Sensitive data for id" });
|
|
|
|
|
const nameSensitive = await screen.findByRole("checkbox", { name: "Sensitive data for name" });
|
|
|
|
|
expect(idSensitive).not.toBeChecked();
|
|
|
|
|
expect(nameSensitive).not.toBeChecked();
|
|
|
|
|
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Suggest sensitive fields" }));
|
|
|
|
|
|
|
|
|
|
await waitFor(() => expect(suggestionBody).toEqual({ modelId: "local-qwen" }));
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByRole("checkbox", { name: "Sensitive data for id" })).toBeChecked();
|
|
|
|
|
expect(screen.getByRole("checkbox", { name: "Sensitive data for name" })).toBeChecked();
|
|
|
|
|
});
|
|
|
|
|
expect(patches).toHaveLength(0);
|
|
|
|
|
|
|
|
|
|
await user.click(screen.getByRole("checkbox", { name: "Sensitive data for name" }));
|
|
|
|
|
expect(screen.getByRole("checkbox", { name: "Sensitive data for name" })).not.toBeChecked();
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Save sensitive fields" }));
|
|
|
|
|
|
|
|
|
|
await waitFor(() => expect(patches).toEqual([{
|
|
|
|
|
columnId: idColumn.id,
|
|
|
|
|
body: {
|
|
|
|
|
version: idColumn.version,
|
|
|
|
|
description: idColumn.description,
|
|
|
|
|
generatedDescription: idColumn.generatedDescription,
|
|
|
|
|
sensitive: true,
|
|
|
|
|
},
|
|
|
|
|
}]));
|
|
|
|
|
expect(await screen.findByText("Sensitive fields saved")).toBeVisible();
|
|
|
|
|
expect(screen.getByRole("checkbox", { name: "Sensitive data for id" })).toBeChecked();
|
|
|
|
|
expect(screen.getByRole("checkbox", { name: "Sensitive data for name" })).not.toBeChecked();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("polls a description run and renders its events in sequence order", async () => {
|
|
|
|
|
const user = userEvent.setup();
|
|
|
|
|
const queuedRun = makeDescriptionGenerationRun();
|
|
|
|
@@ -1617,8 +1717,8 @@ test("polls a description run and renders its events in sequence order", async (
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate description" }));
|
|
|
|
|
|
|
|
|
@@ -1699,8 +1799,8 @@ test("refreshes Catalog Tables and Catalog Columns after column generation compl
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate description" }));
|
|
|
|
|
|
|
|
|
@@ -1708,7 +1808,7 @@ test("refreshes Catalog Tables and Catalog Columns after column generation compl
|
|
|
|
|
await waitFor(() => expect(columnReads).toBe(2));
|
|
|
|
|
await waitFor(() => expect(tableReads).toBe(2));
|
|
|
|
|
expect(within((await screen.findAllByRole("row", { name: /Stable patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"))!).getByText("Stable patient identifier")).toBeVisible();
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }))!).getByText("Stable patient identifier")).toBeVisible();
|
|
|
|
|
expect(client.getQueryState(unrelatedColumnsQuery)?.isInvalidated).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@@ -1732,8 +1832,8 @@ test("keeps the selected column and shows a safe message when generation cannot
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate description" }));
|
|
|
|
|
|
|
|
|
@@ -1799,8 +1899,8 @@ test("shows a basic failed run without exposing private model or provider fields
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate description" }));
|
|
|
|
|
|
|
|
|
@@ -1851,10 +1951,10 @@ test("offers generation and consolidation for multiple selected columns", async
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const idRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
const nameRow = (await screen.findAllByRole("row", { name: /Patient name/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(idRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(idRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: "Generate description" })).toBeEnabled();
|
|
|
|
|
expect(screen.getByRole("menuitem", {
|
|
|
|
@@ -1862,7 +1962,7 @@ test("offers generation and consolidation for multiple selected columns", async
|
|
|
|
|
})).toBeEnabled();
|
|
|
|
|
await user.keyboard("{Escape}");
|
|
|
|
|
|
|
|
|
|
await user.click(within(nameRow!).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(nameRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
const generate = await screen.findByRole("menuitem", { name: "Generate descriptions" });
|
|
|
|
|
expect(generate).toBeEnabled();
|
|
|
|
@@ -1901,7 +2001,7 @@ test.each([
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
const tableRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: "Generate description" }))
|
|
|
|
|
.toHaveAttribute("aria-disabled", "true");
|
|
|
|
@@ -1909,8 +2009,8 @@ test.each([
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Clear" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: "Generate description" }))
|
|
|
|
@@ -1943,8 +2043,8 @@ test("disables another generation start while the selected-column run is active"
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View columns for patients" }));
|
|
|
|
|
const columnRow = (await screen.findAllByRole("row", { name: /Patient identifier/ }))
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox"));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox"));
|
|
|
|
|
.find((row) => within(row).queryByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(within(columnRow!).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Generate description" }));
|
|
|
|
|
expect(await screen.findByRole("complementary", { name: "Description generation" })).toBeVisible();
|
|
|
|
@@ -1956,7 +2056,7 @@ test("disables another generation start while the selected-column run is active"
|
|
|
|
|
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Back to tables" }));
|
|
|
|
|
const tableRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
expect(await screen.findByRole("menuitem", { name: "Generate description" }))
|
|
|
|
|
.toHaveAttribute("aria-disabled", "true");
|
|
|
|
@@ -1982,7 +2082,7 @@ test("disables selected description consolidation without database.manage", asyn
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
const tableRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
|
|
|
|
|
expect(await screen.findByRole("menuitem", {
|
|
|
|
@@ -2011,7 +2111,7 @@ test("shows an operation conflict without clearing selected descriptions or refr
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
const tableRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", {
|
|
|
|
|
name: "Move generated description to Description",
|
|
|
|
@@ -2045,7 +2145,7 @@ test("selected table Actions confirms and deletes incoming and outgoing relation
|
|
|
|
|
await user.click(await screen.findByRole("button", { name: "View Policlinico San Donato" }));
|
|
|
|
|
await user.click(screen.getByRole("tab", { name: "Tables" }));
|
|
|
|
|
const tableRow = await screen.findByRole("row", { name: /patients/ });
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Delete all relationships" }));
|
|
|
|
|
|
|
|
|
@@ -2053,10 +2153,10 @@ test("selected table Actions confirms and deletes incoming and outgoing relation
|
|
|
|
|
expect(screen.getByText(/incoming and outgoing relationships/i)).toBeVisible();
|
|
|
|
|
expect(cleanupBody).toBeUndefined();
|
|
|
|
|
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
expect(screen.queryByText("Delete all relationships for 1 table?")).not.toBeInTheDocument();
|
|
|
|
|
expect(cleanupBody).toBeUndefined();
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox"));
|
|
|
|
|
await user.click(within(tableRow).getByRole("checkbox", { name: /toggle row selection/i }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Actions" }));
|
|
|
|
|
await user.click(await screen.findByRole("menuitem", { name: "Delete all relationships" }));
|
|
|
|
|
await user.click(screen.getByRole("button", { name: "Delete relationships" }));
|
|
|
|
@@ -2133,6 +2233,7 @@ test("navigates from a table to columns and from the database to physical relati
|
|
|
|
|
sourceComment: "Patient identifier",
|
|
|
|
|
description: null,
|
|
|
|
|
generatedDescription: null,
|
|
|
|
|
sensitive: false,
|
|
|
|
|
lastSyncedDatabaseVersion: 3,
|
|
|
|
|
lastSyncedAt: "2026-08-27T10:00:00Z",
|
|
|
|
|
version: 1,
|
|
|
|
|