test(auth): add Playwright E2E coverage for invite request CTA #411
Conversation
…UTH-005) Implements E2E-AUTH-005 (P0): validates that a logged-out visitor can submit an invite request and receive confirmation, and that duplicate submissions are handled gracefully with clear messaging. Changes: - Add data-testid attributes to PageContent.tsx (invite-request-form, invite-email-input, invite-submit-button, invite-duplicate-message) and PersonalForm.tsx (invite-success-message) - Wrap email input and submit button in a proper <form onSubmit> (was a bare div with onClick, no semantic form element) - Add mockGraphQLOperation helper to auth.spec.ts intercepting Apollo operations by name (checkDuplicateEmail, requestUserAccess) - Add two test scenarios: success path and duplicate handling, both verified on Desktop Chrome and Mobile Chrome - Downgrade jest/jest-environment-jsdom from 30.x to 29.7.0 to fix compatibility with ts-jest@29 (upstream merged jest@30 prematurely) Playwright: 6/6 passing across Desktop Chrome and Mobile Chrome Jest: 154/155 suites (1 pre-existing SettingsContent timeout flake, unrelated to this change)
There was a problem hiding this comment.
Pull request overview
This PR adds Playwright end-to-end coverage for the invite request CTA at /auths/request-access (E2E-AUTH-005), and updates the request-access UI to be more testable and semantic. It also adjusts Jest/ts-jest-related dependencies to address a Jest major-version mismatch that was breaking unit tests.
Changes:
- Refactors the request-access CTA interaction to use a semantic
<form onSubmit>and adds stabledata-testidhooks. - Adds Playwright E2E scenarios for invite request success and duplicate handling, with GraphQL network mocking by operation name.
- Downgrades Jest to 29.7.x and updates lockfile entries to restore compatibility with ts-jest.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| quotevote-frontend/src/components/RequestAccess/PersonalForm/PersonalForm.tsx | Adds test targeting for the invite success confirmation UI. |
| quotevote-frontend/src/app/auths/request-access/PageContent.tsx | Converts CTA UI to a form-based submission flow and adds data-testid attributes. |
| quotevote-frontend/e2e/auth.spec.ts | Adds E2E-AUTH-005 coverage and introduces a GraphQL operation-mocking helper. |
| quotevote-frontend/package.json | Adjusts Jest/ts-jest versions to address major-version incompatibility. |
| quotevote-frontend/pnpm-lock.yaml | Lockfile updates reflecting Jest/ts-jest dependency changes. |
Files not reviewed (1)
- quotevote-frontend/pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)
quotevote-frontend/src/components/RequestAccess/PersonalForm/PersonalForm.tsx:77
- data-testid="invite-success-message" is currently applied to the
in both success and non-success states. That makes the selector misleading and allows tests to pass/fail incorrectly (e.g., the element remains visible even when the invite request is not successful).
<h1 data-testid="invite-success-message" className="text-center text-2xl md:text-4xl font-bold mb-4 md:mb-8">
{requestInviteSuccessful ? (
<>
Thank you for{' '}
<span className="text-[#52b274]">joining us</span>
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <button | ||
| data-testid="invite-submit-button" | ||
| onClick={onSubmit} | ||
| disabled={loading} |
| // 2. Email input accepts a registered email address | ||
| await emailInput.fill(registeredUser.email); | ||
| await emailInput.dispatchEvent("input"); | ||
|
|
| * password setup, admin invite management, email delivery. | ||
| */ | ||
|
|
||
| const GRAPHQL_URL = "http://localhost:4000/graphql"; |
| await emailInput.fill(visitorEmail); | ||
| await submitButton.click(); |
| const successMessage = page.getByTestId("invite-success-message"); | ||
| await expect(successMessage).not.toBeVisible(); |
| ts-jest: | ||
| specifier: ^29.4.5 | ||
| version: 29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.25))(typescript@5.9.3) | ||
| specifier: ^29.4.11 | ||
| version: 29.4.11(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@29.7.0(@types/node@20.19.25))(typescript@5.9.3) |
| "jest": "^29.7.0", | ||
| "jest-environment-jsdom": "^29.7.0", | ||
| "next-test-api-route-handler": "^5.0.3", | ||
| "prettier": "^3.7.1", | ||
| "tailwindcss": "^4", | ||
| "ts-jest": "^29.4.5", | ||
| "ts-jest": "^29.4.11", |
| <input | ||
| data-testid="invite-email-input" | ||
| type="email" | ||
| placeholder="Enter Email" | ||
| value={userDetails} |
motirebuma
left a comment
There was a problem hiding this comment.
Nice work @Sakshamk17. Clean and well-scoped -- the E2E spec covers both the happy path and the duplicate handling path, the mockGraphQLOperation helper is reusable, and the <form onSubmit> refactor in PageContent.tsx is a good accessibility improvement. The note about page.keyboard.type() vs fill() for react-hook-form compatibility is a helpful detail for future contributors.
Two things to fix:
-
The
<button onClick={onSubmit}>in PageContent.tsx still has the oldonClickhandler alongside the new<form onSubmit>. Since the form'sonSubmitalready callsonSubmit(), the button'sonClickis redundant and will fire the submission twice if someone clicks (once fromonClick, once from the form submit event). Remove theonClickfrom the button and just keeptype="submit". -
The frontend CI is currently failing. Please make sure
pnpm run test,pnpm run lint, andpnpm run type-checkall pass before this can be merged.
Verdict: Will be approved and merged after fixing the double-submit bug and getting CI green.
Thank you!!
|
@Sakshamk17 is attempting to deploy a commit to the Louis Girifalco's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Hi @motirebuma and @flyblackbox , I have successfully resolved all merge conflicts and synchronized the branch with the upstream main. The codebase is fully normalized and ready for your review. |
There was a problem hiding this comment.
Nice work @Sakshamk17. You addressed the previous feedback:
- Double-submit bug -- fixed. The redundant
onClick={onSubmit}is removed from the button and replaced withtype="submit", so the form'sonSubmithandles submission cleanly without firing twice.
The E2E spec covers both the happy path and the duplicate handling path, the mockGraphQLOperation helper is reusable, and the <form onSubmit> refactor is a good accessibility improvement.
CI is all green (Backend, Frontend, E2E all passing).
Verdict: approved, ready to merge.
Thank you!!!!
Summary
Fixes issue #397 .
This PR introduces Playwright end-to-end test coverage for the invite request CTA at
/auths/request-access, covering both the happy path (successful submission) and the duplicate handling path. It also resolves a blocking semantic issue inPageContent.tsxwhere the form lacked a proper<form>element, and adds thedata-testidselectors required for stable test targeting.Changes Implemented
Fixes & Enhancements
PageContent.tsxfrom an unstablediv + onClicksetup to a semantic<form onSubmit>, enabling native Enter key submission and proper form accessibilitydata-testidattributes acrossPageContent.tsxandPersonalForm.tsxper the selectors specified in the issue:invite-request-forminvite-email-inputinvite-submit-buttoninvite-duplicate-messageinvite-success-messageTest Implementation
e2e/auth.spec.tsunder theInvite Request CTA (E2E-AUTH-005)describe block:checkDuplicateEmail(empty) andrequestUserAccess(success), verifies the "Thank you for joining us" confirmation renderscheckDuplicateEmail(existing record), verifies "This email already exists" message appears and the success state does not rendermockGraphQLOperation()helper to intercept Apollo GraphQL requests by operation name, avoiding any dependency on a live backendBug Fix — Jest/ts-jest version mismatch
jest@30whilets-jestis still onv29— these are incompatible and caused Jest's globals (describe,jest,it) to stop being injected, breaking the entire unit test suitejestandjest-environment-jsdomfrom30.x→29.7.0to restore compatibility withts-jest@29.4.11Verification
Notes for Reviewers
Both GraphQL operations (
checkDuplicateEmailquery andrequestUserAccessmutation) are mocked at the network layer viapage.route()since no real backend is required for this test to be meaningful. Operation names match the camelCase definitions insrc/graphql/queries.tsandsrc/graphql/mutations.tsexactly.page.keyboard.type()is used instead of Playwright'sfill()for the email input. This is intentional —react-hook-formwithzodResolverrequires real keyboard events to trigger validation and enable the submit button.fill()bypasses React's synthetic event system and leaves the button permanently disabled.The
SettingsContenttimeout flake andProfileHeaderCoverassertion failure are both pre-existing upstream issues introduced before this branch and are not caused by these changes.