Skip to content

feat: add @ocom-verification coverage for member management (#293)#298

Open
aaron-rab wants to merge 3 commits into
mainfrom
293-add-ocom-verification-coverage-for-member-management
Open

feat: add @ocom-verification coverage for member management (#293)#298
aaron-rab wants to merge 3 commits into
mainfrom
293-add-ocom-verification-coverage-for-member-management

Conversation

@aaron-rab

@aaron-rab aaron-rab commented Jul 10, 2026

Copy link
Copy Markdown

Summary by Sourcery

Add verification coverage for community member management across API, UI and E2E flows, including member creation and profile update scenarios.

New Features:

  • Introduce GraphQL client per-request header support for member-scoped operations.
  • Add Serenity abilities and page objects for creating members and updating member profiles via API, UI, and browser flows.
  • Define Gherkin feature files and Cucumber step definitions covering member lifecycle and authorization scenarios.

Bug Fixes:

  • Ensure mock queue storage returns correctly shaped end-user update messages for tests.

Enhancements:

  • Wire event handler registration into the mock application services factory for verification tests.
  • Extend GraphQL test server context with principal hints from request headers to support member-aware services.

Build:

  • Update pnpm overrides for body-parser, protobufjs, and js-yaml to newer versions.

Tests:

  • Add acceptance and E2E tasks, questions, notes, and navigation helpers to validate member creation and profile updates.
  • Expand shared page contracts to cover member creation and profile pages for reuse across test suites.

@aaron-rab aaron-rab requested a review from a team July 10, 2026 21:09
@aaron-rab aaron-rab requested a review from a team as a code owner July 10, 2026 21:09
@aaron-rab aaron-rab linked an issue Jul 10, 2026 that may be closed by this pull request
@sourcery-ai

sourcery-ai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds end-to-end and acceptance coverage for community member creation and profile update flows across API and UI, wires GraphQL client to support per-request headers, and integrates event handlers and principal hints to drive member management scenarios.

Sequence diagram for member profile update via API using per-request GraphQL headers

sequenceDiagram
  actor ApiActor
  participant UpdateMember as UpdateMemberTask
  participant UpdateMemberProfile as UpdateMemberProfileAbility
  participant GraphQLClient
  participant ApiServer as MemberAPI

  ApiActor->>UpdateMember: performAs(details)
  UpdateMember->>ApiActor: notes<MemberNotes>().get('lastMemberId')
  UpdateMember->>ApiActor: notes<MemberNotes>().get('lastMemberCommunityId')
  UpdateMember->>ApiActor: PrincipalMemberIdForCommunity.inCommunity(communityId)
  UpdateMember->>UpdateMemberProfile: performAs(actor, { memberId, profile, communityId, principalMemberId })
  UpdateMemberProfile->>GraphQLClient: execute(MEMBER_UPDATE_PROFILE_MUTATION, variables, { headers: { 'x-community-id', 'x-member-id' } })
  GraphQLClient->>ApiServer: HTTP POST /graphql
  ApiServer-->>GraphQLClient: memberUpdateProfile response
  GraphQLClient-->>UpdateMemberProfile: { data, errors? }
  UpdateMemberProfile-->>UpdateMember: { id, profile }
  UpdateMember->>ApiActor: notes<MemberNotes>().set('lastMemberProfileEmail', profile.email)
  UpdateMember->>ApiActor: notes<MemberNotes>().set('lastMemberStatus', 'SUCCESS')
Loading

File-Level Changes

Change Details Files
Enable GraphQL client to send per-request headers for authorization and scoping.
  • Introduce GraphQLExecuteOptions with optional headers field.
  • Extend GraphQLClient.execute to accept options argument.
  • Merge per-request headers into existing Content-Type and resolved headers when issuing POST requests.
packages/cellix/serenity-framework/src/clients/graphql-client.ts
Wire acceptance API test server to register domain event handlers and pass principal hints derived from HTTP headers.
  • Import RegisterEventHandlers and track registration with eventHandlersRegistered flag.
  • Register event handlers against domainDataSource when creating mock application services factory.
  • Derive PrincipalHints (memberId, communityId) from x-member-id and x-community-id headers and pass into ApplicationServicesFactory.forRequest.
packages/ocom-verification/acceptance-api/src/mock-application-services.ts
packages/ocom-verification/acceptance-api/src/servers/api-graphql-test-server.ts
packages/ocom-verification/acceptance-api/package.json
Define shared page objects and contracts for member creation and profile editing used by acceptance and E2E tests.
  • Introduce MemberCreatePage page object with inputs, submit button, validation, and error toast locators.
  • Introduce MemberProfilePage page object with form fields, switches, and helper methods to toggle visibility settings.
  • Extend page-contract type exports to include member-related page contracts for API, UI, and E2E layers.
  • Export new member page objects from verification-shared pages index.
packages/ocom-verification/verification-shared/src/pages/member-create.page.ts
packages/ocom-verification/verification-shared/src/pages/member-profile.page.ts
packages/ocom-verification/verification-shared/src/pages/index.ts
packages/ocom-verification/acceptance-ui/src/shared/page-contracts.ts
packages/ocom-verification/e2e-tests/src/shared/page-contracts.ts
Add acceptance API abilities and GraphQL operations for member creation and profile update, including principal member resolution.
  • Create MEMBER_CREATE_MUTATION and MEMBER_UPDATE_PROFILE_MUTATION plus supporting member queries in member-operations.ts.
  • Implement createMemberAbility (CreateMember ability) that calls memberCreate mutation with x-community-id and x-member-id headers and returns created member info.
  • Implement updateMemberProfileAbility (UpdateMemberProfile ability) that calls memberUpdateProfile mutation with scoped headers and returns normalized profile data.
  • Add PrincipalMemberIdForCommunity question that polls membersForCurrentEndUser to resolve the principal member id per community.
  • Add MemberById question to read member and profile details from API for verification.
packages/ocom-verification/acceptance-api/src/shared/graphql/member-operations.ts
packages/ocom-verification/acceptance-api/src/shared/abilities/create-member.ts
packages/ocom-verification/acceptance-api/src/shared/abilities/update-member-profile.ts
packages/ocom-verification/acceptance-api/src/contexts/community/questions/principal-member-id-for-community.ts
packages/ocom-verification/acceptance-api/src/contexts/community/questions/member-by-id.ts
packages/ocom-verification/acceptance-api/src/shared/abilities/index.ts
Implement acceptance API tasks, notes, and step definitions for member creation and profile update flows.
  • Add MemberNotes and MemberProfileExpectation to capture community ids, member ids, names, profile expectations, and status.
  • Add CreateMember task that uses principal member id and CreateMember ability, updating notes on success.
  • Add UpdateMember task that uses UpdateMemberProfile ability based on member/community ids from notes, storing profile email expectations.
  • Add create-member and update-member step definitions that parse Gherkin data tables, populate notes, invoke tasks, and assert API-level outcomes and profile field equality.
  • Wire new step definition modules into community step-definitions index.
packages/ocom-verification/acceptance-api/src/contexts/community/notes/member-notes.ts
packages/ocom-verification/acceptance-api/src/contexts/community/tasks/create-member.ts
packages/ocom-verification/acceptance-api/src/contexts/community/tasks/update-member-profile.ts
packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/create-member.steps.ts
packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/update-member.steps.ts
packages/ocom-verification/acceptance-api/src/contexts/community/step-definitions/index.ts
Implement acceptance UI tasks, notes, questions, and step definitions for member creation via MembersCreate React component.
  • Add MemberUiNotes to track community ids, end user ids, last member name/community, and creation flag.
  • Add CreateMember task that drives MemberCreatePage in the DOM, filling member name and submitting, with React work flushing.
  • Add MemberCreatedFlag and MemberBelongsToCommunity questions that check notes state for creation and association.
  • Add create-member.steps.tsx that seeds notes, maps communities and end-user accounts, renders MembersCreate inside a wrapper, executes CreateMember, and asserts success and membership.
  • Wire acceptance-ui create-member steps into community step-definitions index.
packages/ocom-verification/acceptance-ui/src/contexts/community/notes/member-notes.ts
packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/create-member.ts
packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-created-flag.ts
packages/ocom-verification/acceptance-ui/src/contexts/community/questions/member-belongs-to-community.ts
packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/create-member.steps.tsx
packages/ocom-verification/acceptance-ui/src/contexts/community/step-definitions/index.ts
Implement E2E Playwright-based tasks, notes, questions, support utilities, and step definitions for UI-driven member creation and profile update flows.
  • Add MemberE2ENotes and MemberProfileExpectation for tracking community ids, end-user mappings, member ids, status, and errors.
  • Implement CreateMember task that navigates to community admin members create page, drives MemberCreatePage, captures validation errors, waits for GraphQL mutation AdminMembersCreateContainerMemberCreate, inspects payload and toast errors, asserts success, and records notes.
  • Implement UpdateMemberProfile task that navigates to community members list/profile, drives MemberProfilePage, watches SharedMemberProfileContainerMemberUpdateProfile mutation, processes payload and errors, and records success/failure in notes.
  • Implement MemberBelongsToCommunity question that uses admin navigation and table cell visibility to check membership.
  • Implement MemberCreatedFlag question that reads memberCreated from notes.
  • Add support/community-admin-navigation helpers to open community admin portals and specific member routes.
  • Add create-member and update-member step definitions that orchestrate login, community creation, seeded accounts, task invocations, and success assertions.
  • Wire new E2E step-definitions into community step-definitions index and world abilities (createMemberAbility, updateMemberProfileAbility).
packages/ocom-verification/e2e-tests/src/contexts/community/notes/member-notes.ts
packages/ocom-verification/e2e-tests/src/contexts/community/tasks/create-member.ts
packages/ocom-verification/e2e-tests/src/contexts/community/tasks/update-member-profile.ts
packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-belongs-to-community.ts
packages/ocom-verification/e2e-tests/src/contexts/community/questions/member-created-flag.ts
packages/ocom-verification/e2e-tests/src/contexts/community/support/community-admin-navigation.ts
packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/create-member.steps.ts
packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/update-member.steps.ts
packages/ocom-verification/e2e-tests/src/contexts/community/step-definitions/index.ts
packages/ocom-verification/acceptance-api/src/world.ts
Define member lifecycle and authorization feature files to describe desired behavior and mark unimplemented scenarios.
  • Add member-lifecycle.feature specifying background, happy-path member creation scenario, and commented future scenarios for profile update, association, listing, filtering, deletion, and validations.
  • Add member-authorization-and-scope.feature describing authorization boundaries and multi-community account associations with scenarios marked unimplemented.
packages/ocom-verification/verification-shared/src/scenarios/community/member/member-lifecycle.feature
packages/ocom-verification/verification-shared/src/scenarios/community/member/member-authorization-and-scope.feature
Update workspace dependency overrides for security/tooling and ensure body-parser and protobuf/js-yaml versions are pinned appropriately.
  • Add body-parser 2.3.0 override.
  • Adjust protobufjs override to 7.6.5 and remove redundant protobufjs@7.5.4 mapping.
  • Broaden js-yaml override selector and bump to 4.3.0.
  • Regenerate pnpm-lock.yaml and .snyk as needed to reflect new overrides.
pnpm-workspace.yaml
.snyk
pnpm-lock.yaml
Refine mock queue storage implementation to build EndUserUpdateQueueMessage more defensively.
  • Construct message object with id and payload first, then conditionally attach popReceipt and dequeueCount when metadata is present.
  • Return the constructed message via Promise.resolve instead of inline satisfies expression.
packages/ocom-verification/acceptance-api/src/mock-application-services.ts

Assessment against linked issues

Issue Objective Addressed Explanation
#293 Add shared Gherkin scenarios in verification-shared covering the member lifecycle (creation, updates, account association, listing/filtering, deletion, authorization, multi-community) with approximately 8–12 scenarios. The PR adds two shared feature files for member lifecycle and authorization/scope, but most scenarios are commented out and marked @unimplemented. Only the member creation scenario is currently active; the update, account association, listing/filtering, deletion, authorization, and multi-community scenarios are present only as commented templates. The total number of implemented (active) scenarios is far below the 8–12 requested and does not cover the full lifecycle.
#293 Implement acceptance-api, acceptance-ui, and e2e step definitions, abilities, and tasks to exercise member management flows (at least creation, updates, account assignment, deletion, validation, and authorization), including end-to-end scenarios that go UI → API. The PR implements substantial support for member creation and profile updates across acceptance-api, acceptance-ui, and e2e: new abilities (createMember, updateMemberProfile), GraphQL mutations/queries, step definitions, tasks, questions, and page objects, plus UI→API end-to-end verification for creation and update. However, no steps or abilities are implemented for account assignment/association, listing/filtering members, deletion, or authorization/permission checks; those flows are only outlined as @unimplemented scenarios and lack concrete step definitions or tasks. Therefore the full set of required member management flows is not covered.
#293 Ensure verification coverage aligns with existing community and iam/member domain contexts and focuses on already implemented functionality (member creation, updates, account assignment, and deletion), including handling users who belong to multiple communities. The new code aligns with existing contexts (community, members) and adds integration pieces such as event handler registration and principal member resolution, and it does exercise member creation and profile updates, including scenarios involving multiple communities ("Green Oaks" and "Blue Harbor"). However, coverage for account assignment and deletion is missing, and authorization behavior is not implemented. Multi-community handling is only partially exercised and not in the context of account associations. As a result, the verification coverage does not fully focus on all the specified already-implemented member functionality.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

await page.goto('/community/accounts', { waitUntil: 'networkidle' });
await openAdminPortalFromCommunityRow(page, communityName);

await page.waitForURL(/\/community\/[^/]+\/admin\/[^/?#]+(?:\/)?(?:\?.*)?$/, { timeout: 15_000 });

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • The global eventHandlersRegistered flag in createMockApplicationServicesFactory may cause cross-test interference or issues under parallel execution; consider scoping event handler registration per test server or using a factory-level guard instead.
  • You’re repeatedly re-declaring ExecuteWithRequestOptions and casting GraphQLClient to GraphQLClient & { execute: ExecuteWithRequestOptions }; it would be more robust to have GraphQLClient.execute formally typed to accept GraphQLExecuteOptions or expose a reusable type so these casts aren’t needed.
  • Helpers like hasGraphqlOperation, selectGraphqlPayload, and graphqlErrors are duplicated across several member tasks; consider extracting them into a shared utility to reduce repetition and keep future changes to GraphQL response handling in one place.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The global `eventHandlersRegistered` flag in `createMockApplicationServicesFactory` may cause cross-test interference or issues under parallel execution; consider scoping event handler registration per test server or using a factory-level guard instead.
- You’re repeatedly re-declaring `ExecuteWithRequestOptions` and casting `GraphQLClient` to `GraphQLClient & { execute: ExecuteWithRequestOptions }`; it would be more robust to have `GraphQLClient.execute` formally typed to accept `GraphQLExecuteOptions` or expose a reusable type so these casts aren’t needed.
- Helpers like `hasGraphqlOperation`, `selectGraphqlPayload`, and `graphqlErrors` are duplicated across several member tasks; consider extracting them into a shared utility to reduce repetition and keep future changes to GraphQL response handling in one place.

## Individual Comments

### Comment 1
<location path="packages/ocom-verification/acceptance-api/src/shared/abilities/create-member.ts" line_range="55" />
<code_context>
+			throw new Error('principalMemberId is required to create a member');
+		}
+
+		const response = await graphql.execute(
+			MEMBER_CREATE_MUTATION,
+			{
</code_context>
<issue_to_address>
**issue (bug_risk):** The optional `role` field in `CreateMemberDetails` is never sent to the GraphQL API.

`CreateMemberDetails.role` is passed through `CreateMemberTaskDetails` but never included in the mutation input, so it is effectively ignored. If `role` should affect backend behavior, add it to the GraphQL input and schema handling; if not, remove it from `CreateMemberDetails` and the task to avoid confusing API consumers.
</issue_to_address>

### Comment 2
<location path="packages/ocom-verification/acceptance-api/src/mock-application-services.ts" line_range="23" />
<code_context>
 type EndUserUpdateQueueMessage = Awaited<ReturnType<QueueStorageOperations['receiveFromEndUserUpdateQueue']>>;

 const communityCreationMessages: RecordedCommunityCreationMessage[] = [];
+let eventHandlersRegistered = false;

 function createMockTokenValidation(): TokenValidation {
</code_context>
<issue_to_address>
**issue (bug_risk):** Global `eventHandlersRegistered` flag may cause cross-test coupling and concurrency issues.

Because `eventHandlersRegistered` is module-level, only the first `createMockApplicationServicesFactory` call will register handlers; subsequent factories may skip registration even if they use different `serviceMongoose` instances or state. In parallel tests or multi-tenant environments this shared flag can cause inconsistent, hard-to-debug behavior. Consider scoping registration to the factory (e.g., per `serviceMongoose` or domainDataSource), or providing an explicit idempotent registration API on the event handler module rather than a global flag.
</issue_to_address>

### Comment 3
<location path="packages/ocom-verification/acceptance-ui/src/contexts/community/tasks/create-member.ts" line_range="8-10" />
<code_context>
+import { type Actor, Task } from '@serenity-js/core';
+import type { AcceptanceUiMemberCreatePage } from '../../../shared/page-contracts.ts';
+
+/** Let the form's async `onFinish` callback settle before assertions run. */
+async function flushPendingReactWork(): Promise<void> {
+	await new Promise<void>((resolve) => setTimeout(resolve, 0));
+	await new Promise<void>((resolve) => setTimeout(resolve, 0));
+}
</code_context>
<issue_to_address>
**suggestion (testing):** Relying on two `setTimeout(0)` calls to flush React work can be brittle.

This helper waits for `onSave` to complete using two zero-delay timers, which is a timing-based approach and can become flaky if the component does more async work or the test runner’s scheduling changes. If there’s a more explicit signal to await (e.g. `waitFor` on a specific state/DOM change or a promise returned from `onSave`), using that instead would make these acceptance tests more reliable.

Suggested implementation:

```typescript
import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom';
import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom';
import { TaskStep } from '@cellix/serenity-framework/serenity';
import { MemberCreatePage } from '@ocom-verification/verification-shared/pages';
import { type Actor, Task } from '@serenity-js/core';
import type { AcceptanceUiMemberCreatePage } from '../../../shared/page-contracts.ts';

/**
 * Wait for the member creation to complete using an explicit UI signal
 * instead of timing-based `setTimeout(0)` calls.
 */
async function waitForMemberCreationToComplete(
	page: AcceptanceUiMemberCreatePage,
	memberName: string,
): Promise<void> {
	await page.waitForMemberToBeCreated(memberName);
}

export const CreateMember = (memberName: string): Task =>

```

To fully implement this change and remove the brittle timing-based approach:

1. Replace any calls to `flushPendingReactWork()` in this file with:
   ```ts
   await waitForMemberCreationToComplete(page, memberName);
   ```
   right after `await page.clickCreateMember();` and before any assertions that depend on the member having been created.

2. In the `AcceptanceUiMemberCreatePage` contract and its concrete `MemberCreatePage` implementation, add a method such as:
   ```ts
   waitForMemberToBeCreated(memberName: string): Promise<void>;
   ```
   that explicitly waits for a reliable UI signal (e.g. new row appearing in a list, success toast, navigation completion, or a specific DOM state) indicating that `onFinish`/`onSave` has completed.

3. If the existing page objects already expose a more appropriate method (e.g. `waitUntilSaved`, `waitForCreateMemberSuccess`, etc.), adjust `waitForMemberCreationToComplete` to call that method instead of `waitForMemberToBeCreated`, and update the helper’s name/comment to reflect the actual signal being used.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

throw new Error('principalMemberId is required to create a member');
}

const response = await graphql.execute(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): The optional role field in CreateMemberDetails is never sent to the GraphQL API.

CreateMemberDetails.role is passed through CreateMemberTaskDetails but never included in the mutation input, so it is effectively ignored. If role should affect backend behavior, add it to the GraphQL input and schema handling; if not, remove it from CreateMemberDetails and the task to avoid confusing API consumers.

type EndUserUpdateQueueMessage = Awaited<ReturnType<QueueStorageOperations['receiveFromEndUserUpdateQueue']>>;

const communityCreationMessages: RecordedCommunityCreationMessage[] = [];
let eventHandlersRegistered = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Global eventHandlersRegistered flag may cause cross-test coupling and concurrency issues.

Because eventHandlersRegistered is module-level, only the first createMockApplicationServicesFactory call will register handlers; subsequent factories may skip registration even if they use different serviceMongoose instances or state. In parallel tests or multi-tenant environments this shared flag can cause inconsistent, hard-to-debug behavior. Consider scoping registration to the factory (e.g., per serviceMongoose or domainDataSource), or providing an explicit idempotent registration API on the event handler module rather than a global flag.

Comment on lines +8 to +10
/** Let the form's async `onFinish` callback settle before assertions run. */
async function flushPendingReactWork(): Promise<void> {
await new Promise<void>((resolve) => setTimeout(resolve, 0));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Relying on two setTimeout(0) calls to flush React work can be brittle.

This helper waits for onSave to complete using two zero-delay timers, which is a timing-based approach and can become flaky if the component does more async work or the test runner’s scheduling changes. If there’s a more explicit signal to await (e.g. waitFor on a specific state/DOM change or a promise returned from onSave), using that instead would make these acceptance tests more reliable.

Suggested implementation:

import { RenderInDom } from '@cellix/serenity-framework/dom/render-in-dom';
import { DomPageAdapter } from '@cellix/serenity-framework/pages/dom';
import { TaskStep } from '@cellix/serenity-framework/serenity';
import { MemberCreatePage } from '@ocom-verification/verification-shared/pages';
import { type Actor, Task } from '@serenity-js/core';
import type { AcceptanceUiMemberCreatePage } from '../../../shared/page-contracts.ts';

/**
 * Wait for the member creation to complete using an explicit UI signal
 * instead of timing-based `setTimeout(0)` calls.
 */
async function waitForMemberCreationToComplete(
	page: AcceptanceUiMemberCreatePage,
	memberName: string,
): Promise<void> {
	await page.waitForMemberToBeCreated(memberName);
}

export const CreateMember = (memberName: string): Task =>

To fully implement this change and remove the brittle timing-based approach:

  1. Replace any calls to flushPendingReactWork() in this file with:

    await waitForMemberCreationToComplete(page, memberName);

    right after await page.clickCreateMember(); and before any assertions that depend on the member having been created.

  2. In the AcceptanceUiMemberCreatePage contract and its concrete MemberCreatePage implementation, add a method such as:

    waitForMemberToBeCreated(memberName: string): Promise<void>;

    that explicitly waits for a reliable UI signal (e.g. new row appearing in a list, success toast, navigation completion, or a specific DOM state) indicating that onFinish/onSave has completed.

  3. If the existing page objects already expose a more appropriate method (e.g. waitUntilSaved, waitForCreateMemberSuccess, etc.), adjust waitForMemberCreationToComplete to call that method instead of waitForMemberToBeCreated, and update the helper’s name/comment to reflect the actual signal being used.

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 @ocom-verification coverage for Member Management

2 participants