Skip to content

Added e2e Stripe checkout initiation support - #26875

Merged
9larsons merged 4 commits into
mainfrom
mg-e2e-stripe-checkout-initiation
Mar 18, 2026
Merged

Added e2e Stripe checkout initiation support#26875
9larsons merged 4 commits into
mainfrom
mg-e2e-stripe-checkout-initiation

Conversation

@9larsons

@9larsons 9larsons commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

no ref

Added Stripe checkout initialization tests to /e2e/. This includes a nasty-looking smoke test that is helping validate the fake Stripe functionality while we build out the rest of this suite.

ref #26810

This adds the fake Stripe product, price, customer, and checkout-session surface needed to start migrating paid signup browser coverage into e2e.
@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Reworks E2E Stripe test tooling: introduces exported Stripe-like TypeScript types and refactors builder functions to return those types; adds composite helpers (StripeList, subscription/checkout session shapes); expands FakeStripeServer with in-memory storage, new product/price/checkout endpoints, parsing utilities, explicit error responses, and upsert/getter methods; exposes server getters via StripeTestService; extends TiersService with AdminTier and createTier; and adds a new E2E smoke test for Stripe checkout initiation.

Possibly related PRs

Suggested reviewers

  • cmraible
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding end-to-end Stripe checkout initiation support, which aligns with the primary changeset.
Description check ✅ Passed The description is directly related to the changeset, explaining that Stripe checkout initialization tests were added to /e2e/ with a smoke test for validating fake Stripe functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mg-e2e-stripe-checkout-initiation
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
e2e/tests/public/stripe-checkout-initiation.test.ts (1)

18-82: Split this into clearer Arrange / Act / Assert phases.

The flow currently does arrange -> assert -> act -> assert -> act -> assert, which makes failures harder to localize and doesn't match the ADR's "clear sections" requirement. Pulling the Stripe-sync checks fully into Arrange (or a helper) and keeping the checkout request/navigation in Act would make this easier to read and debug.

As per coding guidelines, "Use the AAA Pattern (Arrange, Act, Assert) in E2E tests with clear sections".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/public/stripe-checkout-initiation.test.ts` around lines 18 - 82,
Split the test into clear Arrange / Act / Assert sections: in Arrange create the
member and tier (using createMemberFactory and TiersService.createTier), wait
for Stripe to sync (use stripe!.getProducts(), stripe!.getPrices(),
stripe!.getCustomers(), stripe!.getCheckoutSessions() checks or extract them
into a helper like ensureStripeSynced) and capture
product/monthlyPrice/yearlyPrice variables; in Act perform the checkout session
creation request (the page.request.post to
/members/api/create-stripe-checkout-session/ and navigation to
sessionResponse.url); in Assert move all expect(...) checks
(product/monthlyPrice/yearlyPrice properties, response.ok(), sessionResponse
contents, customer/session assertions, and page heading visibility) into the
final Assert block so failures are isolated and the flow follows AAA.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/helpers/services/stripe/fake-stripe-server.ts`:
- Around line 157-171: The price-creation route builds a synthetic product id
when req.body.product is missing but never saves that product, causing later
/v1/products/:id lookups to 404; update the handler so when product is derived
from buildProduct() (i.e., parseString(req.body.product) returns null) you
create and persist that synthetic product via the existing buildProduct() and
upsertProduct(...) before calling upsertPrice(...). Use the same product id
assigned to buildPrice (reference parseString, buildProduct, buildPrice,
upsertProduct, upsertPrice) so the created price’s product exists in the fake
store.

In `@e2e/tests/public/stripe-checkout-initiation.test.ts`:
- Around line 14-17: Rename the test suite string and the individual test title
to follow E2E naming rules: change the suite name "Public - Stripe Checkout
Initiation" to "Ghost Public - Stripe Checkout Initiation" and rename the test
title from "paid tier syncs to fake Stripe and checkout returns a fake session
URL" to a lowercase "what is tested - expected outcome" form such as "paid tier
syncs to fake Stripe - checkout returns a fake session url"; update the strings
where test.describe(...) and test(...) are declared so all assertions and
test.use({stripeEnabled: true}) remain unchanged.

---

Nitpick comments:
In `@e2e/tests/public/stripe-checkout-initiation.test.ts`:
- Around line 18-82: Split the test into clear Arrange / Act / Assert sections:
in Arrange create the member and tier (using createMemberFactory and
TiersService.createTier), wait for Stripe to sync (use stripe!.getProducts(),
stripe!.getPrices(), stripe!.getCustomers(), stripe!.getCheckoutSessions()
checks or extract them into a helper like ensureStripeSynced) and capture
product/monthlyPrice/yearlyPrice variables; in Act perform the checkout session
creation request (the page.request.post to
/members/api/create-stripe-checkout-session/ and navigation to
sessionResponse.url); in Assert move all expect(...) checks
(product/monthlyPrice/yearlyPrice properties, response.ok(), sessionResponse
contents, customer/session assertions, and page heading visibility) into the
final Assert block so failures are isolated and the flow follows AAA.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fb930ac6-65e5-478d-b883-8aac5b89bbb1

