Skip to content

fix(payment): fix GooglePay strategy spec crashing under Jest 29 / Node 22#3299

Merged
PavlenkoM merged 1 commit into
bigcommerce:masterfrom
PavlenkoM:PI-0000-fix-google-pay-test
Jun 25, 2026
Merged

fix(payment): fix GooglePay strategy spec crashing under Jest 29 / Node 22#3299
PavlenkoM merged 1 commit into
bigcommerce:masterfrom
PavlenkoM:PI-0000-fix-google-pay-test

Conversation

@PavlenkoM

@PavlenkoM PavlenkoM commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

What/Why?

The google-pay-integration test suite was failing on master with Jest worker encountered N child process exceptions, exceeding retry limit — unrelated to any feature work.

Root cause: the CHECKOUT-10061 toolchain upgrade (TypeScript 4.7→5.8, Jest 29 + Node 22, #3273) made the worker crash on unhandled promise rejections; Jest 26 previously tolerated them. google-pay-payment-strategy.spec.ts had two distinct problems, the first masking the second:

  1. Leaked unhandled rejections from fire-and-forget click handlers. Several tests trigger an async click handler via button.click() and never await it. When the handler reports an error via onError and re-throws, the rejection is never handled → it crashes the worker. This was amplified by the button being created once in beforeAll and shared across all tests with no deinitialize in between, so click listeners accumulated and a later button.click() fired an earlier test's throwing handler. (The newer container-mode tests added in feat(payment): PI-5215 [FE][Google Pay] Implement container mode in GooglePayPaymentStrategy #3247 already avoid this by capturing and awaiting the handler.)
  2. A pre-existing assertion failure masked by the crash. PI-5216 (feat(payment): PI-5216 show full list of payment methods when GooglePay direct-pay flow payment is processed #3267) mocked _completeCheckoutFlow to a no-op in the direct-pay describe, but that method is the only place LoadingHide is called on the success path — so should hide loading indicator after completing checkout could never pass.

This PR fixes the suite with test-only changes — no production code is touched:

  • Create a fresh button per test (beforeAllbeforeEach, removed in afterEach) so click listeners can't accumulate across tests.
  • For the two tests whose flow rejects (onError, getNonce), capture the registered click handler and await expect(...).rejects.toThrow(...) instead of fire-and-forget button.click() — matching the existing feat(payment): PI-5215 [FE][Google Pay] Implement container mode in GooglePayPaymentStrategy #3247 container-test pattern.
  • For should hide loading indicator after completing checkout, restore the real _completeCheckoutFlow (jsdom only logs the unimplemented window.location.replace, it doesn't throw) so the test asserts genuine production behaviour rather than a stub.

Rollout/Rollback

No production impact — changes are limited to packages/google-pay-integration/src/google-pay-payment-strategy.spec.ts. No experiments, feature flags, or database migrations. Rollback is a straight revert of this commit.

Testing

  • npx nx run google-pay-integration:test71 suites / 414 tests pass, run repeatedly with no flaky worker crashes (the failure was timing-sensitive).
  • npx eslint packages/google-pay-integration/src/google-pay-payment-strategy.spec.ts → clean.
  • Verified each change is independently necessary: with the fresh button alone, reverting onError to button.click() still crashes; the _completeCheckoutFlow test now exercises the real method (confirmed it calls LoadingHide via production code, not a stub).

Before:
Screenshot 2026-06-25 at 14 23 20

After:
Screenshot 2026-06-25 at 14 24 42


Note

Low Risk
Changes are confined to one spec file with no production code, payment runtime, or deployment impact.

Overview
Test-only updates to google-pay-payment-strategy.spec.ts so the suite stops crashing Jest workers after the Jest 29 / Node 22 upgrade (unhandled promise rejections are no longer tolerated).

Wallet button setup now uses beforeEach to create and append a fresh DOM node and afterEach to remove it, instead of a shared beforeAll button that let click listeners stack across tests.

For flows that reject (onError on widget failure, coupons path when getNonce fails), tests no longer fire button.click() without awaiting; they pull the registered click handler from addEventListener mocks and await expect(...).rejects.toThrow(...), matching the existing container-button pattern.

In the direct-pay-on-click block, should hide loading indicator after completing checkout restores the real _completeCheckoutFlow (drops the no-op spy) so LoadingHide is asserted on the actual success path instead of a stub that never hid loading.

Reviewed by Cursor Bugbot for commit 9a86996. Bugbot is set up for automated code reviews on this repo. Configure here.

@PavlenkoM
PavlenkoM requested review from a team as code owners June 25, 2026 12:50
@PavlenkoM
PavlenkoM marked this pull request as draft June 25, 2026 12:55
@PavlenkoM
PavlenkoM marked this pull request as ready for review June 25, 2026 13:01
@PavlenkoM

Copy link
Copy Markdown
Contributor Author

cursor review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 9a86996. Configure here.

@PavlenkoM
PavlenkoM merged commit e8df371 into bigcommerce:master Jun 25, 2026
12 checks passed
@PavlenkoM
PavlenkoM deleted the PI-0000-fix-google-pay-test branch June 25, 2026 13:19
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.

3 participants