Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ packages/*/docs/

packaging/dist

# E2E test temp directories and artifacts
.e2e-tmp

# Shadowenv generates user-specific files that shouldn't be committed
.shadowenv.d/

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"post-release": "./bin/post-release",
"shopify:run": "node packages/cli/bin/dev.js",
"shopify": "nx build cli && node packages/cli/bin/dev.js",
"test:e2e": "nx run-many --target=build --projects=cli,create-app --skip-nx-cache && pnpm --filter e2e exec playwright test",
"test:features": "pnpm nx run features:test",
"test:regenerate-snapshots": "nx build cli && packages/features/snapshots/regenerate.sh",
"test:unit": "pnpm vitest run",
Expand Down Expand Up @@ -130,7 +131,8 @@
"@graphql-typed-document-node/core"
],
"ignoreWorkspaces": [
"packages/eslint-plugin-cli"
"packages/eslint-plugin-cli",
"packages/e2e"
],
"paths": {
"@shopify/eslint-plugin-cli/configs": [
Expand Down
19 changes: 19 additions & 0 deletions packages/e2e/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Required: Client ID of the primary test app (must be in the genghis account's org)
# CI secret: E2E_CLIENT_ID
SHOPIFY_FLAG_CLIENT_ID=
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For initial E2E tests, we won't create new apps but instead use existing ones. We should 100% evolve this, but we need a starting point to monitor and observe stability of this job.


# Required: Genghis account email for browser-based OAuth login
# CI secret: E2E_ACCOUNT_EMAIL
E2E_ACCOUNT_EMAIL=

# Required: Genghis account password for browser-based OAuth login
# CI secret: E2E_ACCOUNT_PASSWORD
E2E_ACCOUNT_PASSWORD=

# Required: Dev store FQDN for dev server / deploy tests (e.g. my-store.myshopify.com)
# CI secret: E2E_STORE_FQDN
E2E_STORE_FQDN=

# Optional: Client ID of a secondary app for config link tests
# CI secret: E2E_SECONDARY_CLIENT_ID
E2E_SECONDARY_CLIENT_ID=
6 changes: 6 additions & 0 deletions packages/e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
test-results/
playwright-report/
dist/
.env
.env.local
5 changes: 5 additions & 0 deletions packages/e2e/helpers/strip-ansi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Re-export strip-ansi as a named export for easier use.
// strip-ansi v7+ is ESM-only and exports a default function.
import stripAnsiModule from 'strip-ansi'

export const stripAnsi: (text: string) => string = stripAnsiModule
39 changes: 39 additions & 0 deletions packages/e2e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@shopify/e2e",
"version": "0.1.0",
"packageManager": "pnpm@10.11.1",
"private": true,
"type": "module",
"scripts": {
"test": "nx run e2e:test",
"lint": "nx lint",
"lint:fix": "nx lint:fix",
"type-check": "nx type-check"
},
"eslintConfig": {
"extends": [
"../../.eslintrc.cjs"
],
"rules": {
"no-console": "off",
"import/extensions": [
"error",
"never",
{
"ignorePackages": true
}
]
}
},
"devDependencies": {
"@playwright/test": "^1.50.0",
"@types/node": "18.19.70",
"execa": "^7.2.0",
"node-pty": "^1.0.0",
"strip-ansi": "^7.1.0",
"tempy": "^1.0.1"
},
"engines": {
"node": ">=20.10.0"
}
}
42 changes: 42 additions & 0 deletions packages/e2e/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable line-comment-position */
/* eslint-disable no-restricted-imports */
import {defineConfig} from '@playwright/test'
import * as fs from 'fs'
import * as path from 'path'
import {fileURLToPath} from 'url'

const __dirname = path.dirname(fileURLToPath(import.meta.url))

// Load .env file if present (CI provides env vars directly)
const envPath = path.join(__dirname, '.env')
if (fs.existsSync(envPath)) {
for (const line of fs.readFileSync(envPath, 'utf-8').split('\n')) {
const trimmed = line.trim()
if (!trimmed || trimmed.startsWith('#')) continue
const eqIdx = trimmed.indexOf('=')
if (eqIdx === -1) continue
const key = trimmed.slice(0, eqIdx).trim()
const value = trimmed.slice(eqIdx + 1).trim()
process.env[key] ??= value
}
}

const isCI = Boolean(process.env.CI)

export default defineConfig({
testDir: './tests',
fullyParallel: false,
forbidOnly: isCI,
retries: 0,
workers: 1,
maxFailures: isCI ? 3 : 0, // Stop early in CI after 3 failures
reporter: isCI ? [['html', {open: 'never'}], ['list']] : [['list']],
timeout: 3 * 60 * 1000, // 3 minutes per test
globalTimeout: 15 * 60 * 1000, // 15 minutes total

use: {
trace: isCI ? 'on' : 'off',
screenshot: isCI ? 'on' : 'off',
video: 'off',
},
})
39 changes: 39 additions & 0 deletions packages/e2e/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/e2e",
"projectType": "library",
"implicitDependencies": ["cli", "create-app"],
"tags": ["scope:e2e"],
"targets": {
"test": {
"executor": "nx:run-commands",
"dependsOn": ["^build"],
"options": {
"command": "pnpm playwright test",
"cwd": "packages/e2e"
}
},
"lint": {
"executor": "nx:run-commands",
"options": {
"command": "pnpm eslint \"**/*.ts\"",
"cwd": "packages/e2e"
}
},
"lint:fix": {
"executor": "nx:run-commands",
"options": {
"command": "pnpm eslint '**/*.ts' --fix",
"cwd": "packages/e2e"
}
},
"type-check": {
"executor": "nx:run-commands",
"options": {
"command": "pnpm tsc --noEmit",
"cwd": "packages/e2e"
}
}
}
}
Loading
Loading