📥 Commits

Reviewing files that changed from the base of the PR and between 832456d and 4a17261.

📒 Files selected for processing (6)
  • e2e/helpers/services/stripe/builders.ts
  • e2e/helpers/services/stripe/fake-stripe-server.ts
  • e2e/helpers/services/stripe/index.ts
  • e2e/helpers/services/stripe/stripe-service.ts
  • e2e/helpers/services/tiers/tiers-service.ts
  • e2e/tests/public/stripe-checkout-initiation.test.ts

Comment thread e2e/helpers/services/stripe/fake-stripe-server.ts
Comment thread e2e/tests/public/stripe-checkout-initiation.test.ts Outdated

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/helpers/services/stripe/fake-stripe-server.ts`:
- Around line 395-407: The mapping over subscriptionData.items and line_items
can crash if entries are null; update the items and line_items handling in
fake-stripe-server.ts to first filter entries with "item != null && typeof item
=== 'object'" before mapping, and use optional chaining when calling helpers
(e.g., replace parseString(item.plan) with parseString(item?.plan) and
parseNumber(item.price) with parseNumber(item?.price)); ensure you still filter
out empty strings after parsing (e.g., .map(...).filter(item => item.plan)).
This touches the code that uses parseString, parseNumber, parseBoolean, and
parseMetadata so keep those calls but guard inputs as described.
- Around line 159-169: The handler currently accepts a caller-provided product
ID (via parseString(req.body.product)) without verifying it exists, leading to
prices referencing missing products; change the logic in the price-creation path
(involving parseString, buildProduct, upsertProduct, buildPrice, and
parseBoolean) so that if a product ID is provided you first check this.products
(or the products store) for that ID and reject the request with a 4xx error when
not found; only create a synthetic product (via buildProduct and upsertProduct)
when no product ID was provided, then proceed to buildPrice using a
guaranteed-existing productId.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 792e218d-fa96-4038-bdee-49855333c9cd

📥 Commits

Reviewing files that changed from the base of the PR and between 4a17261 and d0c7bb0.

📒 Files selected for processing (2)
  • e2e/helpers/services/stripe/fake-stripe-server.ts
  • e2e/tests/public/stripe-checkout-initiation.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • e2e/tests/public/stripe-checkout-initiation.test.ts

Comment thread e2e/helpers/services/stripe/fake-stripe-server.ts
Comment thread e2e/helpers/services/stripe/fake-stripe-server.ts

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

🧹 Nitpick comments (1)
e2e/helpers/services/stripe/fake-stripe-server.ts (1)

326-329: Consider returning 404 for unhandled routes.

The fallback returns 200 for all unhandled routes, which could mask issues where Ghost calls unexpected Stripe endpoints. While permissive behavior helps tests not fail on unimplemented routes, a 404 would more accurately simulate Stripe's behavior and help surface integration gaps earlier.

♻️ Optional: Return 404 for unhandled routes
         this.app.use((req, res) => {
             debug(`Unhandled route: ${req.method} ${req.originalUrl} — returning fallback`);
-            res.status(200).json({id: 'fake', object: 'unknown'});
+            res.status(404).json({error: {type: 'invalid_request_error', message: `Unhandled route: ${req.method} ${req.originalUrl}`}});
         });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/helpers/services/stripe/fake-stripe-server.ts` around lines 326 - 329,
The fallback route in the fake Stripe server (the middleware using this.app.use
that currently logs via debug and responds with res.status(200).json(...))
should return a 404 to better simulate Stripe and surface unexpected calls;
update the middleware to send res.status(404).json(...) (optionally include a
small error object like {error: 'Unhandled route'} or the original path) while
keeping the debug(...) log so unhandled requests are still recorded.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/helpers/services/stripe/fake-stripe-server.ts`:
- Around line 326-329: The fallback route in the fake Stripe server (the
middleware using this.app.use that currently logs via debug and responds with
res.status(200).json(...)) should return a 404 to better simulate Stripe and
surface unexpected calls; update the middleware to send
res.status(404).json(...) (optionally include a small error object like {error:
'Unhandled route'} or the original path) while keeping the debug(...) log so
unhandled requests are still recorded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dfb066e8-9820-4ca1-ba96-0ea1d78ad6d4

📥 Commits

Reviewing files that changed from the base of the PR and between d0c7bb0 and b044a07.

📒 Files selected for processing (1)
  • e2e/helpers/services/stripe/fake-stripe-server.ts

@9larsons
9larsons enabled auto-merge (squash) March 18, 2026 19:05
@9larsons
9larsons merged commit 2f58ef8 into main Mar 18, 2026
28 checks passed
@9larsons
9larsons deleted the mg-e2e-stripe-checkout-initiation branch March 18, 2026 19:38
franky19 pushed a commit to franky19/Ghost that referenced this pull request Apr 18, 2026
no ref

Added Stripe checkout initialization tests to `/e2e/`. This includes a
nasty-looking smoke test that is helping validate the fake Stripe
functionality while we build out the rest of this suite.
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