mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
175 lines
6.2 KiB
TypeScript
175 lines
6.2 KiB
TypeScript
/**
|
|
* The audiences the suite drives, and the fixture data they hang off.
|
|
*
|
|
* Every persona lives in the **Active** railway organization. That is not a
|
|
* style choice: IAM's login SQL joins `o.status = $2` when it builds a session's
|
|
* `employee` array, so a persona in a Debarred org logs in fine but arrives with
|
|
* NO organization context, and then 403s on nearly every HR/Finance call with a
|
|
* message that looks nothing like the real cause. 13 of 15 orgs in this database
|
|
* are Debarred (Addis Ababa sub-cities inherited from the Smart Office lineage,
|
|
* plus rows named after applications rather than legal entities) — they hold ~10
|
|
* employees between them. The railway org holds 2,416 and the whole 7-level
|
|
* position hierarchy. See docs/hr-finance-ui-e2e-matrix.md §1.2.
|
|
*/
|
|
|
|
/** Ethio Djibouti Standard Gauge Railway Share Company — status Active. */
|
|
export const ORG_ID = "8abeba98-502e-4025-b048-c352dcfd198d";
|
|
export const UNIT_ID = "5251ba4d-1dfe-4480-b3d9-da96bd409f72";
|
|
|
|
/**
|
|
* A real parent/child position pair, used for the leave-approval scenarios.
|
|
* Leave L1 approval is deliberately NOT a role grant — the first approver is
|
|
* resolved through the IAM position hierarchy at request time — so a manager and
|
|
* a direct report have to be genuinely related in that tree for the approval
|
|
* scenarios to mean anything. Picking two unrelated positions would make the
|
|
* test pass for the wrong reason.
|
|
*/
|
|
export const MANAGER_POSITION_ID = "6e1b52e0-7c9f-41cf-a277-b738b398b531"; // Team Leader, Online Booking System
|
|
export const REPORT_POSITION_ID = "3ceca5d2-4468-4185-aca2-72723bc6eb01"; // Officer, Operation Data Management
|
|
|
|
/** A position unrelated to the pair above, for personas whose reporting line is irrelevant. */
|
|
export const STAFF_POSITION_ID = "c5fbfcb5-d4d2-4e0b-8f0c-961f94216c82"; // Administrative Assistant I
|
|
|
|
export type Persona = {
|
|
/** Playwright project name and storageState filename. */
|
|
key: string;
|
|
username: string;
|
|
email: string;
|
|
password: string;
|
|
nameEn: string;
|
|
nameAm: string;
|
|
/** IAM role key granted in ORG_ID. */
|
|
roleKey: string;
|
|
positionId: string;
|
|
/** Which app this persona signs into. */
|
|
app: "hr" | "finance";
|
|
};
|
|
|
|
/**
|
|
* One password for every fixture persona. These accounts exist only in
|
|
* `smart_office_e2e`, a disposable clone; the value is checked in deliberately
|
|
* so a run is reproducible without a secret store.
|
|
*/
|
|
export const E2E_PASSWORD = "E2ePersona@2026";
|
|
|
|
export const PERSONAS: Persona[] = [
|
|
{
|
|
key: "hr-manager",
|
|
username: "e2e_hr_manager",
|
|
email: "e2e.hr.manager@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E HR Manager",
|
|
nameAm: "ኢ2ኢ የሰው ሀብት ሥራ አስኪያጅ",
|
|
roleKey: "hr_manager",
|
|
positionId: MANAGER_POSITION_ID,
|
|
app: "hr",
|
|
},
|
|
{
|
|
key: "hr-employee",
|
|
username: "e2e_hr_employee",
|
|
email: "e2e.hr.employee@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E HR Employee",
|
|
nameAm: "ኢ2ኢ ሠራተኛ",
|
|
// The narrowest HR role — self-service only. This is the persona the
|
|
// negative gating scenarios need: it must be REFUSED the manage screens.
|
|
roleKey: "employee_self_service",
|
|
positionId: REPORT_POSITION_ID,
|
|
app: "hr",
|
|
},
|
|
{
|
|
key: "hr-payroll-admin",
|
|
username: "e2e_payroll_admin",
|
|
email: "e2e.payroll.admin@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E Payroll Administrator",
|
|
nameAm: "ኢ2ኢ የደመወዝ አስተዳዳሪ",
|
|
roleKey: "payroll_admin",
|
|
positionId: STAFF_POSITION_ID,
|
|
app: "hr",
|
|
},
|
|
{
|
|
key: "hr-recruitment-officer",
|
|
username: "e2e_recruiter",
|
|
email: "e2e.recruiter@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E Recruitment Officer",
|
|
nameAm: "ኢ2ኢ የቅጥር ኦፊሰር",
|
|
roleKey: "recruitment_officer",
|
|
positionId: STAFF_POSITION_ID,
|
|
app: "hr",
|
|
},
|
|
{
|
|
key: "finance-manager",
|
|
username: "e2e_finance_manager",
|
|
email: "e2e.finance.manager@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E Finance Manager",
|
|
nameAm: "ኢ2ኢ የፋይናንስ ሥራ አስኪያጅ",
|
|
roleKey: "finance_manager",
|
|
positionId: STAFF_POSITION_ID,
|
|
app: "finance",
|
|
},
|
|
{
|
|
key: "finance-accountant",
|
|
username: "e2e_accountant",
|
|
email: "e2e.accountant@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E Accountant",
|
|
nameAm: "ኢ2ኢ ሒሳብ ሠራተኛ",
|
|
roleKey: "accountant",
|
|
positionId: STAFF_POSITION_ID,
|
|
app: "finance",
|
|
},
|
|
{
|
|
key: "finance-cashier",
|
|
username: "e2e_cashier",
|
|
email: "e2e.cashier@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E Cashier",
|
|
nameAm: "ኢ2ኢ ገንዘብ ያዥ",
|
|
// Narrowest Finance role — may record a payment but must NOT approve a bill.
|
|
roleKey: "cashier",
|
|
positionId: STAFF_POSITION_ID,
|
|
app: "finance",
|
|
},
|
|
{
|
|
key: "finance-auditor",
|
|
username: "e2e_auditor",
|
|
email: "e2e.auditor@edr.local",
|
|
password: E2E_PASSWORD,
|
|
nameEn: "E2E Finance Auditor",
|
|
nameAm: "ኢ2ኢ የሒሳብ ተቆጣጣሪ",
|
|
roleKey: "finance_auditor",
|
|
positionId: STAFF_POSITION_ID,
|
|
app: "finance",
|
|
},
|
|
];
|
|
|
|
export const personaByKey = (key: string): Persona => {
|
|
const found = PERSONAS.find((p) => p.key === key);
|
|
if (!found) {
|
|
throw new Error(`No persona "${key}" — known: ${PERSONAS.map((p) => p.key).join(", ")}`);
|
|
}
|
|
return found;
|
|
};
|
|
|
|
/**
|
|
* Verified against the running services on 2026-08-24 — each persona's actual
|
|
* boundary, not what the role matrix says it should be. Kept here because a
|
|
* regression in the seed or the role grants shows up as a boundary shift, and
|
|
* this table is what a failing gating test should be read against.
|
|
*
|
|
* HR (`own-leave` / `approvals` / `employees` / `payroll` / `recruitment`):
|
|
* hr-employee 200 403 403 403 403
|
|
* hr-manager 200 200 200 200 200
|
|
* hr-payroll-admin 200 403 200 200 403
|
|
* hr-recruitment-officer 200 403 200 403 200
|
|
*
|
|
* Finance (`accounts` / `journals` / `create-journal` / `budgets` / `cutover`):
|
|
* finance-manager 200 200 past-guard 200 200
|
|
* finance-accountant 200 200 past-guard 200 200
|
|
* finance-cashier 200 200 403 403 200
|
|
* finance-auditor 200 200 403 200 200
|
|
*/
|