On this page
Core scenarios to testPermission-groups screenEdge cases worth deliberate coverageRegression watchFor Quality
Core scenarios to test
For each of New Expense, Edit Expense, Add Expense Payment, Edit Expense Payment, Bulk Expense Payment, New Salary Adjustment, Edit Salary Adjustment — on both clinic-web and clinic-mobile:
| Scenario | Permission | Expected |
|---|---|---|
| Create new record | Missing | Date field disabled in UI; saved record is dated today, regardless of any date value sent |
| Create new record | Granted | Date field enabled; saved record uses the picked date |
| Edit existing record | Missing | Date field disabled in UI; saved record's date is unchanged from before the edit |
| Edit existing record | Granted | Date field enabled; saved record uses the newly picked date |
Owner (DO_ALL) | N/A | Always behaves as if granted, regardless of the specific permission checkbox |
Permission-groups screen
- Change Creation Date checkbox only renders for the Expenses and Salary
Hub rows on the Settings tab — confirm it's absent elsewhere.
- Checkbox is disabled until Add New is checked for that row.
- Unchecking Add New after Change Creation Date was checked — confirm
the created-at checkbox clears too (don't leave an orphaned permission granted with no add access).
- Checking Change Creation Date without Add New should be impossible
through the UI — worth a direct-request/API check too, since permission checks live server-side and the UI restriction alone isn't the security boundary.
Edge cases worth deliberate coverage
- **Editing an unpaid expense and marking it "Paid" in the same edit, without
the permission.** The expense's own date stays unchanged (or server default if it had none), but the new payment row created by that edit falls back to today, not the expense's date — see editExpense.js:161 (createdAt: expenseDate || dayjs().toDate()). Confirm this is the intended behavior, since it means the expense and its just-created payment can end up on different dates in this specific path.
- Expense payments used to be owner-only (
doAll); they're now gated by
EXPENSES_CREATED_AT. Test that a non-owner with only that permission (and not DO_ALL) can now set an expense payment's date — this is a deliberate widening, confirm it isn't accidentally still blocked somewhere, and confirm a non-owner without the permission still can't.
- Bulk expense payments (
addExpensesBulkPayment) share the exact same
permission as single payments — verify the bulk-pay flow respects it too, not just the single-payment dialog.
- Salary adjustment tied to a lab-order expense: editing an expense that
has a linked salaryAdjustment recalculates the adjustment's amount (unrelated to this PR) — verify that recalculation isn't affected by the date-permission changes, since both paths touch the same resolver.
- Cross-permission independence: a group with
EXPENSES_CREATED_ATbut
not SALARY_ADJUSTMENT_CREATED_AT (or vice versa) should show one form enabled and the other disabled — the two permissions must not leak into each other.
- Server-side enforcement, not just UI: since the UI disables the field
but the permission check is server-side (getPermittedDate / getCreatedAt), verify that a crafted GraphQL request with a date / createdAt argument from an unpermitted user is still ignored server-side — don't rely on manual UI testing alone for this.
- Translations: the tooltip/help string (
app.noCreatedAtPermission) was
added to all locale files (ar, ckb, el, en, fr, it, ku, nl, pl) — spot-check at least the RTL locale (Arabic) renders correctly in the tooltip.
Regression watch
- Appointments and patient-record "created at" permissions
(APPOINTMENTS_CREATED_AT, PATIENTS_DETAILS_CREATED_AT, etc.) are untouched by this PR but use the same helper pattern — a shared-helper bug here could regress those too. Worth a smoke test on at least one of them.
- The Group.js tab-to-column mapping was reindexed
(packages/clinic-web/src/components/dashboard/settings/Groups/Group.js:235) — confirm no other tab's column set shifted unexpectedly (the DHS Settings tab column index was untouched — columns[12] — but worth a quick check that every tab still renders its intended columns).