Skip to content

Add Shopify checkout Playwright integration test#461

Merged
shayancoin merged 1 commit intomainfrom
codex/add-playwright-test-for-shopify-checkout
Oct 20, 2025
Merged

Add Shopify checkout Playwright integration test#461
shayancoin merged 1 commit intomainfrom
codex/add-playwright-test-for-shopify-checkout

Conversation

@shayancoin
Copy link
Owner

@shayancoin shayancoin commented Oct 20, 2025

Summary

  • add a Playwright spec that provisions Shopify fixtures, performs a Storefront checkout, and waits for backend reporting
  • extend the shared Playwright configuration with a dedicated Shopify project, CI-friendly retries, and conditional web-server bootstrapping
  • document the new CI job along with the Shopify and Supabase secrets it requires

Testing

  • cd frontend && npx playwright test --config=../playwright.config.ts --project=shopify-integration

https://chatgpt.com/codex/tasks/task_e_68f66b85ea208330869c8b3cdf5d2582

Summary by CodeRabbit

  • Documentation

    • Updated release checklist to include Shopify integration CI validation and failure signature export guidance.
  • Tests

    • Added comprehensive Shopify checkout integration tests supporting live and mock modes for end-to-end checkout flow validation and backend ingestion verification.

@vercel
Copy link

vercel bot commented Oct 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
paform Ready Ready Preview Comment Oct 20, 2025 6:39pm

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Walkthrough

The changes introduce a multi-project Playwright configuration separating frontend and Shopify integration test execution, add a comprehensive Shopify checkout test spec with live and mock operation modes, and expand the release checklist with explicit Shopify integration verification steps and GitHub Actions secrets documentation.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/release-checklist.md
Expanded CI verification gate: adds shopify-integration Playwright job validation alongside existing performance-budget checks; documents Shopify configuration provisioning, storefront checkout execution, and backend ingestion with required/optional GitHub Actions secrets; retains observability-budgets validation; adds guidance to export failure signatures to on-call runbook.
Playwright Multi-Project Configuration
playwright.config.ts
Restructures config from single testDir to modular two-project setup (frontend-e2e and shopify-integration); adds conditional NODE_PATH initialization and Module._initPaths() call for module resolution; introduces projects array with individualized timeout and use options; adds dynamic webServer configuration omitted when specific projects requested; implements collectRequestedProjects helper for command-line argument parsing; consolidates environment variable handling (frontendEnv, sharedUseOptions) for consistent headless/trace behavior.
Shopify Integration Test Suite
tests/shopify-checkout.spec.ts
Introduces comprehensive Playwright spec with TypeScript interfaces for config, Shopify payloads, and clients; implements fixture-based test suite with memory-backed state; adds dual-mode operation (live vs. mock): live mode provisions Shopify storefront client and polls Supabase for backend ingestion with retry/timeout logic; mock mode simulates end-to-end flow with in-memory clients; includes mock factory functions (createMockStorefront, createMockSupabase), safe JSON parsing utilities, and structured test steps validating module config, checkout execution, and backend status.

Sequence Diagram(s)

sequenceDiagram
    participant Test as shopify-checkout.spec.ts
    participant Config as playwright.config.ts
    participant Storefront as Shopify Storefront
    participant Helper as Backend Helper
    participant Supabase as Supabase Admin
    
    Test->>Test: Determine mode (live/mock)
    alt Live Mode
        Test->>Storefront: Construct client with tokens
        Test->>Test: Create checkout payload
        Test->>Storefront: Send test checkout
        Storefront->>Helper: Forward checkout request
        Helper-->>Storefront: Process & return
        Storefront-->>Test: Checkout response
        Test->>Supabase: Upsert module config
        Test->>Supabase: Poll order record (retry)
        Supabase-->>Test: Ingestion complete
        Test->>Test: Assert identifiers & status
    else Mock Mode
        Test->>Test: Initialize in-memory storefront
        Test->>Test: Create mock Supabase client
        Test->>Test: Execute checkout locally
        Test->>Test: Simulate ingestion
        Test->>Test: Assert identifiers & status
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

