Skip to content

Commit 07eee8f

Browse files
committed
E2E: migrate tests to use new infra
1 parent 019cbfd commit 07eee8f

File tree

13 files changed

+331
-380
lines changed

13 files changed

+331
-380
lines changed

.github/workflows/tests-pr.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,9 @@ jobs:
241241
- name: Run E2E tests
242242
working-directory: packages/e2e
243243
env:
244-
SHOPIFY_FLAG_CLIENT_ID: ${{ secrets.E2E_CLIENT_ID }}
245244
E2E_ACCOUNT_EMAIL: ${{ secrets.E2E_ACCOUNT_EMAIL }}
246245
E2E_ACCOUNT_PASSWORD: ${{ secrets.E2E_ACCOUNT_PASSWORD }}
247246
E2E_STORE_FQDN: ${{ secrets.E2E_STORE_FQDN }}
248-
E2E_SECONDARY_CLIENT_ID: ${{ secrets.E2E_SECONDARY_CLIENT_ID }}
249247
E2E_ORG_ID: ${{ secrets.E2E_ORG_ID }}
250248
run: npx playwright test
251249
- name: Upload Playwright report
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Invalid TOML: malformed syntax (missing closing quote)
2-
client_id = "__E2E_CLIENT_ID__"
2+
client_id = "1234567890"
33
name = "Bad Syntax App
44
application_url = "https://example.com"
55
embedded = true

packages/e2e/data/invalid-tomls/invalid-webhook.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Invalid TOML: bad webhook config (missing required uri)
2-
client_id = "__E2E_CLIENT_ID__"
2+
client_id = "1234567890"
33
name = "Invalid Webhook App"
44
application_url = "https://example.com"
55
embedded = true

packages/e2e/data/invalid-tomls/wrong-type.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Invalid TOML: wrong types for known fields
2-
client_id = "__E2E_CLIENT_ID__"
2+
client_id = "1234567890"
33
name = "Wrong Type App"
44
application_url = "https://example.com"
55
embedded = "not-a-boolean"

packages/e2e/data/valid-app/shopify.app.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Comprehensive shopify.app.toml for E2E regression testing
2-
# client_id is injected at runtime by the toml-app fixture
3-
client_id = "__E2E_CLIENT_ID__"
4-
name = "E2E TOML Regression Test"
2+
# client_id is injected at runtime via injectFixtureToml()
3+
client_id = "__CLIENT_ID__"
4+
name = "__NAME__"
55
application_url = "https://example.com"
66
embedded = true
77

