Skip to content

Commit e0ae4cb

Browse files
authored
Merge pull request #6899 from Shopify/e2e-testing
Add e2e test infrastructure with Playwright + node-pty
2 parents 763680e + b6626f6 commit e0ae4cb

15 files changed

Lines changed: 781 additions & 265 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ packages/*/docs/
151151

152152
packaging/dist
153153

154+
# E2E test temp directories and artifacts
155+
.e2e-tmp
156+
154157
# Shadowenv generates user-specific files that shouldn't be committed
155158
.shadowenv.d/
156159

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"post-release": "./bin/post-release",
2929
"shopify:run": "node packages/cli/bin/dev.js",
3030
"shopify": "nx build cli && node packages/cli/bin/dev.js",
31+
"test:e2e": "nx run-many --target=build --projects=cli,create-app --skip-nx-cache && pnpm --filter e2e exec playwright test",
3132
"test:features": "pnpm nx run features:test",
3233
"test:regenerate-snapshots": "nx build cli && packages/features/snapshots/regenerate.sh",
3334
"test:unit": "pnpm vitest run",
@@ -130,7 +131,8 @@
130131
"@graphql-typed-document-node/core"
131132
],
132133
"ignoreWorkspaces": [
133-
"packages/eslint-plugin-cli"
134+
"packages/eslint-plugin-cli",
135+
"packages/e2e"
134136
],
135137
"paths": {
136138
"@shopify/eslint-plugin-cli/configs": [

packages/e2e/.env.example

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Required: Client ID of the primary test app (must be in the genghis account's org)
2+
# CI secret: E2E_CLIENT_ID
3+
SHOPIFY_FLAG_CLIENT_ID=
4+
5+
# Required: Genghis account email for browser-based OAuth login
6+
# CI secret: E2E_ACCOUNT_EMAIL
7+
E2E_ACCOUNT_EMAIL=
8+
9+
# Required: Genghis account password for browser-based OAuth login
10+
# CI secret: E2E_ACCOUNT_PASSWORD
11+
E2E_ACCOUNT_PASSWORD=
12+
13+
# Required: Dev store FQDN for dev server / deploy tests (e.g. my-store.myshopify.com)
14+
# CI secret: E2E_STORE_FQDN
15+
E2E_STORE_FQDN=
16+
17+
# Optional: Client ID of a secondary app for config link tests
18+
# CI secret: E2E_SECONDARY_CLIENT_ID
19+
E2E_SECONDARY_CLIENT_ID=

packages/e2e/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
test-results/
3+
playwright-report/
4+
dist/
5+
.env
6+
.env.local

packages/e2e/helpers/strip-ansi.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Re-export strip-ansi as a named export for easier use.
2+
// strip-ansi v7+ is ESM-only and exports a default function.
3+
import stripAnsiModule from 'strip-ansi'
4+
5+
export const stripAnsi: (text: string) => string = stripAnsiModule

packages/e2e/package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "@shopify/e2e",
3+
"version": "0.1.0",
4+
"packageManager": "pnpm@10.11.1",
5+
"private": true,
6+
"type": "module",
7+
"scripts": {
8+
"test": "nx run e2e:test",
9+
"lint": "nx lint",
10+
"lint:fix": "nx lint:fix",
11+
"type-check": "nx type-check"
12+
},
13+
"eslintConfig": {
14+
"extends": [
15+
"../../.eslintrc.cjs"
16+
],
17+
"rules": {
18+
"no-console": "off",
19+
"import/extensions": [
20+
"error",
21+
"never",
22+
{
23+
"ignorePackages": true
24+
}
25+
]
26+
}
27+
},
28+
"devDependencies": {
29+
"@playwright/test": "^1.50.0",
30+
"@types/node": "18.19.70",
31+
"execa": "^7.2.0",
32+
"node-pty": "^1.0.0",
33+
"strip-ansi": "^7.1.0",
34+
"tempy": "^1.0.1"
35+
},
36+
"engines": {
37+
"node": ">=20.10.0"
38+
}
39+
}

packages/e2e/playwright.config.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* eslint-disable line-comment-position */
2+
/* eslint-disable no-restricted-imports */
3+
import {defineConfig} from '@playwright/test'
4+
import * as fs from 'fs'
5+
import * as path from 'path'
6+
import {fileURLToPath} from 'url'
7+
8+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
9+
10+
// Load .env file if present (CI provides env vars directly)
11+
const envPath = path.join(__dirname, '.env')
12+
if (fs.existsSync(envPath)) {
13+
for (const line of fs.readFileSync(envPath, 'utf-8').split('\n')) {
14+
const trimmed = line.trim()
15+
if (!trimmed || trimmed.startsWith('#')) continue
16+
const eqIdx = trimmed.indexOf('=')
17+
if (eqIdx === -1) continue
18+
const key = trimmed.slice(0, eqIdx).trim()
19+
const value = trimmed.slice(eqIdx + 1).trim()
20+
process.env[key] ??= value
21+
}
22+
}
23+
24+
const isCI = Boolean(process.env.CI)
25+
26+
export default defineConfig({
27+
testDir: './tests',
28+
fullyParallel: false,
29+
forbidOnly: isCI,
30+
retries: 0,
31+
workers: 1,
32+
maxFailures: isCI ? 3 : 0, // Stop early in CI after 3 failures
33+
reporter: isCI ? [['html', {open: 'never'}], ['list']] : [['list']],
34+
timeout: 3 * 60 * 1000, // 3 minutes per test
35+
globalTimeout: 15 * 60 * 1000, // 15 minutes total
36+
37+
use: {
38+
trace: isCI ? 'on' : 'off',
39+
screenshot: isCI ? 'on' : 'off',
40+
video: 'off',
41+
},
42+
})

packages/e2e/project.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "e2e",
3+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "packages/e2e",
5+
"projectType": "library",
6+
"implicitDependencies": ["cli", "create-app"],
7+
"tags": ["scope:e2e"],
8+
"targets": {
9+
"test": {
10+
"executor": "nx:run-commands",
11+
"dependsOn": ["^build"],
12+
"options": {
13+
"command": "pnpm playwright test",
14+
"cwd": "packages/e2e"
15+
}
16+
},
17+
"lint": {
18+
"executor": "nx:run-commands",
19+
"options": {
20+
"command": "pnpm eslint \"**/*.ts\"",
21+
"cwd": "packages/e2e"
22+
}
23+
},
24+
"lint:fix": {
25+
"executor": "nx:run-commands",
26+
"options": {
27+
"command": "pnpm eslint '**/*.ts' --fix",
28+
"cwd": "packages/e2e"
29+
}
30+
},
31+
"type-check": {
32+
"executor": "nx:run-commands",
33+
"options": {
34+
"command": "pnpm tsc --noEmit",
35+
"cwd": "packages/e2e"
36+
}
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)