Skip to content

WEB-1065: [Playwright] Active-client factory + sequential cleanup#3755

Open
devvaansh wants to merge 1 commit into
openMF:devfrom
devvaansh:WEB-1065-playwright-active-client-factory-sequential-cleanup
Open

WEB-1065: [Playwright] Active-client factory + sequential cleanup#3755
devvaansh wants to merge 1 commit into
openMF:devfrom
devvaansh:WEB-1065-playwright-active-client-factory-sequential-cleanup

Conversation

@devvaansh

@devvaansh devvaansh commented Jul 25, 2026

Copy link
Copy Markdown
Member

Description

Two related fixes to the Playwright test-data foundation, needed before the client account/charge specs can be written.

1. CleanupGuard.flush() did not actually enforce cleanup order.

The guard's contract is that a test creating a client and then a loan on that client must delete the loan first, or Fineract rejects the cascade with a 403. flush() popped the stack in LIFO order — but then handed every deleter to Promise.allSettled in the same tick. The ordering was only apparent: a slow child DELETE could still land after its parent's, which is the exact failure the guard exists to prevent.

flush() now awaits each deleter before starting the next. A rejecting deleter is still caught and recorded, and the drain continues, so one dead resource cannot leak its siblings. Added a staggered-delay regression test that fails against the old implementation.

2. Added createActiveTestClient().

createTestClient() deliberately creates a pending client, because pending is the only state Fineract will hard-delete. That is right for the lifecycle specs, but every upcoming flow — loan accounts, savings accounts, client charges — requires an active client, and each carries a date-ordering constraint relative to the activation date. Getting it wrong produces a Fineract validation error that names neither field.

The new factory encodes the chain once (submittedactivated → account opening) and pre-flight checks it locally, so a mistake fails with a message that actually says which two dates are inverted. Without this, roughly twenty upcoming specs would each re-derive it by hand.

Cleanup caveat, documented in the factory: Fineract will not delete an active client, so the registered deleter is expected to fail and the guard records it without throwing. E2E databases are ephemeral and the E2E_ name prefix keeps orphans greppable.

3. Fixed drift in the factories barrel.

factories/client.ts and factories/client.factory.ts both exported a function named createTestClient with incompatible signatures — one is a pure payload builder, the other seeds via the API and registers cleanup. Only the pure builder was reachable through the barrel, so import { createTestClient } from '../../factories' and from '../../factories/client.factory' silently resolved to different functions. The pure builder is now exported as buildTestClientPayload, and the barrel re-exports both flavours with a note on when to use which.

Related issues and discussion

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

Screenshots, if any

N/A — test infrastructure only, no UI changes.

Testing

  • npx playwright test --project=unit — 96 passed
  • New coverage: sequential-drain regression test, createActiveTestClient integration specs, date-guard negative cases, and a constant-chain invariant test

Note: tsc --noEmit reports a pre-existing duplicate deleteClient() declaration in fixtures/fineract-api.ts on dev. It is untouched here and fixed in the follow-up savings-API PR.

Checklist

  • If you have multiple commits please combine them into one commit by squashing them.
  • Read and understood the contribution guidelines at web-app/.github/CONTRIBUTING.md.

Summary by CodeRabbit

  • New Features
    • Added a new active-client creation option that validates submitted/activation dates in Fineract’s format and enforces active-client invariants.
    • Added exported default date constants to support consistent test setups.
    • Clarified factory exports by separating API-backed client creation from payload building.
  • Bug Fixes
    • Cleanup now executes deleters sequentially (LIFO), and keeps going after individual failures.
  • Tests
    • Added live E2E coverage for active client creation and stricter date rejection, plus cleanup ordering regression tests.

@devvaansh
devvaansh requested a review from a team July 25, 2026 11:18
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 36c815fa-0a5e-434c-9f1d-fbb030b945b9

📥 Commits

Reviewing files that changed from the base of the PR and between 3f7e0a0 and cc0810f.

📒 Files selected for processing (6)
  • playwright/factories/client.factory.spec.ts
  • playwright/factories/client.factory.ts
  • playwright/factories/index.ts
  • playwright/tests/clients/create-client.spec.ts
  • playwright/utils/cleanup-guard.spec.ts
  • playwright/utils/cleanup-guard.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • playwright/factories/client.factory.spec.ts
  • playwright/utils/cleanup-guard.spec.ts
  • playwright/utils/cleanup-guard.ts
  • playwright/tests/clients/create-client.spec.ts
  • playwright/factories/index.ts

Walkthrough

Adds an active Fineract client factory with strict date validation, separates API factories from payload builders, updates related exports and tests, and changes CleanupGuard.flush() to sequential LIFO execution with failure isolation.

Changes

Active client factory and exports

Layer / File(s) Summary
Active client creation and validation
playwright/factories/client.factory.ts, playwright/factories/client.factory.spec.ts
Adds createActiveTestClient, strict Fineract date parsing and ordering validation, default date constants, live active-client coverage, and invalid-input rejection tests.
Factory export separation
playwright/factories/index.ts, playwright/tests/clients/create-client.spec.ts
Renames the payload builder to buildTestClientPayload, exposes API factory symbols and shared resolvers, and updates client tests accordingly.

Sequential cleanup flushing

