Skip to content

WEB-1037: Playwright — client action page objects, seeded factory with state overrides, and ApiSetupManager.getClientTemplate#3722

Open
devvaansh wants to merge 1 commit into
openMF:devfrom
devvaansh:WEB-1037-playwright-add-client-action-page-objects-seeded-factory-with-state-overrides-and-api-setup-manager-get-client-template
Open

WEB-1037: Playwright — client action page objects, seeded factory with state overrides, and ApiSetupManager.getClientTemplate#3722
devvaansh wants to merge 1 commit into
openMF:devfrom
devvaansh:WEB-1037-playwright-add-client-action-page-objects-seeded-factory-with-state-overrides-and-api-setup-manager-get-client-template

Conversation

@devvaansh

@devvaansh devvaansh commented Jul 15, 2026

Copy link
Copy Markdown
Member

Description

Extends the Playwright E2E infrastructure to unblock client-lifecycle specs (activate / reject / withdraw / reactivate / transfer / close) with reusable Page Objects, a seeded factory that owns state-specific setup + cleanup, and a deduplicated client-template API wrapper.

1. Layer-2 selector contracts — playwright/config/selectors.ts

Added five typed selector maps mirroring CloseClientSelectors:

  • ACTIVATE_CLIENT_SELECTORS, REJECT_CLIENT_SELECTORS, WITHDRAW_CLIENT_SELECTORS, REACTIVATE_CLIENT_SELECTORS, TRANSFER_CLIENT_SELECTORS
  • Confirm/Cancel stored as accessible-name strings → resolved via getByRole('button', { name }) (same code path for Angular Material and the React port).

2. Page Objects — playwright/pages/client-actions/

Five thin parallels of close-client.page.ts:

  • activate-client.page.tssubmitActivation({ activationDate })
  • reject-client.page.tssubmitRejection({ rejectionDate, reasonName })
  • withdraw-client.page.tssubmitWithdrawal({ withdrawalDate, reasonName })
  • reactivate-client.page.tssubmitReactivation({ reactivationDate })
  • transfer-client.page.tssubmitTransfer({ destinationOfficeName, transferDate, note? }) (URL regex tolerates both Transfer%20Client and Transfer Client)

Barrel re-exports added in playwright/pages/index.ts.

3. Factory extension — playwright/factories/client.ts

  • New ClientState union: 'pending' | 'active' | 'rejected' | 'withdrawn' | 'closed'
  • New CreateTestClientOverrides widens the existing overrides with state, actionDate, rejectionReasonName, withdrawalReasonName, closureReasonName
  • createTestClient strips seeded-factory-only fields via extractPayloadOverrides so TestClientPayload stays clean
  • New createSeededClient(fineractApi, overrides?) — single owner of "make me a client in state X with a cleanup deleter that works for state X":
state create call follow-up cleanup
pending createPendingClient hard DELETE
active createActiveClient best-effort DELETE
rejected createPendingClient ensureClientRejectionReason + rejectClient best-effort DELETE
withdrawn createPendingClient ensureClientWithdrawalReason + withdrawClient best-effort DELETE
closed createActiveClient ensureClientClosureReason + closeClient best-effort DELETE

Cleanup purges family members first (FK-safe), then deletes; non-pending deletion errors are swallowed and logged.

4. FineractApiClient extension — playwright/fixtures/fineract-api.ts

  • getClientTemplate(officeId?)
  • rejectClient(id, reasonId, date) / withdrawClient(id, reasonId, date)
  • ensureClientRejectionReason(name?) / ensureClientWithdrawalReason(name?) (backed by ClientRejectReason / ClientWithdrawReason system codes).

5. ApiSetupManager domain wrapper — playwright/utils/api-setup-manager.ts

getClientTemplate(officeId?) delegates to dedupe('clientTemplate:' + (officeId ?? 'none'), …). The 'none' sentinel keeps the no-officeId form on its own key so it never collides with clientTemplate:0.

6. Tests

  • playwright/utils/api-setup-manager.spec.ts — 5 new tests: concurrent dedup, serial cache hits, distinct keys per officeId, sentinel isolation from officeId=0, reject eviction.
  • playwright/factories/client.spec.ts — 15 new unit tests (stubbed FineractApiClient): payload synthesis, state→command mapping for all 5 states, actionDate fallback, missing resourceId error, cleanup FK-safe order + best-effort swallow, family-member fetch resilience, return-shape.
  • playwright.config.tsunit project includes factories/client.spec.ts; integration narrowed to .factory.spec.ts only.

Validation

npx playwright test --project=unit --reporter=list
95 passed (948ms)

Related issues and discussion

