feat(quality): add resolution UI for all five rule types and manual scan
DataQualityIssueDetail showed raw JSON as the primary interface for four of five rule types, with no resolution surface beyond generic defer/reject. Add a bounded panel per rule type (provide missing fields, retain/correct an odometer reading, block one of two overlapping bookings, apply the recommended vehicle status) wired to the new backend endpoints, and move raw evidence behind a <details> disclosure. Add a "Run quality scan" action to the workbench (confirmation, progress, per-rule result counts, auto refresh) -- the endpoint already existed but had no UI trigger.
This commit is contained in:
@@ -162,6 +162,76 @@ test("data quality issue detail: defer and reject buttons work", async ({ page,
|
||||
await expect(page.getByText("deferred", { exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
test("data quality: providing missing fields resolves a vehicle issue", async ({ page, request }) => {
|
||||
await resetDemoData(request);
|
||||
await page.goto("/data-quality/DQ-DEMO-ATTENTION");
|
||||
await expect(page.getByRole("heading", { name: "DQ-DEMO-ATTENTION" })).toBeVisible();
|
||||
|
||||
await page.getByLabel("Registration number").fill("TST-777");
|
||||
await page.getByLabel("Make").fill("TestMake");
|
||||
await page.getByLabel("Model").fill("TestModel");
|
||||
await page.getByLabel("Location").fill("Depot");
|
||||
await page.getByRole("button", { name: "Save and re-check" }).click();
|
||||
|
||||
await expect(page.getByText("resolved", { exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
test("data quality: resolving a booking overlap blocks one booking", async ({ page, request }) => {
|
||||
await resetDemoData(request);
|
||||
await page.goto("/data-quality/DQ-DEMO-OVERLAP");
|
||||
await expect(page.getByRole("heading", { name: "DQ-DEMO-OVERLAP" })).toBeVisible();
|
||||
|
||||
await page.getByRole("radio", { name: /Block BK-DEMO-OVERLAP-A/ }).check();
|
||||
await page.getByRole("button", { name: /^Block BK-DEMO-OVERLAP-A$/ }).click();
|
||||
|
||||
await expect(page.getByText("resolved", { exact: true })).toBeVisible();
|
||||
const booking = await page.request.get("/api/v1/bookings/BK-DEMO-OVERLAP-A");
|
||||
expect((await booking.json()).status).toBe("blocked");
|
||||
});
|
||||
|
||||
test("data quality: applying the recommended status resolves a vehicle conflict", async ({
|
||||
page,
|
||||
request,
|
||||
}) => {
|
||||
await resetDemoData(request);
|
||||
await page.goto("/data-quality/DQ-DEMO-STATUS");
|
||||
await expect(page.getByRole("heading", { name: "DQ-DEMO-STATUS" })).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "Calculate and apply recommended status" }).click();
|
||||
await page.getByRole("button", { name: "Yes, apply" }).click();
|
||||
|
||||
await expect(page.getByText("Applied", { exact: false })).toBeVisible();
|
||||
});
|
||||
|
||||
test("data quality: retaining canonical resolves an odometer regression issue", async ({
|
||||
page,
|
||||
request,
|
||||
}) => {
|
||||
await resetDemoData(request);
|
||||
const issues = await (
|
||||
await page.request.get("/api/v1/data-quality/issues", {
|
||||
params: { rule_type: "odometer_regression", status: "open" },
|
||||
})
|
||||
).json();
|
||||
const target = issues[0];
|
||||
|
||||
await page.goto(`/data-quality/${target.public_ref}`);
|
||||
await expect(page.getByRole("heading", { name: target.public_ref })).toBeVisible();
|
||||
await page.getByRole("radio", { name: /Retain canonical/ }).check();
|
||||
await page.getByRole("button", { name: "Resolve issue" }).click();
|
||||
|
||||
await expect(page.getByText("resolved", { exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
test("data quality: manual scan runs and shows a result summary", async ({ page, request }) => {
|
||||
await resetDemoData(request);
|
||||
await page.goto("/data-quality");
|
||||
await page.getByRole("button", { name: "Run quality scan" }).click();
|
||||
await page.getByRole("button", { name: "Yes, run scan" }).click();
|
||||
|
||||
await expect(page.getByText(/Scan complete/)).toBeVisible();
|
||||
});
|
||||
|
||||
test("automation page: status filter and retry button work", async ({ page, request }) => {
|
||||
await resetDemoData(request);
|
||||
await page.goto("/automation");
|
||||
|
||||
Reference in New Issue
Block a user