mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Adding all the tests and fixes to the passengers app
This commit is contained in:
79
e2e-ui/specs/backoffice/config-validation.spec.ts
Normal file
79
e2e-ui/specs/backoffice/config-validation.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { API_URL, ROUTE_ID, staffToken } from "../../fixtures/data";
|
||||
import { UI_IDS } from "../../../apps/edr-passenger-api/test/fixtures/seed-ui";
|
||||
|
||||
/**
|
||||
* Track B — server-side validation gaps and the promo field-name mismatch. Each test calls the same
|
||||
* passenger-api endpoints the backoffice forms hit, proving the client-side guards are the ONLY guard
|
||||
* (the API accepts values the forms block) or that a UI/DTO field-name split silently breaks a config.
|
||||
*/
|
||||
function auth() {
|
||||
return { Authorization: `Bearer ${staffToken()}` };
|
||||
}
|
||||
|
||||
test("BC-8 ✅ a promo over 100% is rejected by the API (max validation, M-2)", async ({ request }) => {
|
||||
// percentOff must be bounded 0..100 at the DTO layer (the backoffice form has no such check).
|
||||
const res = await request.post(`${API_URL}/promos`, {
|
||||
headers: auth(),
|
||||
data: { code: `E2E_OVER100_${Date.now()}`, title: "over", percentOff: 200, validUntil: "2030-01-01T00:00:00Z", active: true },
|
||||
});
|
||||
expect(res.status()).toBe(400); // ✅ 200% discount rejected
|
||||
|
||||
// A valid promo (≤100%) still succeeds.
|
||||
const okRes = await request.post(`${API_URL}/promos`, {
|
||||
headers: auth(),
|
||||
data: { code: `E2E_OK_${Date.now()}`, title: "ok", percentOff: 50, validUntil: "2030-01-01T00:00:00Z", active: true },
|
||||
});
|
||||
expect(okRes.ok()).toBeTruthy();
|
||||
const promo = (await okRes.json())?.data ?? {};
|
||||
await request.delete(`${API_URL}/promos/${promo.id}`, { headers: auth() }).catch(() => {});
|
||||
});
|
||||
|
||||
test("PB-7 🔴 a promo created with the backoffice UI field names is inert (field-name mismatch)", async ({ request }) => {
|
||||
// The backoffice /promos form sends discountType/discountValue/isActive, but the DTO reads
|
||||
// percentOff/amountOffMinor/active — so the sent discount is dropped and the promo saves at 0.
|
||||
const res = await request.post(`${API_URL}/promos`, {
|
||||
headers: auth(),
|
||||
data: { code: `E2E_UIFIELDS_${Date.now()}`, title: "uifields", discountType: "PERCENTAGE", discountValue: 25, isActive: true, validUntil: "2030-01-01T00:00:00Z" },
|
||||
});
|
||||
expect(res.ok()).toBeTruthy();
|
||||
const promo = (await res.json())?.data ?? {};
|
||||
expect(promo.discountValue).toBe(0); // 🔴 the 25% the UI "set" was silently dropped
|
||||
await request.delete(`${API_URL}/promos/${promo.id}`, { headers: auth() }).catch(() => {});
|
||||
});
|
||||
|
||||
test("BC-9 ✅ a negative seat-hold duration is rejected by /config (DTO validation, M-3)", async ({ request }) => {
|
||||
// The settings form has min=1 max=60; the API must now enforce the same at the DTO layer.
|
||||
const res = await request.patch(`${API_URL}/config`, {
|
||||
headers: auth(),
|
||||
data: { seat_hold_duration_minutes: "-1" },
|
||||
});
|
||||
expect(res.status()).toBe(400); // ✅ negative duration rejected
|
||||
|
||||
// A sane value in range still succeeds and is stored.
|
||||
const ok = await request.patch(`${API_URL}/config`, { headers: auth(), data: { seat_hold_duration_minutes: "15" } });
|
||||
expect(ok.ok()).toBeTruthy();
|
||||
expect(((await ok.json())?.data ?? {}).seat_hold_duration_minutes).toBe("15");
|
||||
});
|
||||
|
||||
test("BC-10 ✅ a schedule with a past departure is rejected by the API (past-date block, M-4)", async ({ request }) => {
|
||||
// The schedules form only checks arrival > departure — the API must ALSO reject a past departure.
|
||||
const past = new Date("2020-01-02T06:00:00.000Z");
|
||||
const arrive = new Date("2020-01-02T10:00:00.000Z");
|
||||
const res = await request.post(`${API_URL}/schedules`, {
|
||||
headers: auth(),
|
||||
data: { trainId: UI_IDS.train, routeId: ROUTE_ID, departureAt: past.toISOString(), arrivalAt: arrive.toISOString() },
|
||||
});
|
||||
expect(res.status()).toBe(400); // ✅ past-dated schedule rejected
|
||||
|
||||
// A future schedule (a different day than the seeded one) is still accepted.
|
||||
const dep = new Date(Date.now() + 30 * 864e5); dep.setUTCHours(6, 0, 0, 0);
|
||||
const arr = new Date(dep.getTime() + 4 * 3600e3);
|
||||
const okRes = await request.post(`${API_URL}/schedules`, {
|
||||
headers: auth(),
|
||||
data: { trainId: UI_IDS.train, routeId: ROUTE_ID, departureAt: dep.toISOString(), arrivalAt: arr.toISOString() },
|
||||
});
|
||||
expect(okRes.ok()).toBeTruthy();
|
||||
const sched = (await okRes.json())?.data ?? {};
|
||||
await request.delete(`${API_URL}/schedules/${sched.id}`, { headers: auth() }).catch(() => {});
|
||||
});
|
||||
19
e2e-ui/specs/backoffice/currencies.smoke.spec.ts
Normal file
19
e2e-ui/specs/backoffice/currencies.smoke.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Backoffice smoke (Track B foundation): the staff storageState authenticates past the middleware
|
||||
* cookie gate, /currencies loads its list from the API, and the add-rate control is reachable.
|
||||
* Proves staff auth (cookie + localStorage + API token) is fully wired.
|
||||
*/
|
||||
test("backoffice: staff can load /currencies and reach the add-rate control", async ({ page }) => {
|
||||
await page.goto("/currencies", { waitUntil: "domcontentloaded" });
|
||||
|
||||
// Not bounced to /login (middleware cookie gate passed).
|
||||
await expect(page).not.toHaveURL(/\/login/);
|
||||
|
||||
// The page rendered a currencies view with a seeded currency and an add control.
|
||||
await expect(page.getByText(/ETB|USD|DJF/).first()).toBeVisible({ timeout: 20_000 });
|
||||
await expect(
|
||||
page.getByRole("button", { name: /add/i }).first(),
|
||||
).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user