https://mifosforge.jira.com/browse/WEB-1037

Screenshots, if any

No TypeScript errors across touched files or downstream consumer specs.

Checklist

  • Commits squashed into one (30d56abf8)
  • Read and understood the contribution guidelines at web-app/.github/CONTRIBUTING.md

Summary by CodeRabbit

  • New Features
    • Added Playwright page objects and typed form selectors for client lifecycle actions: Activate, Reject, Withdraw, Reactivate, and Transfer.
    • Introduced enhanced client factory utilities to build deterministic client payloads, seed clients into lifecycle states, and provide safe cleanup.
    • Added client template retrieval with in-memory deduped caching for shared and office-scoped templates.
  • Tests
    • Expanded unit test coverage for client factory payload creation, state transitions, seeded cleanup semantics, and template caching behavior.
  • Chores
    • Updated Playwright test discovery so unit/integration suites target the appropriate spec naming patterns.

@devvaansh
devvaansh requested a review from a team July 15, 2026 10:53
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@devvaansh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 77852cb6-3ec6-4439-bc8d-f927b55a6de2

📥 Commits

Reviewing files that changed from the base of the PR and between 8cfdd0a and 89c3c4a.

📒 Files selected for processing (14)
  • playwright.config.ts
  • playwright/config/selectors.ts
  • playwright/factories/client.spec.ts
  • playwright/factories/client.ts
  • playwright/factories/index.ts
  • playwright/fixtures/fineract-api.ts
  • playwright/pages/client-actions/activate-client.page.ts
  • playwright/pages/client-actions/reactivate-client.page.ts
  • playwright/pages/client-actions/reject-client.page.ts
  • playwright/pages/client-actions/transfer-client.page.ts
  • playwright/pages/client-actions/withdraw-client.page.ts
  • playwright/pages/index.ts
  • playwright/utils/api-setup-manager.spec.ts
  • playwright/utils/api-setup-manager.ts

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "pre_merge_checks"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Changes

The Playwright suite adds seeded client factories, lifecycle API helpers, client-action page objects, typed selectors, client-template caching, and updated test discovery. Unit coverage validates payload generation, state transitions, cleanup behavior, and template caching.

Seeded client workflows

Layer / File(s) Summary
Client workflow contracts and API commands
playwright/factories/client.ts, playwright/fixtures/fineract-api.ts
Client states, seeded-client return types, reason helpers, and reject/withdraw commands are defined.
Seeded client orchestration
playwright/factories/client.ts, playwright/factories/index.ts
Factories build payloads, create clients, apply lifecycle transitions, expose cleanup, and re-export the new API.
Factory workflow validation
playwright/factories/client.spec.ts
Unit tests cover payload overrides, state mapping, response identifiers, cleanup ordering, failures, and returned values.

Client action page objects

