mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
test(e2e): import lab results from a CSV on an account of its own
The import journey ran on the shared account in both projects, so one project's duplicate verdict could rest on the other's import. It now runs on the labs journey's account, emptied first, checks that the dry run writes nothing and the import writes exactly the accepted row, and finds the result on the labs page before the second run.
This commit is contained in:
1 parent
f185855d76
commit
0bf6a54be0
2 files changed
+83
-20
No files matched your search
@@ -1,29 +1,69 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
|
||||
import { expect, test } from "./setup/test";
|
||||
|
||||
import { STORAGE_STATE_PATH } from "./setup/global-setup";
|
||||
import {
|
||||
criticalAccount,
|
||||
criticalStorageState,
|
||||
resetCriticalAccount,
|
||||
} from "./setup/critical-fixture";
|
||||
|
||||
/**
|
||||
* Lab results from a spreadsheet (#1215), at phone width, against the real
|
||||
* server: the mapping is suggested from the headers, the check reports a
|
||||
* refused row by line and writes nothing, the import writes the rest, and a
|
||||
* second import of the same file only finds duplicates.
|
||||
* Lab results from a spreadsheet (#1215), against the real server: the
|
||||
* mapping is suggested from the headers, the check reports a refused row by
|
||||
* line and writes nothing, the import writes the rest, the imported row is on
|
||||
* the labs page, and a second import of the same file only finds duplicates.
|
||||
*
|
||||
* The account is the labs journey's own, one per project
|
||||
* (`critical-fixture.ts`), emptied of results first. Before v1.46 this ran on
|
||||
* the shared account in both projects, so the "only duplicates" verdict of
|
||||
* one project could be the other project's first import.
|
||||
*/
|
||||
|
||||
const ANALYTE = "E2E Marker CSV";
|
||||
|
||||
function csv(): string {
|
||||
const day = new Date(Date.now() - 30 * 86_400_000).toISOString().slice(0, 10);
|
||||
return [
|
||||
"Analyte;Value;Unit;Date",
|
||||
`E2E Marker CSV;5,4;mmol/L;${day}`,
|
||||
`E2E Marker CSV;1.234;mmol/L;${day}`,
|
||||
// A decimal comma, as a German lab export writes it.
|
||||
`${ANALYTE};5,4;mmol/L;${day}`,
|
||||
// Either 1.234 or 1234: refused as ambiguous rather than guessed.
|
||||
`${ANALYTE};1.234;mmol/L;${day}`,
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
/** The account's lab results, as the list route answers them. */
|
||||
async function storedResults(
|
||||
page: Page,
|
||||
): Promise<Array<{ analyte: string; value: number | null; unit: string }>> {
|
||||
const res = await page.request.get("/api/labs");
|
||||
expect(res.status()).toBe(200);
|
||||
const { data } = (await res.json()) as {
|
||||
data: {
|
||||
results: Array<{ analyte: string; value: number | null; unit: string }>;
|
||||
};
|
||||
};
|
||||
return data.results.map(({ analyte, value, unit }) => ({
|
||||
analyte,
|
||||
value,
|
||||
unit,
|
||||
}));
|
||||
}
|
||||
|
||||
test.describe("record CSV import", () => {
|
||||
test.use({
|
||||
storageState: STORAGE_STATE_PATH,
|
||||
viewport: { width: 390, height: 844 },
|
||||
test.use({ storageState: criticalStorageState("labs") });
|
||||
|
||||
test.beforeEach(async ({}, testInfo) => {
|
||||
// Fixture hygiene: what a previous run or a retry left on the account.
|
||||
await resetCriticalAccount(criticalAccount("labs", testInfo), [
|
||||
"DELETE FROM lab_results WHERE user_id = $1",
|
||||
]);
|
||||
});
|
||||
|
||||
test("checks, imports and then only finds duplicates", async ({ page }) => {
|
||||
test("checks, imports, lists the result and then only finds duplicates @critical", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/settings/export");
|
||||
await page.locator('[data-slot="record-import-open-labs"]').click();
|
||||
const sheet = page.locator('[data-slot="record-import-sheet"]');
|
||||
@@ -48,19 +88,42 @@ test.describe("record CSV import", () => {
|
||||
await expect(
|
||||
page.locator('[data-slot="record-import-error-row"]'),
|
||||
).toHaveCount(1);
|
||||
// The check is a dry run.
|
||||
expect(await storedResults(page)).toEqual([]);
|
||||
|
||||
await page.locator('[data-slot="record-import-run"]').click();
|
||||
await expect(
|
||||
page.locator('[data-slot="record-import-done"]'),
|
||||
).toBeVisible();
|
||||
expect(await storedResults(page)).toEqual([
|
||||
{ analyte: ANALYTE, value: 5.4, unit: "mmol/L" },
|
||||
]);
|
||||
|
||||
// Second run of the same file.
|
||||
await page.keyboard.press("Escape");
|
||||
await page.locator('[data-slot="record-import-open-labs"]').click();
|
||||
await page.locator('[data-slot="record-import-file"]').setInputFiles(file);
|
||||
await page.locator('[data-slot="record-import-check"]').click();
|
||||
await expect(
|
||||
page.locator('[data-slot="record-import-run"]'),
|
||||
).toBeDisabled();
|
||||
await test.step("the result is on the labs page", async () => {
|
||||
await page.goto("/labs");
|
||||
const analyte = page
|
||||
.locator('[data-slot="lab-list-analyte"]')
|
||||
.filter({ hasText: ANALYTE })
|
||||
.filter({ visible: true });
|
||||
await expect(analyte).toHaveCount(1);
|
||||
// The cell the name heads carries the latest reading under it.
|
||||
await expect(analyte.locator("xpath=../..")).toContainText("5.4");
|
||||
});
|
||||
|
||||
await test.step("a second run of the same file", async () => {
|
||||
await page.goto("/settings/export");
|
||||
await page.locator('[data-slot="record-import-open-labs"]').click();
|
||||
await page
|
||||
.locator('[data-slot="record-import-file"]')
|
||||
.setInputFiles(file);
|
||||
await page.locator('[data-slot="record-import-check"]').click();
|
||||
await expect(
|
||||
page.locator('[data-slot="record-import-checked"]'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.locator('[data-slot="record-import-run"]'),
|
||||
).toBeDisabled();
|
||||
expect(await storedResults(page)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -49,7 +49,7 @@ const E2E = join(process.cwd(), "e2e");
|
||||
* the set is the release gate, so a journey that loses its tag is a change
|
||||
* somebody should see here.
|
||||
*/
|
||||
const CRITICAL_TEST_FLOOR = 12;
|
||||
const CRITICAL_TEST_FLOOR = 13;
|
||||
|
||||
/** A test whose title literal carries the tag, however the call is spelled. */
|
||||
const CRITICAL_TEST =
|
||||
|
||||
Reference in new issue
Block a user