packages/e2e/playwright.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default defineConfig({
1515
maxFailures: isCI ? 3 : 0, // Stop early in CI after 3 failures
1616
reporter: isCI ? [['html', {open: 'never'}], ['list']] : [['list']],
1717
timeout: 3 * 60 * 1000, // 3 minutes per test
18-
globalTimeout: 15 * 60 * 1000, // 15 minutes total
18+
globalTimeout: 30 * 60 * 1000, // 30 minutes total
1919

2020
use: {
2121
trace: isCI ? 'on' : 'off',

packages/e2e/setup/app.ts

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ import * as fs from 'fs'
66
import type {CLIContext, CLIProcess, ExecResult} from './cli.js'
77
import type {BrowserContext} from './browser.js'
88

9-
// Env override applied to all CLI helpers — strips CLIENT_ID so commands use the app's own toml.
10-
// NOTE: Do NOT add SHOPIFY_CLI_PARTNERS_TOKEN here. The partners token overrides OAuth in the
11-
// CLI's auth priority, and the App Management API token it exchanges to lacks permissions to
12-
// create apps (403). OAuth provides the full set of required permissions.
13-
const FRESH_APP_ENV = {SHOPIFY_FLAG_CLIENT_ID: undefined}
14-
159
// ---------------------------------------------------------------------------
1610
// CLI helpers — thin wrappers around cli.exec()
1711
// ---------------------------------------------------------------------------
@@ -45,8 +39,8 @@ export async function createApp(ctx: {
4539
if (ctx.flavor) args.push('--flavor', ctx.flavor)
4640

4741
const result = await cli.execCreateApp(args, {
48-
// Strip CLIENT_ID so the CLI creates a new app instead of linking to a pre-existing one
49-
env: {FORCE_COLOR: '0', ...FRESH_APP_ENV},
42+
// Disable color output and strip CLIENT_ID to prevent leaking from parent process.env
43+
env: {FORCE_COLOR: '0', SHOPIFY_FLAG_CLIENT_ID: undefined},
5044
timeout: 5 * 60 * 1000,
5145
})
5246

@@ -81,6 +75,33 @@ export async function createApp(ctx: {
8175
return {...result, appDir}
8276
}
8377

78+
// ---------------------------------------------------------------------------
79+
// Fixture helpers — TOML manipulation for test setup
80+
// ---------------------------------------------------------------------------
81+
82+
/**
83+
* Read the client_id from a shopify.app.toml file.
84+
*/
85+
export function extractClientId(appDir: string): string {
86+
const toml = fs.readFileSync(path.join(appDir, 'shopify.app.toml'), 'utf8')
87+
const match = toml.match(/client_id\s*=\s*"([^"]+)"/)
88+
if (!match?.[1]) {
89+
throw new Error(`Could not find client_id in ${path.join(appDir, 'shopify.app.toml')}`)
90+
}
91+
return match[1]
92+
}
93+
94+
/**
95+
* Overwrite a created app's shopify.app.toml with a fixture TOML template.
96+
* The template should contain `__CLIENT_ID__` and `__NAME__` placeholders which get
97+
* replaced with the app's real client_id and the provided name.
98+
*/
99+
export function injectFixtureToml(appDir: string, fixtureTomlContent: string, name: string): void {
100+
const clientId = extractClientId(appDir)
101+
const toml = fixtureTomlContent.replace(/__CLIENT_ID__/g, clientId).replace(/__NAME__/g, name)
102+
fs.writeFileSync(path.join(appDir, 'shopify.app.toml'), toml)
103+
}
104+
84105
export async function generateExtension(
85106
ctx: CLIContext & {
86107
name: string
@@ -90,11 +111,11 @@ export async function generateExtension(
90111
): Promise<ExecResult> {
91112
const args = ['app', 'generate', 'extension', '--name', ctx.name, '--path', ctx.appDir, '--template', ctx.template]
92113
if (ctx.flavor) args.push('--flavor', ctx.flavor)
93-
return ctx.cli.exec(args, {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
114+
return ctx.cli.exec(args, {timeout: 5 * 60 * 1000})
94115
}
95116

96117
export async function buildApp(ctx: CLIContext): Promise<ExecResult> {
97-
return ctx.cli.exec(['app', 'build', '--path', ctx.appDir], {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
118+
return ctx.cli.exec(['app', 'build', '--path', ctx.appDir], {timeout: 5 * 60 * 1000})
98119
}
99120

100121
export async function deployApp(
@@ -112,7 +133,7 @@ export async function deployApp(
112133
if (ctx.version) args.push('--version', ctx.version)
113134
if (ctx.message) args.push('--message', ctx.message)
114135
if (ctx.config) args.push('--config', ctx.config)
115-
return ctx.cli.exec(args, {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
136+
return ctx.cli.exec(args, {timeout: 5 * 60 * 1000})
116137
}
117138

118139
export async function appInfo(ctx: CLIContext): Promise<{
@@ -124,15 +145,15 @@ export async function appInfo(ctx: CLIContext): Promise<{
124145
entrySourceFilePath: string
125146
}[]
126147
}> {
127-
const result = await ctx.cli.exec(['app', 'info', '--path', ctx.appDir, '--json'], {env: FRESH_APP_ENV})
148+
const result = await ctx.cli.exec(['app', 'info', '--path', ctx.appDir, '--json'])
128149
if (result.exitCode !== 0) {
129150
throw new Error(`app info failed (exit ${result.exitCode}):\nstdout: ${result.stdout}\nstderr: ${result.stderr}`)
130151
}
131152
return JSON.parse(result.stdout)
132153
}
133154

134155
export async function functionBuild(ctx: CLIContext): Promise<ExecResult> {
135-
return ctx.cli.exec(['app', 'function', 'build', '--path', ctx.appDir], {env: FRESH_APP_ENV, timeout: 3 * 60 * 1000})
156+
return ctx.cli.exec(['app', 'function', 'build', '--path', ctx.appDir], {timeout: 3 * 60 * 1000})
136157
}
137158

138159
export async function functionRun(
@@ -141,14 +162,12 @@ export async function functionRun(
141162
},
142163
): Promise<ExecResult> {
143164
return ctx.cli.exec(['app', 'function', 'run', '--path', ctx.appDir, '--input', ctx.inputPath], {
144-
env: FRESH_APP_ENV,
145165
timeout: 60 * 1000,
146166
})
147167
}
148168

149169
export async function versionsList(ctx: CLIContext): Promise<ExecResult> {
150170
return ctx.cli.exec(['app', 'versions', 'list', '--path', ctx.appDir, '--json'], {
151-
env: FRESH_APP_ENV,
152171
timeout: 60 * 1000,
153172
})
154173
}
@@ -159,7 +178,6 @@ export async function configLink(
159178
},
160179
): Promise<ExecResult> {
161180
return ctx.cli.exec(['app', 'config', 'link', '--path', ctx.appDir, '--client-id', ctx.clientId], {
162-
env: FRESH_APP_ENV,
163181
timeout: 2 * 60 * 1000,
164182
})
165183
}
@@ -374,13 +392,9 @@ export async function cleanupApp(
374392
// ---------------------------------------------------------------------------
375393

376394
export const appTestFixture = authFixture.extend<{authReady: void}>({
377-
// Auto-trigger authLogin and strip CLIENT_ID so tests create their own apps
395+
// Auto-trigger authLogin so the OAuth session is available for all app tests
378396
authReady: [
379-
async (
380-
{authLogin: _authLogin, env}: {authLogin: void; env: import('./env.js').E2EEnv},
381-
use: () => Promise<void>,
382-
) => {
383-
delete env.processEnv.SHOPIFY_FLAG_CLIENT_ID
397+
async ({authLogin: _authLogin}: {authLogin: void}, use: () => Promise<void>) => {
384398
await use()
385399
},
386400
{auto: true},

packages/e2e/setup/env.ts

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,8 @@ const __filename = fileURLToPath(import.meta.url)
88
const __dirname = path.dirname(__filename)
99

1010
export interface E2EEnv {
11-
/** Partners token for API auth (empty string if not set) */
12-
partnersToken: string
13-
/** Primary test app client ID (empty string if not set) */
14-
clientId: string
1511
/** Dev store FQDN (e.g. cli-e2e-test.myshopify.com) */
1612
storeFqdn: string
17-
/** Secondary app client ID for config link tests */
18-
secondaryClientId: string
1913
/** Dedicated e2e org ID for fresh-app tests (empty string if not set) */
2014
orgId: string
2115
/** Environment variables to pass to CLI processes */
@@ -64,19 +58,13 @@ export function createIsolatedEnv(baseDir: string): {tempDir: string; xdgEnv: {[
6458

6559
/**
6660
* Asserts that a required environment variable is set.
67-
* Call this at the top of tests that need auth.
61+
* Call this at the top of tests that need specific env vars.
6862
*/
69-
export function requireEnv(
70-
env: E2EEnv,
71-
...keys: (keyof Pick<E2EEnv, 'partnersToken' | 'clientId' | 'storeFqdn' | 'secondaryClientId' | 'orgId'>)[]
72-
): void {
63+
export function requireEnv(env: E2EEnv, ...keys: (keyof Pick<E2EEnv, 'storeFqdn' | 'orgId'>)[]): void {
7364
for (const key of keys) {
7465
if (!env[key]) {
7566
const envVarNames: {[key: string]: string} = {
76-
partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN',
77-
clientId: 'SHOPIFY_FLAG_CLIENT_ID',
7867
storeFqdn: 'E2E_STORE_FQDN',
79-
secondaryClientId: 'E2E_SECONDARY_CLIENT_ID',
8068
orgId: 'E2E_ORG_ID',
8169
}
8270
throw new Error(`${envVarNames[key]} environment variable is required for this test`)
@@ -85,17 +73,14 @@ export function requireEnv(
8573
}
8674

8775
/**
88-
* Worker-scoped fixture providing auth tokens and environment configuration.
89-
* Auth tokens are optional — tests that need them should call requireEnv().
76+
* Worker-scoped fixture providing environment configuration.
77+
* Env vars are optional — tests that need them should call requireEnv().
9078
*/
9179
export const envFixture = base.extend<{}, {env: E2EEnv}>({
9280
env: [
9381
// eslint-disable-next-line no-empty-pattern
9482
async ({}, use) => {
95-
const partnersToken = process.env.SHOPIFY_CLI_PARTNERS_TOKEN ?? ''
96-
const clientId = process.env.SHOPIFY_FLAG_CLIENT_ID ?? ''
9783
const storeFqdn = process.env.E2E_STORE_FQDN ?? ''
98-
const secondaryClientId = process.env.E2E_SECONDARY_CLIENT_ID ?? ''
9984
const orgId = process.env.E2E_ORG_ID ?? ''
10085

10186
const tmpBase = process.env.E2E_TEMP_DIR ?? path.join(directories.root, '.e2e-tmp')
@@ -112,21 +97,12 @@ export const envFixture = base.extend<{}, {env: E2EEnv}>({
11297
SHOPIFY_CLI_1P_DEV: undefined,
11398
}
11499

115-
if (partnersToken) {
116-
processEnv.SHOPIFY_CLI_PARTNERS_TOKEN = partnersToken
117-
}
118-
if (clientId) {
119-
processEnv.SHOPIFY_FLAG_CLIENT_ID = clientId
120-
}
121100
if (storeFqdn) {
122101
processEnv.SHOPIFY_FLAG_STORE = storeFqdn
123102
}
124103

125104
const env: E2EEnv = {
126-
partnersToken,
127-
clientId,
128105
storeFqdn,
129-
secondaryClientId,
130106
orgId,
131107
processEnv,
132108
tempDir,

packages/e2e/setup/toml-app.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)