Layer / File(s) Summary
Sequential LIFO cleanup
playwright/utils/cleanup-guard.ts, playwright/utils/cleanup-guard.spec.ts
Changes cleanup draining to await each reverse-insertion deleter before starting the next, while preserving failure recording and continuation behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 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 and concisely summarizes the two main changes: the active-client factory and sequential cleanup behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 changed the title WEB-1065: [Playwright] Active-client factory + sequential LIFO cleanup WEB-1065: [Playwright] Active-client factory + sequential cleanup Jul 25, 2026

@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

🧹 Nitpick comments (2)
playwright/utils/cleanup-guard.ts (1)

166-177: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the stale Promise.allSettled reference from FlushOutcome documentation.

The implementation now invokes deleters sequentially, but the adjacent FlushOutcome docs still describe the result as coming from Promise.allSettled. Update that description to refer to the underlying deleter invocation.

🤖 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/utils/cleanup-guard.ts` around lines 166 - 177, Update the
FlushOutcome documentation near the sequential drain logic to remove the stale
Promise.allSettled reference and describe the result as originating from the
underlying deleter invocation. Leave the sequential LIFO behavior and
error-recording semantics unchanged.
playwright/utils/cleanup-guard.spec.ts (1)

76-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a deterministic gate instead of fixed timer delays.

The Arrange-Act-Assert structure is clear, but setTimeout(1)/setTimeout(25) introduces unnecessary timing sensitivity. Gate the child deleter with a promise, assert that the parent has not started, then release the child.

Suggested test structure
-    const slowDeleter = (label: string, delayMs: number) => async () => {
-      events.push(`start:${label}`);
-      await new Promise((resolve) => setTimeout(resolve, delayMs));
-      events.push(`end:${label}`);
-    };
+    let releaseChild = () => {};
+    const childGate = new Promise<void>((resolve) => {
+      releaseChild = resolve;
+    });
+    let markChildStarted = () => {};
+    const childStarted = new Promise<void>((resolve) => {
+      markChildStarted = resolve;
+    });

-    guard.register('parent', slowDeleter('parent', 1));
-    guard.register('child', slowDeleter('child', 25));
+    guard.register('parent', async () => {
+      events.push('start:parent');
+      events.push('end:parent');
+    });
+    guard.register('child', async () => {
+      events.push('start:child');
+      markChildStarted();
+      await childGate;
+      events.push('end:child');
+    });

-    await guard.flush();
+    const flushPromise = guard.flush();
+    await childStarted;
+    expect(events).toEqual(['start:child']);
+    releaseChild();
+    await flushPromise;

As per path instructions, keep this test in clear Arrange-Act-Assert form and minimize brittle timing dependencies.

🤖 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/utils/cleanup-guard.spec.ts` around lines 76 - 110, Update the
“awaits each deleter before starting the next” test to replace fixed setTimeout
delays with a deterministic child-completion promise gate. Start flush, assert
the child has started while the parent has not, resolve the gate, await flush,
and retain the expected child-before-parent event ordering in clear
Arrange-Act-Assert form.

Source: Path instructions

🤖 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.factory.ts`:
- Around line 221-225: Update the extra construction in createTestClient so
overrides.extra is merged before the active-client invariants, then explicitly
set active, activationDate, and submittedOnDate from the validated values.
Ensure caller-provided extra fields cannot replace any of these three fields or
bypass date-order validation.

---

Nitpick comments:
In `@playwright/utils/cleanup-guard.spec.ts`:
- Around line 76-110: Update the “awaits each deleter before starting the next”
test to replace fixed setTimeout delays with a deterministic child-completion
promise gate. Start flush, assert the child has started while the parent has
not, resolve the gate, await flush, and retain the expected child-before-parent
event ordering in clear Arrange-Act-Assert form.

In `@playwright/utils/cleanup-guard.ts`:
- Around line 166-177: Update the FlushOutcome documentation near the sequential
drain logic to remove the stale Promise.allSettled reference and describe the
result as originating from the underlying deleter invocation. Leave the
sequential LIFO behavior and error-recording semantics unchanged.
🪄 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 Plus

Run ID: ebf018e1-f2d9-498a-b50d-e9c59474cf5c

📥 Commits

Reviewing files that changed from the base of the PR and between 1f3e6d2 and c142d53.

📒 Files selected for processing (6)
  • playwright/factories/client.factory.spec.ts
  • playwright/factories/client.factory.ts
  • playwright/factories/index.ts
  • playwright/tests/clients/create-client.spec.ts
  • playwright/utils/cleanup-guard.spec.ts
  • playwright/utils/cleanup-guard.ts

Comment thread playwright/factories/client.factory.ts
@devvaansh
devvaansh force-pushed the WEB-1065-playwright-active-client-factory-sequential-cleanup branch from c142d53 to 3f7e0a0 Compare July 25, 2026 11:24
CleanupGuard.flush() now awaits each deleter in turn instead of
dispatching all of them concurrently via Promise.allSettled. LIFO
ordering was previously only apparent: a child resource's DELETE could
still reach Fineract after its parent's, producing an FK violation.

Adds createActiveTestClient() with a monotonic date chain
(submitted -> activated -> account opening) and a local pre-flight guard,
so an inverted date fails with a message naming both fields rather than
an opaque Fineract validation error.

Fixes the factories barrel: client.ts and client.factory.ts both exported
createTestClient with incompatible signatures and only the pure builder
was reachable through the barrel. It is now buildTestClientPayload.
@devvaansh
devvaansh force-pushed the WEB-1065-playwright-active-client-factory-sequential-cleanup branch from 3f7e0a0 to cc0810f Compare July 25, 2026 14:18
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