Layer / File(s) Summary
Client action selector contracts
playwright/config/selectors.ts
Typed selector maps define controls for activate, reject, withdraw, reactivate, and transfer forms.
Client action page workflows
playwright/pages/client-actions/*, playwright/pages/index.ts
Page objects implement loading, form submission, option selection, cancellation navigation, and barrel exports for each action.

Playwright infrastructure

Layer / File(s) Summary
Client template caching
playwright/fixtures/fineract-api.ts, playwright/utils/api-setup-manager.ts, playwright/utils/api-setup-manager.spec.ts
Client templates support global or office-scoped retrieval, deduplication, keyed caching, and retry behavior after failures.
Test project discovery rules
playwright.config.ts
The unit project includes the client factory spec, while integration discovery targets *.factory.spec.ts files.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as Factory test
  participant Factory as createSeededClient
  participant API as FineractApiClient
  participant Cleanup as cleanup
  Test->>Factory: request client state
  Factory->>API: create client
  Factory->>API: apply lifecycle command
  Factory-->>Test: return SeededTestClient
  Test->>Cleanup: invoke cleanup
  Cleanup->>API: delete family members
  Cleanup->>API: delete client
Loading

Possibly related PRs

Suggested reviewers: alberto-art3ch

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: new client action page objects, seeded client factory state overrides, and the new ApiSetupManager client template wrapper.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devvaansh
devvaansh force-pushed the WEB-1037-playwright-add-client-action-page-objects-seeded-factory-with-state-overrides-and-api-setup-manager-get-client-template branch 2 times, most recently from b920077 to eec1702 Compare July 15, 2026 11:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
playwright/factories/client.spec.ts (2)

92-190: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use satisfies to validate the stub before casting.

as unknown as FineractApiClient bypasses the compatibility checking claimed by the comment, allowing API signature drift to compile unnoticed. Validate the object against a Pick<FineractApiClient, ...> first, retaining the cast only at the final handoff.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playwright/factories/client.spec.ts` around lines 92 - 190, Update buildStub
so the stub object is first validated with satisfies against a
Pick<FineractApiClient, ...> containing the implemented methods, ensuring
signature drift is caught; retain the final as unknown as FineractApiClient cast
only when assigning the validated stub to the returned api field.

364-379: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that cleanup still attempts deleteClient.

This test only checks that cleanup resolves, so it also passes if cleanup stops after the family-member lookup failure. Record the deleted ID and assert that deleteClient(99) was reached.

Proposed assertion
+    let deletedClientId: number | undefined;
     const failingStub = {
       getFirstOfficeId: async (): Promise<number> => 7,
       createPendingClient: async (): Promise<{ resourceId: number }> => ({ resourceId: 99 }),
       getClientFamilyMembers: async (): Promise<never> => {
         throw new Error('boom');
       },
-      deleteClient: async (): Promise<void> => undefined
+      deleteClient: async (clientId: number): Promise<void> => {
+        deletedClientId = clientId;
+      }
     } as unknown as FineractApiClient;

     const seeded = await createSeededClient(failingStub);
     await expect(seeded.cleanup()).resolves.toBeUndefined();
+    expect(deletedClientId).toBe(99);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playwright/factories/client.spec.ts` around lines 364 - 379, Update the
cleanup rejection test around createSeededClient to track calls to the
failingStub.deleteClient method, recording the client ID received. After
awaiting seeded.cleanup(), assert that deleteClient was called with ID 99, while
retaining the existing resolution assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@playwright/factories/client.ts`:
- Around line 51-57: Update CreateTestClientOverrides and createSeededClient so
callers cannot provide GeneralStepData fields that the seeded API path ignores;
either narrow the override type to the fields actually mapped into the request
or resolve and include every supported override, including office selection and
persisted client fields. Ensure the returned payload reflects the values saved
by createSeededClient.
- Around line 137-184: Update createSeededClient around the lifecycle transition
switch and cleanup function so cleanup is registered immediately after client
creation, before reason lookups or state commands can fail, and invoke it when
any transition rejects. Ensure non-pending clients also receive state-aware or
suite-level teardown when hard deletion is unavailable, while preserving cleanup
of family members and pending clients.

In `@playwright/fixtures/fineract-api.ts`:
- Around line 410-453: Remove the duplicate declarations of
ensureClientRejectionReason and ensureClientWithdrawalReason in this section,
and remove the second declarations of rejectClient and withdrawClient later in
the class. Preserve one complete implementation of each lifecycle method and
leave their behavior unchanged.

In `@playwright/utils/api-setup-manager.ts`:
- Around line 189-204: Remove the duplicated getClientTemplate method and its
associated JSDoc block, preserving the single existing definition and its
deduplication behavior.

---

Nitpick comments:
In `@playwright/factories/client.spec.ts`:
- Around line 92-190: Update buildStub so the stub object is first validated
with satisfies against a Pick<FineractApiClient, ...> containing the implemented
methods, ensuring signature drift is caught; retain the final as unknown as
FineractApiClient cast only when assigning the validated stub to the returned
api field.
- Around line 364-379: Update the cleanup rejection test around
createSeededClient to track calls to the failingStub.deleteClient method,
recording the client ID received. After awaiting seeded.cleanup(), assert that
deleteClient was called with ID 99, while retaining the existing resolution
assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 14154b4c-6c83-4335-9a92-a103cc6a415b

📥 Commits

Reviewing files that changed from the base of the PR and between 4493297 and b920077.

📒 Files selected for processing (14)
  • playwright.config.ts
  • playwright/config/selectors.ts
  • playwright/factories/client.spec.ts
  • playwright/factories/client.ts
  • playwright/factories/index.ts
  • playwright/fixtures/fineract-api.ts
  • playwright/pages/client-actions/activate-client.page.ts
  • playwright/pages/client-actions/reactivate-client.page.ts
  • playwright/pages/client-actions/reject-client.page.ts
  • playwright/pages/client-actions/transfer-client.page.ts
  • playwright/pages/client-actions/withdraw-client.page.ts
  • playwright/pages/index.ts
  • playwright/utils/api-setup-manager.spec.ts
  • playwright/utils/api-setup-manager.ts

Comment thread playwright/factories/client.ts
Comment thread playwright/factories/client.ts
Comment thread playwright/fixtures/fineract-api.ts Outdated
Comment thread playwright/utils/api-setup-manager.ts Outdated
@devvaansh
devvaansh force-pushed the WEB-1037-playwright-add-client-action-page-objects-seeded-factory-with-state-overrides-and-api-setup-manager-get-client-template branch from eec1702 to c792443 Compare July 15, 2026 11:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@playwright/fixtures/fineract-api.ts`:
- Around line 129-135: Update the officeId conditional in getClientTemplate to
check specifically for undefined, ensuring officeId=0 includes the query
parameter while omitted officeId retains the unscoped URL.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b7a8d85-3f11-43c6-941c-8a9ab1144533

📥 Commits

Reviewing files that changed from the base of the PR and between b920077 and 8cfdd0a.

📒 Files selected for processing (14)
  • playwright.config.ts
  • playwright/config/selectors.ts
  • playwright/factories/client.spec.ts
  • playwright/factories/client.ts
  • playwright/factories/index.ts
  • playwright/fixtures/fineract-api.ts
  • playwright/pages/client-actions/activate-client.page.ts
  • playwright/pages/client-actions/reactivate-client.page.ts
  • playwright/pages/client-actions/reject-client.page.ts
  • playwright/pages/client-actions/transfer-client.page.ts
  • playwright/pages/client-actions/withdraw-client.page.ts
  • playwright/pages/index.ts
  • playwright/utils/api-setup-manager.spec.ts
  • playwright/utils/api-setup-manager.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • playwright/factories/index.ts
  • playwright/utils/api-setup-manager.ts
  • playwright/pages/index.ts
  • playwright/factories/client.spec.ts
  • playwright/config/selectors.ts
  • playwright/factories/client.ts

Comment on lines +129 to +135
async getClientTemplate(officeId?: number): Promise<any> {
const url = officeId
? `/fineract-provider/api/v1/clients/template?officeId=${officeId}`
: '/fineract-provider/api/v1/clients/template';
const res = await this.ctx.get(url);
return this.validateResponse(res, 'getClientTemplate');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a strict undefined check for officeId.

A falsy check (officeId ? ... : ...) drops the query parameter if officeId is 0. While Fineract IDs are typically positive integers, using a strict !== undefined check is more robust and correctly aligns with the test suite, which explicitly expects officeId=0 to be treated as a distinct, scoped request (as seen in the sentinel isolation test in api-setup-manager.spec.ts).

🛡️ Proposed fix
   async getClientTemplate(officeId?: number): Promise<any> {
-    const url = officeId
+    const url = officeId !== undefined
       ? `/fineract-provider/api/v1/clients/template?officeId=${officeId}`
       : '/fineract-provider/api/v1/clients/template';
     const res = await this.ctx.get(url);
     return this.validateResponse(res, 'getClientTemplate');
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getClientTemplate(officeId?: number): Promise<any> {
const url = officeId
? `/fineract-provider/api/v1/clients/template?officeId=${officeId}`
: '/fineract-provider/api/v1/clients/template';
const res = await this.ctx.get(url);
return this.validateResponse(res, 'getClientTemplate');
}
async getClientTemplate(officeId?: number): Promise<any> {
const url = officeId !== undefined
? `/fineract-provider/api/v1/clients/template?officeId=${officeId}`
: '/fineract-provider/api/v1/clients/template';
const res = await this.ctx.get(url);
return this.validateResponse(res, 'getClientTemplate');
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playwright/fixtures/fineract-api.ts` around lines 129 - 135, Update the
officeId conditional in getClientTemplate to check specifically for undefined,
ensuring officeId=0 includes the query parameter while omitted officeId retains
the unscoped URL.

…verrides, and ApiSetupManager.getClientTemplate

- Add 5 Layer-2 selector maps (activate/reject/withdraw/reactivate/transfer)
- Add 5 client-action Page Objects under playwright/pages/client-actions/
- Extend client factory with ClientState union, CreateTestClientOverrides,
  and createSeededClient covering pending/active/rejected/withdrawn/closed
  with FK-safe cleanup deleters
- Extend FineractApiClient with getClientTemplate, rejectClient,
  withdrawClient, ensureClientRejectionReason, ensureClientWithdrawalReason
- Add ApiSetupManager.getClientTemplate domain wrapper with 'none' sentinel
- Add 15 factory unit tests + 5 getClientTemplate wrapper tests (95 unit
  tests total, all passing)
- Route factories/client.spec.ts through the 'unit' project;
  keep .factory.spec.ts under 'integration'
@devvaansh
devvaansh force-pushed the WEB-1037-playwright-add-client-action-page-objects-seeded-factory-with-state-overrides-and-api-setup-manager-get-client-template branch from 8cfdd0a to 89c3c4a Compare July 16, 2026 13:38
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.

1 participant