Skip to content

Commit 8a98157

Browse files
committed
add toml regression tests
1 parent d0e302e commit 8a98157

10 files changed

Lines changed: 216 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Invalid TOML: malformed syntax (missing closing quote)
2+
client_id = "__E2E_CLIENT_ID__"
3+
name = "Bad Syntax App
4+
application_url = "https://example.com"
5+
embedded = true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Invalid TOML: app_proxy with invalid prefix value
2+
client_id = "__E2E_CLIENT_ID__"
3+
name = "Invalid Prefix App"
4+
application_url = "https://example.com"
5+
embedded = true
6+
7+
[app_proxy]
8+
url = "https://example.com/proxy"
9+
subpath = "test"
10+
prefix = "not-a-valid-prefix"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Invalid TOML: bad webhook config (missing required uri)
2+
client_id = "__E2E_CLIENT_ID__"
3+
name = "Invalid Webhook App"
4+
application_url = "https://example.com"
5+
embedded = true
6+
7+
[webhooks]
8+
api_version = "2025-01"
9+
10+
[[webhooks.subscriptions]]
11+
topics = ["products/create"]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Invalid TOML: unknown top-level section
2+
client_id = "__E2E_CLIENT_ID__"
3+
name = "Unknown Section App"
4+
application_url = "https://example.com"
5+
embedded = true
6+
7+
[completely_made_up_section]
8+
foo = "bar"
9+
baz = 123
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Invalid TOML: wrong types for known fields
2+
client_id = "__E2E_CLIENT_ID__"
3+
name = "Wrong Type App"
4+
application_url = "https://example.com"
5+
embedded = "not-a-boolean"
6+
7+
[access_scopes]
8+
scopes = 12345
9+
use_legacy_install_flow = "nope"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "e2e-toml-regression-test",
3+
"version": "1.0.0",
4+
"private": true
5+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# 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"
5+
application_url = "https://example.com"
6+
embedded = true
7+
8+
[access_scopes]
9+
scopes = "read_products,write_products,read_orders"
10+
use_legacy_install_flow = false
11+
12+
[access.admin]
13+
direct_api_mode = "online"
14+
embedded_app_direct_api_access = true
15+
16+
[auth]
17+
redirect_urls = [
18+
"https://example.com/auth/callback",
19+
"https://example.com/auth/shopify/callback",
20+
]
21+
22+
[webhooks]
23+
api_version = "2025-01"
24+
25+
[[webhooks.subscriptions]]
26+
topics = ["products/create"]
27+
uri = "https://example.com/webhooks/products/create"
28+
29+
[[webhooks.subscriptions]]
30+
topics = ["orders/create"]
31+
uri = "https://example.com/webhooks/orders/create"
32+
33+
[app_proxy]
34+
url = "https://example.com/proxy"
35+
subpath = "e2e-test"
36+
prefix = "apps"
37+
38+
[pos]
39+
embedded = false
40+
41+
[build]
42+
automatically_update_urls_on_dev = true
43+
include_config_on_deploy = true
44+
45+
[app_preferences]
46+
url = "https://example.com/preferences"

packages/e2e/setup/toml-app.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* eslint-disable no-restricted-imports */
2+
import {authFixture} from './auth.js'
3+
import * as path from 'path'
4+
import * as fs from 'fs'
5+
import {fileURLToPath} from 'url'
6+
7+
const __filename = fileURLToPath(import.meta.url)
8+
const __dirname = path.dirname(__filename)
9+
10+
const FIXTURE_DIR = path.join(__dirname, '../data/valid-app')
11+
12+
/**
13+
* Test fixture that copies the full-toml fixture into a temp directory,
14+
* injects the real client_id, and exposes the path to tests.
15+
*/
16+
export const tomlAppFixture = authFixture.extend<{tomlAppDir: string}>({
17+
tomlAppDir: async ({env, authLogin: _authLogin}, use) => {
18+
const appDir = fs.mkdtempSync(path.join(env.tempDir, 'toml-app-'))
19+
20+
// Copy fixture files
21+
for (const file of fs.readdirSync(FIXTURE_DIR)) {
22+
fs.copyFileSync(path.join(FIXTURE_DIR, file), path.join(appDir, file))
23+
}
24+
25+
// Inject real client_id
26+
const tomlPath = path.join(appDir, 'shopify.app.toml')
27+
const toml = fs.readFileSync(tomlPath, 'utf8')
28+
fs.writeFileSync(tomlPath, toml.replace('__E2E_CLIENT_ID__', env.clientId))
29+
30+
await use(appDir)
31+
32+
fs.rmSync(appDir, {recursive: true, force: true})
33+
},
34+
})
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* eslint-disable no-console */
2+
/* eslint-disable no-restricted-imports */
3+
import {authFixture as test} from '../setup/auth.js'
4+
import {requireEnv} from '../setup/env.js'
5+
import {expect} from '@playwright/test'
6+
import * as path from 'path'
7+
import * as fs from 'fs'
8+
import {fileURLToPath} from 'url'
9+
10+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
11+
const INVALID_TOMLS_DIR = path.join(__dirname, '../data/invalid-tomls')
12+
13+
const invalidTomls = fs.readdirSync(INVALID_TOMLS_DIR).filter((file) => file.endsWith('.toml'))
14+
15+
test.describe('TOML config invalid', () => {
16+
for (const tomlFile of invalidTomls) {
17+
const label = tomlFile.replace('.toml', '')
18+
19+
test(`deploy rejects invalid toml: ${label}`, async ({cli, env}) => {
20+
requireEnv(env, 'clientId')
21+
22+
// Set up temp dir with invalid toml + minimal package.json
23+
const appDir = fs.mkdtempSync(path.join(env.tempDir, `invalid-toml-${label}-`))
24+
try {
25+
const toml = fs
26+
.readFileSync(path.join(INVALID_TOMLS_DIR, tomlFile), 'utf8')
27+
.replace('__E2E_CLIENT_ID__', env.clientId)
28+
fs.writeFileSync(path.join(appDir, 'shopify.app.toml'), toml)
29+
fs.writeFileSync(
30+
path.join(appDir, 'package.json'),
31+
JSON.stringify({name: `invalid-${label}`, version: '1.0.0', private: true}),
32+
)
33+
34+
const result = await cli.exec(['app', 'deploy', '--path', appDir, '--force'], {
35+
timeout: 2 * 60 * 1000,
36+
})
37+
const output = result.stdout + result.stderr
38+
console.log(`[${label}] exit code: ${result.exitCode}\n[${label}] output:\n${output}`)
39+
expect(result.exitCode, `expected deploy to fail for ${label}, but it succeeded:\n${output}`).not.toBe(0)
40+
} finally {
41+
fs.rmSync(appDir, {recursive: true, force: true})
42+
}
43+
})
44+
}
45+
})
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* eslint-disable no-console */
2+
import {tomlAppFixture as test} from '../setup/toml-app.js'
3+
import {requireEnv} from '../setup/env.js'
4+
import {expect} from '@playwright/test'
5+
6+
test.describe('TOML config regression', () => {
7+
test('deploy succeeds with fully populated toml', async ({cli, env, tomlAppDir}) => {
8+
requireEnv(env, 'clientId')
9+
10+
const result = await cli.exec(['app', 'deploy', '--path', tomlAppDir, '--force'], {
11+
timeout: 5 * 60 * 1000,
12+
})
13+
const output = result.stdout + result.stderr
14+
expect(result.exitCode, `deploy failed:\n${output}`).toBe(0)
15+
})
16+
17+
test('dev starts with fully populated toml', async ({cli, env, tomlAppDir}) => {
18+
test.setTimeout(5 * 60 * 1000)
19+
requireEnv(env, 'clientId', 'storeFqdn')
20+
21+
const proc = await cli.spawn(['app', 'dev', '--path', tomlAppDir], {
22+
env: {CI: ''},
23+
})
24+
25+
try {
26+
await proc.waitForOutput('Ready, watching for changes in your app', 3 * 60 * 1000)
27+
28+
const output = proc.getOutput()
29+
expect(output).toContain('q')
30+
31+
proc.sendKey('q')
32+
const exitCode = await proc.waitForExit(30_000)
33+
expect(exitCode, `dev exited with non-zero code. Output:\n${proc.getOutput()}`).toBe(0)
34+
} catch (error) {
35+
const captured = proc.getOutput()
36+
console.error(`[toml-config dev] Captured PTY output:\n${captured}`)
37+
throw error
38+
} finally {
39+
proc.kill()
40+
}
41+
})
42+
})

0 commit comments

Comments
 (0)