Skip to content

Commit e574bd4

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

12 files changed

Lines changed: 322 additions & 377 deletions

File tree

.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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
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__"
2+
# client_id is injected at runtime via injectFixtureToml()
3+
client_id = "__CLIENT_ID__"
44
name = "E2E TOML Regression Test"
55
application_url = "https://example.com"
66
embedded = true

packages/e2e/setup/app.ts

Lines changed: 29 additions & 21 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
// ---------------------------------------------------------------------------
@@ -46,7 +40,7 @@ export async function createApp(ctx: {
4640

4741
const result = await cli.execCreateApp(args, {
4842
// 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},
43+
env: {FORCE_COLOR: '0'},
5044
timeout: 5 * 60 * 1000,
5145
})
5246

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

78+
/**
79+
* Read the client_id from a shopify.app.toml file.
80+
*/
81+
export function extractClientId(appDir: string): string {
82+
const toml = fs.readFileSync(path.join(appDir, 'shopify.app.toml'), 'utf8')
83+
const match = toml.match(/client_id\s*=\s*"([^"]+)"/)
84+
if (!match?.[1]) {
85+
throw new Error(`Could not find client_id in ${path.join(appDir, 'shopify.app.toml')}`)
86+
}
87+
return match[1]
88+
}
89+
90+
/**
91+
* Overwrite a created app's shopify.app.toml with a fixture TOML template.
92+
* The template should contain `__CLIENT_ID__` which gets replaced with the app's real client_id.
93+
*/
94+
export function injectFixtureToml(appDir: string, fixtureTomlContent: string): void {
95+
const clientId = extractClientId(appDir)
96+
fs.writeFileSync(path.join(appDir, 'shopify.app.toml'), fixtureTomlContent.replace('__CLIENT_ID__', clientId))
97+
}
98+
8499
export async function generateExtension(
85100
ctx: CLIContext & {
86101
name: string
@@ -90,11 +105,11 @@ export async function generateExtension(
90105
): Promise<ExecResult> {
91106
const args = ['app', 'generate', 'extension', '--name', ctx.name, '--path', ctx.appDir, '--template', ctx.template]
92107
if (ctx.flavor) args.push('--flavor', ctx.flavor)
93-
return ctx.cli.exec(args, {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
108+
return ctx.cli.exec(args, {timeout: 5 * 60 * 1000})
94109
}
95110

96111
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})
112+
return ctx.cli.exec(['app', 'build', '--path', ctx.appDir], {timeout: 5 * 60 * 1000})
98113
}
99114

100115
export async function deployApp(
@@ -112,7 +127,7 @@ export async function deployApp(
112127
if (ctx.version) args.push('--version', ctx.version)
113128
if (ctx.message) args.push('--message', ctx.message)
114129
if (ctx.config) args.push('--config', ctx.config)
115-
return ctx.cli.exec(args, {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
130+
return ctx.cli.exec(args, {timeout: 5 * 60 * 1000})
116131
}
117132

118133
export async function appInfo(ctx: CLIContext): Promise<{
@@ -124,15 +139,15 @@ export async function appInfo(ctx: CLIContext): Promise<{
124139
entrySourceFilePath: string
125140
}[]
126141
}> {
127-
const result = await ctx.cli.exec(['app', 'info', '--path', ctx.appDir, '--json'], {env: FRESH_APP_ENV})
142+
const result = await ctx.cli.exec(['app', 'info', '--path', ctx.appDir, '--json'])
128143
if (result.exitCode !== 0) {
129144
throw new Error(`app info failed (exit ${result.exitCode}):\nstdout: ${result.stdout}\nstderr: ${result.stderr}`)
130145
}
131146
return JSON.parse(result.stdout)
132147
}
133148

134149
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})
150+
return ctx.cli.exec(['app', 'function', 'build', '--path', ctx.appDir], {timeout: 3 * 60 * 1000})
136151
}
137152

138153
export async function functionRun(
@@ -141,14 +156,12 @@ export async function functionRun(
141156
},
142157
): Promise<ExecResult> {
143158
return ctx.cli.exec(['app', 'function', 'run', '--path', ctx.appDir, '--input', ctx.inputPath], {
144-
env: FRESH_APP_ENV,
145159
timeout: 60 * 1000,
146160
})
147161
}
148162

149163
export async function versionsList(ctx: CLIContext): Promise<ExecResult> {
150164
return ctx.cli.exec(['app', 'versions', 'list', '--path', ctx.appDir, '--json'], {
151-
env: FRESH_APP_ENV,
152165
timeout: 60 * 1000,
153166
})
154167
}
@@ -159,7 +172,6 @@ export async function configLink(
159172
},
160173
): Promise<ExecResult> {
161174
return ctx.cli.exec(['app', 'config', 'link', '--path', ctx.appDir, '--client-id', ctx.clientId], {
162-
env: FRESH_APP_ENV,
163175
timeout: 2 * 60 * 1000,
164176
})
165177
}
@@ -374,13 +386,9 @@ export async function cleanupApp(
374386
// ---------------------------------------------------------------------------
375387

376388
export const appTestFixture = authFixture.extend<{authReady: void}>({
377-
// Auto-trigger authLogin and strip CLIENT_ID so tests create their own apps
389+
// Auto-trigger authLogin so the OAuth session is available for all app tests
378390
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
391+
async ({authLogin: _authLogin}: {authLogin: void}, use: () => Promise<void>) => {
384392
await use()
385393
},
386394
{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)