Skip to content

Add payment module E2E tests for Social Protection#99

Open
Shahzaibahmad97 wants to merge 10 commits intodevelopfrom
feature/payments-e2e-tests
Open

Add payment module E2E tests for Social Protection#99
Shahzaibahmad97 wants to merge 10 commits intodevelopfrom
feature/payments-e2e-tests

Conversation

@Shahzaibahmad97
Copy link
Copy Markdown
Contributor

@Shahzaibahmad97 Shahzaibahmad97 commented Apr 2, 2026

Description

Adds Cypress E2E test coverage for the Payments domain — payment plans, payment cycles, payment points, payrolls, and payroll reconciliation. This PR also includes a foundational refactor of the monolithic commands.js into domain-scoped modules and hardens shared support commands (login/logout resilience, MUI date input helper, frontend module config, searcher + form helpers, constants module).

Type of Change

  • Feature
  • Bug fix
  • Chore (Refactor, Docs, CI/CD)
  • Other, please specify

Related Issue(s) / Task(s)


Refactor: Command Module Split

  • Split monolithic cypress/support/commands.js into domain-scoped modules under commands/ (auth, admin, ui, form, searcher, location, programs, registry, tasks, grievance, payments)
  • Barrel commands/index.js registers all modules
  • Add date.js helper (getTodayFormatted)
  • Add shared constants.js (TIMEOUTS, CALC_RULES, PAYROLL_STATUS, PAYMENT_CYCLE_STATUS)
  • Per-folder command reference docs at cypress/support/commands/COMMANDS.md and cypress/support/commands/payments/COMMANDS.md so spec authors can pick existing helpers instead of re-implementing UI steps

Refactor: Shared Support Command Enhancements

  • Harden cy.login() — check DOM for already-authenticated state before entering credentials; clear cookies for clean state; increased timeout to 30s; handle /front/login, /front, and authenticated redirect states as valid entrypoints
  • Harden cy.logout() — handle already-logged-out state gracefully (assert login screen if already on it)
  • Harden cy.logoutAdminInterface() — guard against missing logout button (link or button element)
  • Add enterDateInput / selectDateFromCalendar commands that navigate the MUI DatePicker calendar popup
  • Add setFrontendModuleConfig command for frontend-layer module configuration
  • Add chooseMuiAutocomplete generic helper for MUI autocomplete fields
  • Add chooseFirstMuiSelect, toggleMuiCheckbox, assertMuiInputDisabled, assertMuiSelectValue, assertMuiAutoComplete, assertMuiInputNotEmpty helpers
  • Add generic saveClick, saveAndAwaitJournal, assertSave, assertSaveDisabled, assertSaveEnabled, waitForJournalProgress, assertJournalFirstEntryContains, assertJournalNoFail, createClick form helpers
  • Add searcher helpers: aliasGraphqlQuery + awaitSearcherRefresh (GraphQL-intercept aliasing replaces stale "N X Found" post-search text waits), resetSearcherFilters, assertTableRowVisible, assertTableRowNotVisible, openRowAction, openRowActionIfPresent
  • Add chooseLocation + chooseLocationLevel location-cascade helpers

Program / Project Enhancements

  • createProgram accepts an optional 5th schema parameter to set the beneficiary JSON schema during program creation
  • Schema validation waits for backend async validation (SVG icon + adornment class check) before saving
  • Beneficiary schema (educated_level, able_bodied, number_of_children) passed to individual programs, enabling advanced criteria in payment plan and payroll forms
  • New enterProjectTimeEntriesPerBeneficiary(projectPath, daysByText) — sets per-beneficiary, per-day work-percent values against the timesheet project grid (token-based row matching tolerates first/last name in separate <td> cells; re-queries DOM on every cell to avoid stale-handle flakes from MUI table re-renders)

Payment Plan — payment-plan.cy.js