The changes span heterogeneous modifications across configuration, test infrastructure, and documentation. The playwright.config.ts restructuring involves conditional logic, dynamic project configuration, NODE_PATH manipulation, and helper functions requiring careful validation. The shopify-checkout.spec.ts introduces a substantial new test suite with dual operation modes (live/mock), external API integration, polling logic with retry/timeout semantics, mock implementations, and interface definitions—each requiring separate reasoning. The documentation update is straightforward but contextualizes the overall scope. Combined complexity and file diversity warrant mid-to-high review intensity.

Possibly related PRs

  • Configure Playwright defaults for CI #115: Modifies playwright.config.ts to add root configuration and update frontend test script setup; the main PR extends this into a multi-project structure with dynamic webServer behavior and environment scaffolding.
  • Add CI-aligned Playwright config #102: Restructures playwright.config.ts from single to multi-project CI-aligned configuration; the main PR replaces this with a more modular structure supporting both frontend and Shopify integration projects.
  • Add Playwright global setup for artifacts directory #165: Modifies playwright.config.ts to adjust test runner behavior via globalSetup; overlaps with the main PR's restructuring of webServer and project configuration logic.

Poem

🐰 Playwright hops in, now two projects dance,
Frontend and Shopify in sweet expanse.
Mock and live modes, a toggle so keen,
Checkout flows tested—the best ever seen!
CI gates rise, our checklist grows long,
Release day strong, our integration song!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The provided description does not follow the required template structure specified for this repository. The template requires three sections: PR Type, Short Description, and Tests Added. The author instead provided Summary, Testing, and an external link, completely omitting the explicit PR Type designation. While the description does contain substantive information about what was changed and how to test it, the failure to follow the template structure and missing PR Type makes this non-compliant with the repository's requirements for pull request documentation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Add Shopify checkout Playwright integration test" accurately describes the primary addition in this changeset—a new comprehensive Playwright test spec for Shopify checkout integration. While the PR also includes supporting changes to the Playwright configuration and documentation updates, the title correctly identifies the core addition (the new test file). The title is specific, concise, and clearly communicates the main purpose of the PR to someone scanning the commit history.
✨ Finishing touches
  • 📝 Docstrings were successfully generated.
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/add-playwright-test-for-shopify-checkout

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +217 to +219
while (Date.now() < deadline) {
const response = await fetch(`${supabaseUrl}/rest/v1/${DEFAULT_ORDER_TABLE}?order_id=eq.${encodeURIComponent(orderId)}`, {
method: 'GET',

Choose a reason for hiding this comment

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

P1 Badge Include select clause when polling Supabase REST API

The Supabase polling loop calls GET ${supabaseUrl}/rest/v1/${DEFAULT_ORDER_TABLE}?order_id=eq.${…} but omits a select query parameter. PostgREST requires select on GET requests; without it the endpoint responds with HTTP 406 and this path always throws before reading any order rows. As a result the integration test will fail even when the order has been ingested. Add ?select=* (or the specific columns) to the request so the poller can return the row when it exists.

Useful? React with 👍 / 👎.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/release-checklist.md (1)

36-39: Gate must also include the new shopify-integration job.

Update this bullet to explicitly require shopify-integration to pass (in addition to performance-budget and observability-budgets) to keep the gate consistent with Section 1.

-  - All CI jobs, including `performance-budget` and `observability-budgets`, pass.
+  - All CI jobs pass, including `performance-budget`, `observability-budgets`, and `shopify-integration`.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c765892 and 6f5d9e2.

📒 Files selected for processing (3)
  • docs/release-checklist.md (1 hunks)
  • playwright.config.ts (3 hunks)
  • tests/shopify-checkout.spec.ts (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
tests/shopify-checkout.spec.ts

[error] 85-85: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

Comment on lines +8 to +17
- Confirm the **shopify-integration** Playwright job passes. It executes `tests/shopify-checkout.spec.ts`, which provisions Shopify configuration, drives a Storefront test checkout, and waits for the backend to ingest the order. Configure the following GitHub Actions secrets so the run can talk to Shopify and Supabase:
- `SHOPIFY_STORE_DOMAIN`
- `SHOPIFY_STOREFRONT_ACCESS_TOKEN`
- `SHOPIFY_STOREFRONT_HELPER_URL`
- `SHOPIFY_STOREFRONT_HELPER_TOKEN` (if the helper requires bearer auth)
- `SHOPIFY_TEST_VARIANT_ID`
- `SHOPIFY_TEST_CURRENCY` (defaults to `USD` if omitted)
- `SUPABASE_URL`
- `SUPABASE_SERVICE_ROLE_KEY`
- Optional: `SHOPIFY_MODULE_CONFIG_TABLE` and `SHOPIFY_ORDER_TABLE` when the Supabase schema uses custom table names.
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Harden secrets handling for CI (service-role key).

Document safeguards for SUPABASE_SERVICE_ROLE_KEY and other tokens:

  • Use GitHub Environments with required reviewers and secret scoping to shopify-integration only.
  • Ensure logs/artifacts never echo secrets; mask them and avoid attaching request/response bodies that may include auth headers.
  • Prefer short‑lived tokens if possible; rotate on a schedule and after test failures/incidents.

Adding these points here prevents accidental leakage during integration runs.

🤖 Prompt for AI Agents
In docs/release-checklist.md around lines 8–17, the checklist currently lists
GitHub Actions secrets for the shopify-integration job but lacks CI
secret-handling safeguards; update this section to document concrete protections
for SUPABASE_SERVICE_ROLE_KEY and other tokens by: add bullets instructing use
of GitHub Environments scoped to the shopify-integration workflow with required
reviewers, restrict secret access to the job only, ensure masking of secrets and
avoid logging or artifacting request/response bodies that may contain auth
headers, recommend short‑lived tokens plus scheduled rotation and rotation after
failures/incidents, and optionally call out using separate least-privilege
service role keys for CI versus production.

@@ -1,7 +1,9 @@
import path from 'path';
import { Module } from 'module';
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Make NODE_PATH handling cross‑platform and fix private API typing.

  • Use path.delimiter instead of hardcoded : for Windows support.
  • Module._initPaths() is private and not typed; cast to any or avoid it.
  • Prefer node: specifier for core module import.

Apply this diff:

-import { Module } from 'module';
+import { Module } from 'node:module';
@@
-const nodePathEntries = [path.resolve(__dirname, 'frontend/node_modules'), process.env.NODE_PATH].filter(Boolean) as string[];
+const nodePathEntries = [path.resolve(__dirname, 'frontend/node_modules'), process.env.NODE_PATH]
+  .filter(Boolean) as string[];
 if (nodePathEntries.length > 0) {
-  process.env.NODE_PATH = nodePathEntries.join(':');
-  Module._initPaths();
+  process.env.NODE_PATH = nodePathEntries.join(path.delimiter);
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  (Module as any)._initPaths?.();
 }

Alternatively, avoid NODE_PATH entirely by using TS path aliases + bundler resolution.

Also applies to: 34-38

🤖 Prompt for AI Agents
In playwright.config.ts around lines 2 and 34-38, the code imports the private
Module API and assumes POSIX NODE_PATH separator; change the import to use the
core specifier (import Module from 'node:module' or import * as Module from
'node:module') and replace hardcoded ':' with path.delimiter from the path
module to make NODE_PATH handling cross‑platform; avoid directly calling/typing
Module._initPaths() by casting Module to any when invoking it or refactor to not
call it at all (e.g., rebuild NODE_PATH into process.env.NODE_PATH or rely on TS
path aliases + bundler), and ensure any modifications to NODE_PATH
append/prepend using path.delimiter consistently for Windows support.

Comment on lines +55 to +59
use: {
...sharedUseOptions,
baseURL: process.env.BASE_URL || 'http://localhost:3000',
env: frontendEnv,
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

use.env is not a supported Playwright option (TS/type error and no effect).

This will fail type‑checking under PlaywrightTestConfig and won’t set process.env for tests. Tests already read process.env.* directly, and webServer.env correctly seeds Next’s dev server.

  • Remove env under use for both projects.
  • Keep env only where supported (webServer.env).
  • Also avoid actionTimeout: 0; prefer a bounded value to prevent hangs.

Apply this diff:

@@
-      use: {
-        ...sharedUseOptions,
-        baseURL: process.env.BASE_URL || 'http://localhost:3000',
-        env: frontendEnv,
-      },
+      use: {
+        ...sharedUseOptions,
+        baseURL: process.env.BASE_URL || 'http://localhost:3000',
+      },
@@
-      use: {
-        ...sharedUseOptions,
-        actionTimeout: 0,
-        baseURL: process.env.BACKEND_BASE_URL || 'http://localhost:8787',
-        env: {
-          SHOPIFY_STORE_DOMAIN: process.env.SHOPIFY_STORE_DOMAIN || '',
-          SHOPIFY_STOREFRONT_ACCESS_TOKEN: process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN || '',
-          SHOPIFY_STOREFRONT_HELPER_URL: process.env.SHOPIFY_STOREFRONT_HELPER_URL || '',
-          SHOPIFY_STOREFRONT_HELPER_TOKEN: process.env.SHOPIFY_STOREFRONT_HELPER_TOKEN || '',
-          SHOPIFY_TEST_VARIANT_ID: process.env.SHOPIFY_TEST_VARIANT_ID || '',
-          SHOPIFY_TEST_CURRENCY: process.env.SHOPIFY_TEST_CURRENCY || 'USD',
-          SHOPIFY_MODULE_CONFIG_TABLE: process.env.SHOPIFY_MODULE_CONFIG_TABLE || 'shopify_module_configurations',
-          SHOPIFY_ORDER_TABLE: process.env.SHOPIFY_ORDER_TABLE || 'shopify_orders',
-          SUPABASE_URL: process.env.SUPABASE_URL || '',
-          SUPABASE_SERVICE_ROLE_KEY: process.env.SUPABASE_SERVICE_ROLE_KEY || '',
-          NODE_PATH: [path.resolve(__dirname, 'frontend/node_modules'), process.env.NODE_PATH]
-            .filter(Boolean)
-            .join(':'),
-        },
-      },
+      use: {
+        ...sharedUseOptions,
+        actionTimeout: process.env.CI ? 30_000 : 45_000,
+        baseURL: process.env.BACKEND_BASE_URL || 'http://localhost:8787',
+      },

Also applies to: 67-86

🤖 Prompt for AI Agents
In playwright.config.ts around lines 55–59 (and similarly lines 67–86), the
configuration incorrectly sets use.env (unsupported by Playwright types and has
no effect) and sets actionTimeout: 0; remove the env property from each use
block so you only seed environment variables via webServer.env, and replace
actionTimeout: 0 with a reasonable bounded timeout (e.g., a nonzero millisecond
value) to avoid potential test hangs.

Comment on lines +85 to +89
memoryState: async ({}, use) => {
const state: InMemoryState = { orders: new Map() };
await use(state);
},
moduleConfig: async ({ memoryState }, use) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix Biome error: avoid empty object pattern in fixture param.

Replace the empty destructuring with an unused identifier.

-  memoryState: async ({}, use) => {
+  memoryState: async (_ctx, use) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
memoryState: async ({}, use) => {
const state: InMemoryState = { orders: new Map() };
await use(state);
},
moduleConfig: async ({ memoryState }, use) => {
memoryState: async (_ctx, use) => {
const state: InMemoryState = { orders: new Map() };
await use(state);
},
moduleConfig: async ({ memoryState }, use) => {
🧰 Tools
🪛 Biome (2.1.2)

[error] 85-85: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🤖 Prompt for AI Agents
In tests/shopify-checkout.spec.ts around lines 85 to 89, the fixture uses an
empty object destructuring in the parameter list (async ({}, use) => ...) which
triggers a Biome lint/error; replace the empty destructuring with an unused
identifier (for example async (_context, use) => or async (_ , use) =>) so the
signature is valid and the fixture behavior remains unchanged.

Comment on lines +121 to +139
const client: ShopifyStorefrontClient = {
async performTestCheckout(payload) {
const requestBody = {
email: payload.email,
lineItems: payload.lineItems,
shippingAddress: payload.shippingAddress,
currencyCode: moduleConfig.currencyCode,
note: payload.note ?? `Playwright checkout for ${testInfo.title}`,
};

const response = await fetch(new URL('/test-checkout', storefrontHelperUrl).toString(), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': storefrontAccessToken,
...(helperAuthToken ? { Authorization: `Bearer ${helperAuthToken}` } : {}),
},
body: JSON.stringify(requestBody),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add request timeouts to external calls (prevent hung CI) — prefer Playwright request or a small timeout helper.

Current fetch calls have no timeout; network stalls can hang the test despite project timeouts.

Option A (preferred): use APIRequestContext (test.request)

  • Inject request into fixtures and replace fetch with request.post/get including timeout.

Option B: add fetchWithTimeout and use it here.

Diff (Option B – minimal change):

@@
-          const response = await fetch(new URL('/test-checkout', storefrontHelperUrl).toString(), {
+          const response = await fetchWithTimeout(new URL('/test-checkout', storefrontHelperUrl).toString(), {
             method: 'POST',
             headers: {
               'Content-Type': 'application/json',
               'X-Shopify-Storefront-Access-Token': storefrontAccessToken,
               ...(helperAuthToken ? { Authorization: `Bearer ${helperAuthToken}` } : {}),
             },
             body: JSON.stringify(requestBody),
+            timeoutMs: 60_000,
           });
@@
-          const response = await fetch(`${supabaseUrl}/rest/v1/${DEFAULT_MODULE_CONFIG_TABLE}`, {
+          const response = await fetchWithTimeout(`${supabaseUrl}/rest/v1/${DEFAULT_MODULE_CONFIG_TABLE}`, {
             method: 'POST',
             headers: {
               ...headers,
               Prefer: 'resolution=merge-duplicates',
             },
             body: JSON.stringify(payload),
+            timeoutMs: 30_000,
           });
@@
-            const response = await fetch(`${supabaseUrl}/rest/v1/${DEFAULT_ORDER_TABLE}?order_id=eq.${encodeURIComponent(orderId)}`, {
+            const response = await fetchWithTimeout(`${supabaseUrl}/rest/v1/${DEFAULT_ORDER_TABLE}?order_id=eq.${encodeURIComponent(orderId)}`, {
               method: 'GET',
-              headers,
+              headers,
+              timeoutMs: 30_000,
             });

Add this helper near delay:

+async function fetchWithTimeout(input: RequestInfo, init: (RequestInit & { timeoutMs?: number }) = {}): Promise<Response> {
+  const { timeoutMs = 60_000, ...rest } = init;
+  const ac = new AbortController();
+  const id = setTimeout(() => ac.abort(), timeoutMs);
+  try {
+    return await fetch(input, { ...rest, signal: ac.signal });
+  } finally {
+    clearTimeout(id);
+  }
+}

If you’d like Option A, I can provide a patch wiring request into the fixtures.

Also applies to: 196-204, 217-235

🤖 Prompt for AI Agents
In tests/shopify-checkout.spec.ts around lines 121 to 139, the test's external
POST using fetch has no timeout and can hang CI; replace this fetch with a
Playwright APIRequestContext call (test.request.post) configured with a timeout,
or if you choose the minimal change implement and use a fetchWithTimeout helper
that wraps fetch with an abort controller and a short default timeout, then call
that helper here with an appropriate timeout value; ensure headers/body remain
the same and propagate any thrown errors so the test fails fast.

@shayancoin shayancoin merged commit 306cd6f into main Oct 20, 2025
7 of 12 checks passed
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #463

coderabbitai bot added a commit that referenced this pull request Oct 20, 2025
Docstrings generation was requested by @shayancoin.

* #461 (comment)

The following files were modified:

* `playwright.config.ts`
shayancoin pushed a commit that referenced this pull request Oct 20, 2025
…463)

Docstrings generation was requested by @shayancoin.

* #461 (comment)

The following files were modified:

* `playwright.config.ts`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant