Skip to content

Commit e55998a

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

12 files changed

Lines changed: 325 additions & 378 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: 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/setup/app.ts

Lines changed: 31 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,29 @@ 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__` and `__NAME__` placeholders which get
93+
* replaced with the app's real client_id and the provided name.
94+
*/
95+
export function injectFixtureToml(appDir: string, fixtureTomlContent: string, name: string): void {
96+
const clientId = extractClientId(appDir)
97+
const toml = fixtureTomlContent.replace('__CLIENT_ID__', clientId).replace('__NAME__', name)
98+
fs.writeFileSync(path.join(appDir, 'shopify.app.toml'), toml)
99+
}
100+
84101
export async function generateExtension(
85102
ctx: CLIContext & {
86103
name: string
@@ -90,11 +107,11 @@ export async function generateExtension(
90107
): Promise<ExecResult> {
91108
const args = ['app', 'generate', 'extension', '--name', ctx.name, '--path', ctx.appDir, '--template', ctx.template]
92109
if (ctx.flavor) args.push('--flavor', ctx.flavor)
93-
return ctx.cli.exec(args, {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
110+
return ctx.cli.exec(args, {timeout: 5 * 60 * 1000})
94111
}
95112

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

100117
export async function deployApp(
@@ -112,7 +129,7 @@ export async function deployApp(
112129
if (ctx.version) args.push('--version', ctx.version)
113130
if (ctx.message) args.push('--message', ctx.message)
114131
if (ctx.config) args.push('--config', ctx.config)
115-
return ctx.cli.exec(args, {env: FRESH_APP_ENV, timeout: 5 * 60 * 1000})
132+
return ctx.cli.exec(args, {timeout: 5 * 60 * 1000})
116133
}
117134

118135
export async function appInfo(ctx: CLIContext): Promise<{
@@ -124,15 +141,15 @@ export async function appInfo(ctx: CLIContext): Promise<{
124141
entrySourceFilePath: string
125142
}[]
126143
}> {
127-
const result = await ctx.cli.exec(['app', 'info', '--path', ctx.appDir, '--json'], {env: FRESH_APP_ENV})
144+
const result = await ctx.cli.exec(['app', 'info', '--path', ctx.appDir, '--json'])
128145
if (result.exitCode !== 0) {
129146
throw new Error(`app info failed (exit ${result.exitCode}):\nstdout: ${result.stdout}\nstderr: ${result.stderr}`)
130147
}
131148
return JSON.parse(result.stdout)
132149
}
133150

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

138155
export async function functionRun(
@@ -141,14 +158,12 @@ export async function functionRun(
141158
},
142159
): Promise<ExecResult> {
143160
return ctx.cli.exec(['app', 'function', 'run', '--path', ctx.appDir, '--input', ctx.inputPath], {
144-
env: FRESH_APP_ENV,
145161
timeout: 60 * 1000,
146162
})
147163
}
148164

149165
export async function versionsList(ctx: CLIContext): Promise<ExecResult> {
150166
return ctx.cli.exec(['app', 'versions', 'list', '--path', ctx.appDir, '--json'], {
151-
env: FRESH_APP_ENV,
152167
timeout: 60 * 1000,
153168
})
154169
}
@@ -159,7 +174,6 @@ export async function configLink(
159174
},
160175
): Promise<ExecResult> {
161176
return ctx.cli.exec(['app', 'config', 'link', '--path', ctx.appDir, '--client-id', ctx.clientId], {
162-
env: FRESH_APP_ENV,
163177
timeout: 2 * 60 * 1000,
164178
})
165179
}
@@ -374,13 +388,9 @@ export async function cleanupApp(
374388
// ---------------------------------------------------------------------------
375389

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