Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,45 @@ jobs:
- name: Verify package (publint)
run: pnpm verify

- name: Build sample app
run: pnpm sample:build

# Cache Playwright's browser binaries (~92MB compressed) keyed on the
# installed @playwright/test version. On cache hit we skip the binary
# download and only install the apt system deps (which live outside the
# cache). On miss we install both via `--with-deps`.
- name: Get Playwright version
id: playwright-version
run: |
VERSION=$(node -e "console.log(require('@playwright/test/package.json').version)")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}

- name: Install Playwright browsers + system deps (cache miss)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium

- name: Install Playwright system deps only (cache hit)
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: pnpm exec playwright install-deps chromium

- name: E2E tests (playwright → sample app)
run: pnpm e2e

- name: Upload Playwright report on failure
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-report
path: platforms/web/playwright-report/
retention-days: 7

- name: Pack and inspect contents
run: |
pnpm pack --pack-destination /tmp/web-pack
Expand Down
6 changes: 6 additions & 0 deletions platforms/web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ Thumbs.db
.env
.env.local
.env.*.local

# Playwright
playwright-report/
test-results/
blob-report/
playwright/.cache/
7 changes: 7 additions & 0 deletions platforms/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ pnpm test:watch
pnpm lint # typecheck + oxlint + oxfmt --check
pnpm format # oxfmt (writes in place)
pnpm verify # publint

pnpm sample # serve the playground at http://localhost:5173
pnpm sample:build # build the playground (sample/dist/)

pnpm e2e:install # one-time: download playwright's chromium binary
pnpm e2e # run playwright e2e tests against the playground
pnpm e2e:ui # interactive playwright UI mode
```

## Tooling
Expand Down
6 changes: 6 additions & 0 deletions platforms/web/e2e/header.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { expect, test } from "@playwright/test";

test("playground header shows the Checkout Kit heading", async ({ page }) => {
await page.goto("/");
await expect(page.getByRole("heading", { level: 1 })).toHaveText("Checkout Kit");
});
13 changes: 13 additions & 0 deletions platforms/web/e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
// Playwright tests run in node via the @playwright/test runner — they
// don't need our library-grade isolatedDeclarations rule, and they need
// node + playwright globals instead of vitest globals.
"isolatedDeclarations": false,
"declaration": false,
"noEmit": true,
"types": ["node", "@playwright/test"]
},
"include": ["./**/*.ts", "../playwright.config.ts"]
}
19 changes: 14 additions & 5 deletions platforms/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,26 @@
"dev": "vite build --watch",
"test": "vitest run --coverage",
"test:watch": "vitest",
"lint": "pnpm run typecheck && pnpm run lint:js && pnpm run format:check",
"lint:js": "oxlint --report-unused-disable-directives --max-warnings 0 src",
"lint:js:fix": "oxlint --fix src",
"format": "oxfmt src",
"format:check": "oxfmt --check src",
"lint": "pnpm run typecheck && pnpm run sample:typecheck && pnpm run e2e:typecheck && pnpm run lint:js && pnpm run format:check",
"lint:js": "oxlint --report-unused-disable-directives --max-warnings 0 src sample e2e",
"lint:js:fix": "oxlint --fix src sample e2e",
"format": "oxfmt src sample e2e",
"format:check": "oxfmt --check src sample e2e",
"typecheck": "tsc --noEmit",
"sample": "vite --config sample/vite.config.ts",
"sample:build": "vite build --config sample/vite.config.ts",
"sample:preview": "vite preview --config sample/vite.config.ts",
"sample:typecheck": "tsc --noEmit -p sample/tsconfig.json",
"e2e": "playwright test",
"e2e:ui": "playwright test --ui",
"e2e:install": "playwright install --with-deps chromium",
"e2e:typecheck": "tsc --noEmit -p e2e/tsconfig.json",
"verify": "publint",
"prepack": "pnpm run build"
},
"devDependencies": {
"@custom-elements-manifest/analyzer": "^0.10.4",
"@playwright/test": "^1.59.1",
"@types/node": "^22.10.0",
"@vitest/coverage-v8": "^3.2.4",
"happy-dom": "^15.11.7",
Expand Down
43 changes: 43 additions & 0 deletions platforms/web/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {defineConfig, devices} from "@playwright/test";

const PORT = 5174;
const BASE_URL = `http://localhost:${PORT}`;

export default defineConfig({
testDir: "./e2e",
// Only `*.spec.ts` so vitest unit tests under `src/` are never picked up.
testMatch: /.*\.spec\.ts$/,
fullyParallel: true,
// Fail CI if a `.only` is left in.
forbidOnly: Boolean(process.env["CI"]),
retries: process.env["CI"] ? 2 : 0,
workers: process.env["CI"] ? 1 : undefined,
reporter: process.env["CI"]
? [["github"], ["html", {open: "never"}]]
: "list",
use: {
baseURL: BASE_URL,
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "off",
},
projects: [
// Start with chromium only. Add `firefox` and `webkit` here when
// cross-browser coverage becomes a real concern.
{
name: "chromium",
use: {...devices["Desktop Chrome"]},
},
],
webServer: {
// Use the vite dev server on a dedicated port so it can run alongside
// a regular `pnpm sample` session on :5173 without conflict. `--no-open`
// suppresses the auto-open behavior set in sample/vite.config.ts.
command: `vite --config sample/vite.config.ts --port ${PORT} --strictPort --no-open`,
url: BASE_URL,
reuseExistingServer: !process.env["CI"],
timeout: 60_000,
stdout: "pipe",
stderr: "pipe",
},
});
38 changes: 38 additions & 0 deletions platforms/web/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 55 additions & 0 deletions platforms/web/sample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Web Component Playground

A development harness for the `<shopify-checkout>` web component. Renders the
component with adjustable options and logs all dispatched `checkout:*` events
in real time.

## Run locally

```bash
cd platforms/web
pnpm sample
```

Vite serves at `http://localhost:5173`. The page has three panels:

- **Options** — form for setting the component's attributes (`src`,
`target`, `color-scheme`, `preload`) plus a small panel of manual method
buttons (`open()`, `close()`, `focus()`) for ad-hoc debugging.
- **Demo Storefront** — a mocked merchant product card with a **Buy now**
button that calls `checkout.open()`. The button is disabled until you
enter a checkout URL in the Options panel. Below the card, a collapsible
readout shows the component's read-only state (`cart`, `locale`,
`orderConfirmation`, `error`, `sessionId`).
- **Events** — a chronological log of every `checkout:*` event the component
dispatches, with a snapshot of component state at the moment the event
fired. Respondable events are tagged with a badge.

The `<shopify-checkout>` element is appended to `<body>` rather than placed
inside the storefront panel — for `popup` and `auto` targets, the element
has no visible footprint of its own; only its internal dialog scrim appears
when `open()` is called. `target="inline"` is intentionally not supported
in the v1 of the component.

## Status

The `<shopify-checkout>` component implementation has not yet landed in
`../src`. Until it does, the element renders as an unknown HTML element and
dispatches no events — the playground is wired up against the component's
eventual API surface but is **non-functional at runtime**.

The forward-looking API surface is declared in [`./types.d.ts`](./types.d.ts).
Delete that file once `@shopify/checkout-kit` exports the real `ShopifyCheckout`
types from `../src`.

## Build

```bash
pnpm sample:build # outputs to sample/dist/
```

CI runs this on every PR (see `.github/workflows/web.yml`) so the sample stays
buildable as the package evolves.

The sample is **not** published to npm — it's excluded by the `files`
allowlist in `platforms/web/package.json`.
Loading
Loading