Test Cases (15 tests)

  • Validates required fields are enforced before allowing creation (save button disabled)
  • Creates a benefit-plan payment plan successfully and verifies it in the list and detail form
  • Blocks save when the code is changed to a duplicate value
  • Applies advanced criteria from the program JSON schema (field, filter, value, amount)
  • Searches payment plans by code and by name
  • Edits all editable fields on an existing payment plan and verifies updated values persist
  • Adds a new version of a payment plan
  • Deletes a payment plan and shows it only in deleted history
  • Creates a benefit-plan payment plan for a group-profile program (smoke test)
  • Filters payment plans by benefit plan / program
  • Applies multiple advanced criteria rows (Educated level + Able bodied)
  • Filters payment plans by date range (dateValidFrom / dateValidTo)
  • Resets payment plan filters and restores full list
  • Creates a payment plan with timesheet calcrule and Base Day Rate
  • Creates a timesheet payment plan without optional Base Day Rate

Behaviour change — picker now uses program code, not name

The Program autocomplete on the payment plan form was failing intermittently because long benefit-plan names get visually truncated/mangled while typing into the MUI input. The picker now searches by the unique 8-char program code, with the human-readable name kept only for display assertions. This means:

  • planData(label, benefitPlanCode, benefitPlanName) — code is now the primary key
  • fillPaymentPlanForm({ ..., benefitPlanCode, benefitPlanName })benefitPlanCode is preferred when present, falls back to benefitPlanName for legacy callers
  • assertPaymentPlanDetailFields({ ..., benefitPlanCode, benefitPlanName }) — same fallback pattern

Command Helpers

Command Purpose
cy.openCreatePaymentPlan() Navigate to payment plan list and click create
cy.fillPaymentPlanForm(...) Fill type, code, name, calculation rule, calculation params, benefit plan (by code or name), dates, advanced criteria
cy.savePaymentPlan(mutationLabel?) Click save and await async journal
cy.createPaymentPlan(...) End-to-end: open → fill → save → assert no failure journal entry
cy.filterPaymentPlans(...) Filter by code, name, dateValidFrom, dateValidTo, showDeleted, showHistory
cy.resetPaymentPlanFilters() Click Reset and wait for the searcher to refresh
cy.assertPaymentPlanDetailFields(...) Assert form values after reopening (code-or-name match)
cy.assertPaymentPlanRowVisible(...) / cy.assertPaymentPlanRowNotVisible(...) Row presence assertions
cy.openPaymentPlanForEditFromList(...) Filter → click Edit
cy.replacePaymentPlanFromList(...) Filter → click Add New Version
cy.deletePaymentPlan(...) Filter → click Delete → confirm dialog → verify journal

Payment Cycle — payment-cycle.cy.js

Test Cases (13 tests)

  • Validates required fields are enforced before allowing creation
  • Creates a PENDING payment cycle successfully
  • Searches payment cycles by code
  • Views payment cycle details from the list (eye icon)
  • Creates an ACTIVE payment cycle via task approval and verifies all fields
  • Creates a SUSPENDED payment cycle
  • Blocks save when the code is changed to a duplicate value
  • Filters payment cycles by status
  • Verifies read-only / detail-page behavior
  • Creates a payment cycle and immediately searches for it (list refresh)
  • Resets payment cycle filters and restores full list
  • Filters payment cycles by date range (Date From / Date To)
  • Payroll-form PaymentCyclePicker excludes non-ACTIVE cycles (asserts a PENDING cycle never appears in the autocomplete options on the payroll create form, since the picker queries paymentCycle(status: ACTIVE))

Command Helpers

Command Purpose
cy.openCreatePaymentCycle() Navigate to payment cycle list and click create
cy.fillPaymentCycleForm(...) Fill code, start date, end date, status
cy.savePaymentCycle() PENDING/SUSPENDED redirects to detail URL; ACTIVE dismisses the coreAlert dialog and returns to list
cy.createPaymentCycle(...) End-to-end: open → fill → save
cy.filterPaymentCycles({ code, status, dateFrom, dateTo }) Filter by code, status, and date range (date params added in this PR)
cy.resetPaymentCycleFilters() Click Reset and wait for the searcher to refresh
cy.assertPaymentCycleDetailFields(...) Assert form values on the detail page
cy.assertPaymentCycleRowVisible(...) / cy.assertPaymentCycleRowNotVisible(...) Row presence assertions
cy.openPaymentCycleForViewFromList(...) Filter → click View (eye icon)

Payment Point — payment-point.cy.js

Test Cases (16 tests, all passing)

Validates required fields, creates with full location hierarchy, verifies detail page, filters by name / PPM / Region / Region+District / Region+District+Municipality / full hierarchy, wrong-Region-no-match, cascading Region→District options, reset filters, view via eye icon, edits name, deletes from list, deletes from detail page.

Command Helpers

Command Purpose
cy.openCreatePaymentPoint(), cy.fillPaymentPointForm(...), cy.savePaymentPoint(), cy.createPaymentPoint(...) Create flow
cy.filterPaymentPoints(...), cy.resetPaymentPointFilters() List filter / reset
cy.assertPaymentPointDetailFields(...), cy.assertPaymentPointRowVisible(...), cy.assertPaymentPointRowNotVisible(...) Assertions
cy.openPaymentPointForViewFromList(...), cy.deletePaymentPointFromList(...) Row actions

Payroll — payroll.cy.js

Test Cases (12 tests)

Required-field validation, create + assert, search, view, delete (with payroll_delete task approval), pending list visibility, PENDING APPROVAL status assertion, summary dialog open/close, payment plan → cycle → payroll integration smoke, status filter, reset filters, timesheet-calcrule end-to-end.

Command Helpers (existing)

Command Purpose
cy.openCreatePayroll(), cy.fillPayrollForm(...), cy.savePayroll(), cy.createPayroll(...) Create flow
cy.filterPayrolls(...), cy.resetPayrollFilters() List / pending list filter
cy.assertPayrollDetailFields(...), cy.assertPayrollRowVisible(...), cy.assertPayrollRowNotVisible(...) Assertions
cy.openPayrollForViewFromList(...), cy.deletePayrollFromList(...) Row actions
cy.openPayrollPendingSummary(...) Open reconciliation summary dialog from /front/payrollsPending
cy.approveTaskFromList(...), cy.approveLatestPaymentCycleTask(), cy.ensurePermissiveTaskGroup(), cy.ensurePaymentCycleTaskGroup(...) Maker-checker support

Payroll Reconciliation — payroll-reconciliation.cy.js

End-to-end coverage of the reconciliation state machine for both calc-rule families. Each test takes a payroll from PENDING_APPROVAL through APPROVE_FOR_PAYMENT to RECONCILED, including UI-driven CSV download, edit, and re-upload, plus the Approve and Close dialog action that creates the payroll_reconciliation task whose approval gates the final RECONCILED transition.

Test Cases (4 implemented)

Cash transfer / social-protection calcrule:

  • Full reconciliation — creates a benefit-plan program (Fixed amount = 250), enrolls 4 individual beneficiaries, sets up an ACTIVE payment cycle and a social_protection-calcrule payment plan with StrategyOfflinePayment, creates a payroll, approves the accept_payroll task, downloads the reconciliation CSV from the UI, marks every row Paid=Yes with a unique receipt, re-uploads through the dialog, asserts the per-beneficiary amounts on the summary dialog, clicks Approve and Close, approves the resulting payroll_reconciliation task, and asserts payroll status = RECONCILED.

Timesheet / base-day-rate calcrule:

  • Per-beneficiary day patterns drive amount calculation — creates a timesheet-calcrule program (Base Day Rate = 100) with 4 beneficiaries assigned to a project; uses enterProjectTimeEntriesPerBeneficiary to seed different day patterns per individual: full days (10), partial days (4 + half-days), zero days, mixed half-days. Verifies each beneficiary's Amount = effective_days × BDR on the summary dialog (e.g., 5 days = 500, 10 days = 1000, mixed half-days = 400, etc.).
  • Stage-1 partial reconciliation — uploads a CSV marking only some rows Paid=Yes, asserts the per-row BenefitConsumption status changes are reflected on re-download.
  • Stage-2 full reconciliation + close — re-downloads, marks all remaining rows Paid=Yes, re-uploads, then runs the Approve and Close + payroll_reconciliation task approval flow, and asserts payroll status = RECONCILED. (This stage previously appeared to be "missing" because the close+approve sequence was buried in nested .then blocks; it is now lifted to outer scope so the flow mirrors the cash-transfer test.)

Command Helpers

Command Purpose
cy.parseReconciliationCsv(text) Pure parser: returns { headers, rows } from a reconciliation CSV string (handles the BE's 11-column layout)
cy.buildReconciliationCsv(rows, headers?) Pure builder: serialises { ... } rows back into CSV text using RECONCILIATION_CSV_HEADERS order
cy.downloadReconciliationFromUI() Clicks the Download button on the payroll detail page, intercepts GET /api/payroll/csv_reconciliation/, returns { headers, rows, csvText }
cy.uploadReconciliationFromUI(payrollName, csvText) Writes the CSV to cypress/fixtures/_generated/recon_<safe>_<timestamp>.csv, opens the Upload Payment Data dialog, attaches the file, intercepts POST /api/payroll/import_payroll_reconciliation/, surfaces backend error bodies on non-2xx responses. The timestamp suffix avoids the BE's "File already exists at the specified path" rejection on re-upload
cy.approveAcceptPayrollTask(payrollName) Approves the accept_payroll task that transitions PENDING_APPROVAL → APPROVE_FOR_PAYMENT
cy.approveAndClosePayrollFromSummary(payrollName) From /front/payrollsApproved, opens the row's summary dialog and clicks Approve and Close (this is the action that creates the payroll_reconciliation task — the bit the original test design missed)
cy.approvePayrollReconciliationTask(payrollName) Approves the resulting payroll_reconciliation task that finally transitions APPROVE_FOR_PAYMENT → RECONCILED
cy.assertReconciliationSummary(payrollName, { selected, total, totalAmount, totalDelivered }) Scopes inside [role="dialog"] and asserts the four summary metrics (uses .should('exist') not be.visible because the dialog cards exist in DOM but aren't reported as visible by headless Electron)

Reconciliation flow notes (for future contributors)

  • CSV upload alone only flips per-row BenefitConsumption.status — it does not transition the payroll itself. The payroll → RECONCILED transition is gated on a user clicking Approve and Close on the summary dialog, which creates the payroll_reconciliation task. Approving that task is what flips the payroll's status.
  • RELAY_CONNECTION_MAX_LIMIT=100 — beneficiary GraphQL queries must use first: 100.
  • The CSV "Payroll Status" column carries the raw enum (APPROVE_FOR_PAYMENT, with underscores), not the UI label (APPROVE FOR PAYMENT). Compare against the literal enum.

Demo

To be added after test runs are recorded.

Checklist

  • New Cypress commands follow the domain-module pattern (commands/<domain>.commands.js)
  • Tests clean up created data in after() hooks (payment plans, programs, payment points, payrolls where applicable)
  • Login/logout commands handle edge cases (already logged in/out)
  • Program creation supports beneficiary schema for advanced criteria
  • Payroll spec and command helpers added
  • Payment point spec and command helpers added
  • Payment plan fully green in targeted Cypress run
  • Payment cycle fully green in targeted Cypress run
  • Payment point fully green in targeted Cypress run (16/16)
  • Payroll fully green in targeted Cypress run
  • Payroll reconciliation fully green in targeted Cypress run (4/4)
  • Per-folder command reference docs (COMMANDS.md) added under cypress/support/commands/ and cypress/support/commands/payments/ so future spec authors can pick existing helpers instead of re-implementing UI flows
  • Cypress recordings/screenshots attached

Make login and logout resilient to already-authenticated state by
checking the DOM before acting.  Add enterDateInput command for MUI
DatePicker fields and setFrontendModuleConfig for frontend-layer
module configuration.
Introduce Cypress specs and command helpers for payment plan and
payment cycle workflows.  Payment plan coverage includes create, edit,
search, delete, versioning, duplicate-code validation, advanced
criteria, and group-profile smoke.  Payment cycle coverage includes
create, search, view-details, and required-field validation.
Pass beneficiary JSON schema during program creation so that
advanced criteria fields (educated_level, able_bodied, etc.) are
available in payment plan and payroll forms.  Harden login command
with cookie clearing and increased timeout.  Add initial payroll
spec and command helpers.
Payment plan: filter by benefit plan/program, multiple advanced
criteria rows, calculation rule persistence.
Payment cycle: ACTIVE/SUSPENDED creation, duplicate code block,
status filter, read-only detail page, immediate search after create.
Payroll: pending-approval status check, cross-domain integration
smoke test.
Add a dedicated payment-point spec (16 tests) covering CRUD, the full
location-level filter cascade (region, district, municipality, village),
detail view, and filter reset.  Add the matching command module
(payment-point.commands.js) plus a payment-cycle config fixture used by
the new suites.

Expand payroll.cy.js with the timesheet calcrule integration flow:
enroll individuals directly as Active, create a project with locations
and the new "Allow beneficiaries to enroll in multiple projects" flag,
assign beneficiaries, enter time entries, complete the project, wire a
timesheet payment plan + ACTIVE payment cycle, and create the payroll.

Fix cypress.config.js updateCSV task to preserve rows with an empty
group_code so standalone individuals stay eligible for individual
program enrollment.  Update individuals.csv with 20 standalone
individuals (HEAD role, R1 location codes) to support those flows.

Strengthen shared support commands: assertion helpers for detail
fields, autocomplete partial-match assertion, safer login/logout on
stale sessions, better task-group and project helpers
(assignBeneficiariesToProject, enterProjectTimeEntries,
updateProjectStatus, approveLatestPaymentCycleTask), and a
calculationParams-aware payment plan form filler.
Extract form, searcher, location, and constants into dedicated support modules, then move every payment domain (cycle, plan, point, payroll) plus tasks/programs/registry/UI commands onto them. Replace the stale "N X Found" post-search text waits with GraphQL-intercept aliasing (aliasGraphqlQuery + awaitSearcherRefresh) to eliminate filter/row-assert races, scope the payroll delete confirmation click to [role="dialog"] so the delete mutation fires reliably, move filterPayrolls' visitPending into its options object, and drop an unused payment-cycle fixture.
Adds the payroll-reconciliation Cypress spec covering both calc
rule families (social-protection cash transfer and timesheet base-day-rate)
end-to-end through the full PENDING_APPROVAL -> APPROVE_FOR_PAYMENT
-> RECONCILED state machine, including UI-driven CSV download/edit/upload
and the "Approve and Close" + payroll_reconciliation task approval that
gates the terminal RECONCILED transition.

Also fixes a payment-plan picker regression where long benefit-plan
names were mangled during entry: the picker now searches by the unique
8-char program code (planData/fillPaymentPlanForm/assertPaymentPlanDetailFields
all gain a benefitPlanCode parameter, preferred over name when present).

New helpers:
- payroll: parseReconciliationCsv, buildReconciliationCsv,
  downloadReconciliationFromUI, uploadReconciliationFromUI,
  approveAndClosePayrollFromSummary, approvePayrollReconciliationTask,
  approveAcceptPayrollTask, assertReconciliationSummary
- programs: enterProjectTimeEntriesPerBeneficiary (per-beneficiary
  per-day work-percent entry against the timesheet project grid)

Payment-cycle spec gains two tests: date-range filter coverage and an
assertion that the payroll form's PaymentCyclePicker excludes
non-ACTIVE cycles.

.gitignore: ignore generated reconciliation CSV scratch directory and
local dev artifacts.
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
20 Security Hotspots
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@Shahzaibahmad97 Shahzaibahmad97 requested a review from weilu May 1, 2026 14:02
@Shahzaibahmad97 Shahzaibahmad97 self-assigned this May 1, 2026
@Shahzaibahmad97 Shahzaibahmad97 marked this pull request as ready for review May 1, 2026 14:02
@Shahzaibahmad97 Shahzaibahmad97 requested a review from anthbel May 1, 2026 14:16
@weilu weilu requested a review from Copilot May 1, 2026 14:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Payments-domain Cypress E2E suite and refactors Cypress support code into domain-scoped command modules to improve reuse and reduce test flakiness across openIMIS Social Protection workflows.

Changes:

  • Introduces Payments E2E specs covering payment plans, payment cycles, payment points, payrolls, and payroll reconciliation flows.
  • Replaces the monolithic cypress/support/commands.js with domain-scoped cypress/support/commands/* modules plus shared helpers/constants.
  • Hardens/shared-izes common UI interactions (MUI date picker navigation, searcher refresh via GraphQL intercepts, journal-based save/wait helpers, task-approval helpers).

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
cypress/support/helpers/date.js Adds shared date formatting helper used by program assertions.
cypress/support/e2e.js Loads the new commands barrel from cypress/support/commands.
cypress/support/constants.js Centralizes shared constants (timeouts, statuses, calc-rule labels).
cypress/support/commands/ui.commands.js Adds reusable MUI UI helpers (inputs/selects/autocomplete/date-picker navigation).
cypress/support/commands/tasks.commands.js Adds task-group setup + generic maker-checker task approval helpers.
cypress/support/commands/searcher.commands.js Adds GraphQL-alias-based searcher refresh + row-action helpers to reduce flakiness.
cypress/support/commands/registry.commands.js Adds/updates helpers for seeding individuals/households and counting standalone individuals.
cypress/support/commands/programs.commands.js Extends program flows (schema support, project timesheet grid helpers).
cypress/support/commands/payments/payroll.commands.js Adds payroll + reconciliation CSV download/upload + reconciliation summary helpers.
cypress/support/commands/payments/payment-point.commands.js Adds payment point CRUD + filtering helpers.
cypress/support/commands/payments/payment-plan.commands.js Adds payment plan CRUD, filtering, advanced criteria helpers.
cypress/support/commands/payments/payment-cycle.commands.js Adds payment cycle CRUD/filter helpers including ACTIVE via task workflow.
cypress/support/commands/payments/index.js Registers all payments-domain commands.
cypress/support/commands/location.commands.js Adds unified location selection helper across mixed MUI widgets.
cypress/support/commands/index.js Barrel that registers all command modules.
cypress/support/commands/grievance.commands.js Moves grievance-related commands into a dedicated module.
cypress/support/commands/form.commands.js Adds shared save/journal helpers (save click, await journal, assertions).
cypress/support/commands/auth.commands.js Hardens login/logout + admin-interface login/logout.
cypress/support/commands/admin.commands.js Adds admin UI helpers including frontend module config creation.
cypress/support/commands.js Removes the prior monolithic Cypress commands file.
cypress/fixtures/individuals.csv Adds standalone individuals rows needed for individual-program enrollment tests.
cypress/e2e/payroll.cy.js Adds payroll workflow E2E coverage including timesheet payroll integration.
cypress/e2e/payroll-reconciliation.cy.js Adds reconciliation state-machine E2E coverage (cash-transfer + timesheet).
cypress/e2e/payment-point.cy.js Adds payment point E2E coverage (create/filter/edit/delete).
cypress/e2e/payment-plan.cy.js Adds payment plan E2E coverage (criteria, versions, delete/history, date filters, timesheet rule).
cypress/e2e/payment-cycle.cy.js Adds payment cycle E2E coverage including ACTIVE approval workflow and date filtering.
cypress.config.js Preserves empty group_code while randomizing CSV so standalone individuals remain available.
.gitignore Ignores Cypress videos and generated fixtures; adds common local env/editor ignores.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cypress/support/commands/tasks.commands.js Outdated
Comment thread cypress/support/commands/tasks.commands.js
Comment thread cypress/e2e/payment-plan.cy.js
Comment thread cypress/support/commands/payments/payroll.commands.js Outdated
- Use canonical /front/AllTasks URL in tasks.commands.js to match
  programs.commands.js and the URL the SPA actually serves at
  localhost:3000/front/AllTasks. Avoids relying on React Router's
  case-insensitive default.
- Complete the truncated comment block above deletePayrollFromList
  so the warning about unscoped Ok matching is a full sentence.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 4, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
20 Security Hotspots
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add e2e integration tests for Payments

2 participants