@essential-apps/shopify-test-runner 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contracts/normalize.d.ts +61 -0
- package/dist/contracts/normalize.d.ts.map +1 -0
- package/dist/contracts/normalize.js +99 -0
- package/dist/contracts/normalize.js.map +1 -0
- package/dist/contracts/normalizeHtml.d.ts +37 -0
- package/dist/contracts/normalizeHtml.d.ts.map +1 -0
- package/dist/contracts/normalizeHtml.js +89 -0
- package/dist/contracts/normalizeHtml.js.map +1 -0
- package/dist/edge/cert.d.ts +44 -0
- package/dist/edge/cert.d.ts.map +1 -0
- package/dist/edge/cert.js +117 -0
- package/dist/edge/cert.js.map +1 -0
- package/dist/edge/edgeProxy.d.ts +43 -0
- package/dist/edge/edgeProxy.d.ts.map +1 -0
- package/dist/edge/edgeProxy.js +297 -0
- package/dist/edge/edgeProxy.js.map +1 -0
- package/dist/edge/nodeShim.d.ts +2 -0
- package/dist/edge/nodeShim.d.ts.map +1 -0
- package/dist/edge/nodeShim.js +217 -0
- package/dist/edge/nodeShim.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/buildSourceBundle.d.ts +56 -0
- package/dist/lib/buildSourceBundle.d.ts.map +1 -0
- package/dist/lib/buildSourceBundle.js +153 -0
- package/dist/lib/buildSourceBundle.js.map +1 -0
- package/dist/lib/freePort.d.ts +5 -0
- package/dist/lib/freePort.d.ts.map +1 -0
- package/dist/lib/freePort.js +33 -0
- package/dist/lib/freePort.js.map +1 -0
- package/dist/lib/functionBuild.d.ts +99 -0
- package/dist/lib/functionBuild.d.ts.map +1 -0
- package/dist/lib/functionBuild.js +413 -0
- package/dist/lib/functionBuild.js.map +1 -0
- package/dist/lib/neonWsProxy.d.ts +41 -0
- package/dist/lib/neonWsProxy.d.ts.map +1 -0
- package/dist/lib/neonWsProxy.js +101 -0
- package/dist/lib/neonWsProxy.js.map +1 -0
- package/dist/lib/sourceZipUpload.d.ts +45 -0
- package/dist/lib/sourceZipUpload.d.ts.map +1 -0
- package/dist/lib/sourceZipUpload.js +129 -0
- package/dist/lib/sourceZipUpload.js.map +1 -0
- package/dist/lib/stealthLaunch.d.ts +35 -0
- package/dist/lib/stealthLaunch.d.ts.map +1 -0
- package/dist/lib/stealthLaunch.js +46 -0
- package/dist/lib/stealthLaunch.js.map +1 -0
- package/dist/lib/storeAutomation.d.ts +22 -0
- package/dist/lib/storeAutomation.d.ts.map +1 -0
- package/dist/lib/storeAutomation.js +85 -0
- package/dist/lib/storeAutomation.js.map +1 -0
- package/dist/playwright/baseConfig.d.ts +62 -0
- package/dist/playwright/baseConfig.d.ts.map +1 -0
- package/dist/playwright/baseConfig.js +68 -0
- package/dist/playwright/baseConfig.js.map +1 -0
- package/dist/playwright/globalSetup.d.ts +2 -0
- package/dist/playwright/globalSetup.d.ts.map +1 -0
- package/dist/playwright/globalSetup.js +139 -0
- package/dist/playwright/globalSetup.js.map +1 -0
- package/dist/playwright/index.d.ts +9 -0
- package/dist/playwright/index.d.ts.map +1 -0
- package/dist/playwright/index.js +9 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/probes/fonts.d.ts +4 -0
- package/dist/probes/fonts.d.ts.map +1 -0
- package/dist/probes/fonts.js +255 -0
- package/dist/probes/fonts.js.map +1 -0
- package/dist/probes/mirror.d.ts +4 -0
- package/dist/probes/mirror.d.ts.map +1 -0
- package/dist/probes/mirror.js +260 -0
- package/dist/probes/mirror.js.map +1 -0
- package/dist/probes/runProbe.d.ts +3 -0
- package/dist/probes/runProbe.d.ts.map +1 -0
- package/dist/probes/runProbe.js +219 -0
- package/dist/probes/runProbe.js.map +1 -0
- package/dist/probes/types.d.ts +72 -0
- package/dist/probes/types.d.ts.map +1 -0
- package/dist/probes/types.js +2 -0
- package/dist/probes/types.js.map +1 -0
- package/dist/scripts/_probeSourceUrl.d.ts +3 -0
- package/dist/scripts/_probeSourceUrl.d.ts.map +1 -0
- package/dist/scripts/_probeSourceUrl.js +119 -0
- package/dist/scripts/_probeSourceUrl.js.map +1 -0
- package/dist/scripts/addStore.d.ts +3 -0
- package/dist/scripts/addStore.d.ts.map +1 -0
- package/dist/scripts/addStore.js +46 -0
- package/dist/scripts/addStore.js.map +1 -0
- package/dist/scripts/buildDockerImage.d.ts +3 -0
- package/dist/scripts/buildDockerImage.d.ts.map +1 -0
- package/dist/scripts/buildDockerImage.js +60 -0
- package/dist/scripts/buildDockerImage.js.map +1 -0
- package/dist/scripts/captureAuth.d.ts +3 -0
- package/dist/scripts/captureAuth.d.ts.map +1 -0
- package/dist/scripts/captureAuth.js +124 -0
- package/dist/scripts/captureAuth.js.map +1 -0
- package/dist/scripts/captureContracts.d.ts +3 -0
- package/dist/scripts/captureContracts.d.ts.map +1 -0
- package/dist/scripts/captureContracts.js +517 -0
- package/dist/scripts/captureContracts.js.map +1 -0
- package/dist/scripts/captureRestContracts.d.ts +3 -0
- package/dist/scripts/captureRestContracts.d.ts.map +1 -0
- package/dist/scripts/captureRestContracts.js +245 -0
- package/dist/scripts/captureRestContracts.js.map +1 -0
- package/dist/scripts/checkOperationCoverage.d.ts +3 -0
- package/dist/scripts/checkOperationCoverage.d.ts.map +1 -0
- package/dist/scripts/checkOperationCoverage.js +302 -0
- package/dist/scripts/checkOperationCoverage.js.map +1 -0
- package/dist/scripts/cleanupStores.d.ts +3 -0
- package/dist/scripts/cleanupStores.d.ts.map +1 -0
- package/dist/scripts/cleanupStores.js +77 -0
- package/dist/scripts/cleanupStores.js.map +1 -0
- package/dist/scripts/createStores.d.ts +3 -0
- package/dist/scripts/createStores.d.ts.map +1 -0
- package/dist/scripts/createStores.js +66 -0
- package/dist/scripts/createStores.js.map +1 -0
- package/dist/scripts/deployAppVersion.d.ts +3 -0
- package/dist/scripts/deployAppVersion.d.ts.map +1 -0
- package/dist/scripts/deployAppVersion.js +591 -0
- package/dist/scripts/deployAppVersion.js.map +1 -0
- package/dist/scripts/devE2eBackend.d.ts +3 -0
- package/dist/scripts/devE2eBackend.d.ts.map +1 -0
- package/dist/scripts/devE2eBackend.js +117 -0
- package/dist/scripts/devE2eBackend.js.map +1 -0
- package/dist/scripts/devOnlineBackend.d.ts +3 -0
- package/dist/scripts/devOnlineBackend.d.ts.map +1 -0
- package/dist/scripts/devOnlineBackend.js +117 -0
- package/dist/scripts/devOnlineBackend.js.map +1 -0
- package/dist/scripts/installApp.d.ts +3 -0
- package/dist/scripts/installApp.d.ts.map +1 -0
- package/dist/scripts/installApp.js +163 -0
- package/dist/scripts/installApp.js.map +1 -0
- package/dist/scripts/listStores.d.ts +3 -0
- package/dist/scripts/listStores.d.ts.map +1 -0
- package/dist/scripts/listStores.js +18 -0
- package/dist/scripts/listStores.js.map +1 -0
- package/dist/scripts/runDocker.d.ts +3 -0
- package/dist/scripts/runDocker.d.ts.map +1 -0
- package/dist/scripts/runDocker.js +88 -0
- package/dist/scripts/runDocker.js.map +1 -0
- package/dist/scripts/runDockerAuth.d.ts +3 -0
- package/dist/scripts/runDockerAuth.d.ts.map +1 -0
- package/dist/scripts/runDockerAuth.js +108 -0
- package/dist/scripts/runDockerAuth.js.map +1 -0
- package/dist/scripts/runDockerOffline.d.ts +3 -0
- package/dist/scripts/runDockerOffline.d.ts.map +1 -0
- package/dist/scripts/runDockerOffline.js +129 -0
- package/dist/scripts/runDockerOffline.js.map +1 -0
- package/dist/scripts/runDockerOfflineExplore.d.ts +3 -0
- package/dist/scripts/runDockerOfflineExplore.d.ts.map +1 -0
- package/dist/scripts/runDockerOfflineExplore.js +116 -0
- package/dist/scripts/runDockerOfflineExplore.js.map +1 -0
- package/dist/scripts/runIsolatedDockerOffline.d.ts +3 -0
- package/dist/scripts/runIsolatedDockerOffline.d.ts.map +1 -0
- package/dist/scripts/runIsolatedDockerOffline.js +351 -0
- package/dist/scripts/runIsolatedDockerOffline.js.map +1 -0
- package/dist/scripts/runOffline.d.ts +3 -0
- package/dist/scripts/runOffline.d.ts.map +1 -0
- package/dist/scripts/runOffline.js +521 -0
- package/dist/scripts/runOffline.js.map +1 -0
- package/dist/scripts/runOfflineE2e.d.ts +3 -0
- package/dist/scripts/runOfflineE2e.d.ts.map +1 -0
- package/dist/scripts/runOfflineE2e.js +408 -0
- package/dist/scripts/runOfflineE2e.js.map +1 -0
- package/dist/scripts/runOfflineFullTests.d.ts +3 -0
- package/dist/scripts/runOfflineFullTests.d.ts.map +1 -0
- package/dist/scripts/runOfflineFullTests.js +1456 -0
- package/dist/scripts/runOfflineFullTests.js.map +1 -0
- package/dist/scripts/runSupermachine.d.ts +3 -0
- package/dist/scripts/runSupermachine.d.ts.map +1 -0
- package/dist/scripts/runSupermachine.js +474 -0
- package/dist/scripts/runSupermachine.js.map +1 -0
- package/dist/scripts/runSupermachineAuth.d.ts +3 -0
- package/dist/scripts/runSupermachineAuth.d.ts.map +1 -0
- package/dist/scripts/runSupermachineAuth.js +454 -0
- package/dist/scripts/runSupermachineAuth.js.map +1 -0
- package/dist/scripts/runTests.d.ts +3 -0
- package/dist/scripts/runTests.d.ts.map +1 -0
- package/dist/scripts/runTests.js +278 -0
- package/dist/scripts/runTests.js.map +1 -0
- package/dist/scripts/runVm.d.ts +3 -0
- package/dist/scripts/runVm.d.ts.map +1 -0
- package/dist/scripts/runVm.js +524 -0
- package/dist/scripts/runVm.js.map +1 -0
- package/dist/scripts/runVmAuth.d.ts +3 -0
- package/dist/scripts/runVmAuth.d.ts.map +1 -0
- package/dist/scripts/runVmAuth.js +475 -0
- package/dist/scripts/runVmAuth.js.map +1 -0
- package/dist/scripts/runVmScript.d.ts +3 -0
- package/dist/scripts/runVmScript.d.ts.map +1 -0
- package/dist/scripts/runVmScript.js +242 -0
- package/dist/scripts/runVmScript.js.map +1 -0
- package/dist/scripts/setupTestDb.d.ts +3 -0
- package/dist/scripts/setupTestDb.d.ts.map +1 -0
- package/dist/scripts/setupTestDb.js +61 -0
- package/dist/scripts/setupTestDb.js.map +1 -0
- package/dist/scripts/verifyContracts.d.ts +3 -0
- package/dist/scripts/verifyContracts.d.ts.map +1 -0
- package/dist/scripts/verifyContracts.js +258 -0
- package/dist/scripts/verifyContracts.js.map +1 -0
- package/dist/scripts/verifyRestContracts.d.ts +3 -0
- package/dist/scripts/verifyRestContracts.d.ts.map +1 -0
- package/dist/scripts/verifyRestContracts.js +237 -0
- package/dist/scripts/verifyRestContracts.js.map +1 -0
- package/dist/vite/offlineConfig.d.ts +34 -0
- package/dist/vite/offlineConfig.d.ts.map +1 -0
- package/dist/vite/offlineConfig.js +61 -0
- package/dist/vite/offlineConfig.js.map +1 -0
- package/dist/vite/onlineConfig.d.ts +42 -0
- package/dist/vite/onlineConfig.d.ts.map +1 -0
- package/dist/vite/onlineConfig.js +56 -0
- package/dist/vite/onlineConfig.js.map +1 -0
- package/docker/Dockerfile +67 -0
- package/docker/Dockerfile.vm +137 -0
- package/docker/README.md +50 -0
- package/docker/entrypoint.sh +198 -0
- package/package.json +85 -0
- package/src/contracts/normalize.ts +96 -0
- package/src/contracts/normalizeHtml.ts +98 -0
- package/src/edge/ca.cnf +14 -0
- package/src/edge/ca.crt +22 -0
- package/src/edge/ca.key +28 -0
- package/src/edge/cert.ts +117 -0
- package/src/edge/edgeProxy.ts +390 -0
- package/src/edge/server.cnf +28 -0
- package/src/edge/server.crt +26 -0
- package/src/edge/server.key +28 -0
- package/src/index.ts +67 -0
- package/src/lib/buildSourceBundle.ts +197 -0
- package/src/lib/freePort.ts +33 -0
- package/src/lib/functionBuild.ts +490 -0
- package/src/lib/neonWsProxy.ts +124 -0
- package/src/lib/sourceZipUpload.ts +168 -0
- package/src/lib/stealthLaunch.ts +57 -0
- package/src/lib/storeAutomation.ts +110 -0
- package/src/playwright/baseConfig.ts +120 -0
- package/src/playwright/globalSetup.ts +179 -0
- package/src/playwright/index.ts +11 -0
- package/src/probes/fonts.ts +279 -0
- package/src/probes/mirror.ts +283 -0
- package/src/probes/runProbe.ts +257 -0
- package/src/probes/types.ts +73 -0
- package/src/scripts/addStore.ts +59 -0
- package/src/scripts/buildDockerImage.ts +66 -0
- package/src/scripts/captureAuth.ts +145 -0
- package/src/scripts/captureContracts.ts +675 -0
- package/src/scripts/captureRestContracts.ts +319 -0
- package/src/scripts/checkOperationCoverage.ts +365 -0
- package/src/scripts/cleanupStores.ts +91 -0
- package/src/scripts/createStores.ts +77 -0
- package/src/scripts/deployAppVersion.ts +692 -0
- package/src/scripts/devOnlineBackend.ts +141 -0
- package/src/scripts/installApp.ts +188 -0
- package/src/scripts/listStores.ts +19 -0
- package/src/scripts/runDockerAuth.ts +120 -0
- package/src/scripts/runOffline.ts +577 -0
- package/src/scripts/runOfflineFullTests.ts +1634 -0
- package/src/scripts/runTests.ts +306 -0
- package/src/scripts/runVm.ts +562 -0
- package/src/scripts/runVmAuth.ts +541 -0
- package/src/scripts/runVmScript.ts +282 -0
- package/src/scripts/setupTestDb.ts +71 -0
- package/src/scripts/verifyContracts.ts +310 -0
- package/src/scripts/verifyRestContracts.ts +275 -0
- package/src/vite/onlineConfig.ts +60 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* verifyRestContracts — replay each vendored REST contract,
|
|
4
|
+
* diff vs the contract.
|
|
5
|
+
*
|
|
6
|
+
* Sister to `verifyContracts.ts`, but for REST. See
|
|
7
|
+
* `captureRestContracts.ts` for the manifest format and capture
|
|
8
|
+
* flow; this script consumes the captured contracts and asserts the
|
|
9
|
+
* target still returns the same shape.
|
|
10
|
+
*
|
|
11
|
+
* - `--target offline` (default): hit the in-process mock-admin
|
|
12
|
+
* Hono app. Detects regression in the mock's REST stubs.
|
|
13
|
+
* - `--target live`: hit a real Shopify admin endpoint with
|
|
14
|
+
* CONTRACTS_LIVE_SHOP + CONTRACTS_LIVE_ACCESS_TOKEN. Detects
|
|
15
|
+
* drift between vendored contracts and what Shopify actually
|
|
16
|
+
* returns today.
|
|
17
|
+
*
|
|
18
|
+
* Responses are normalised (volatile IDs / timestamps / CDN URLs /
|
|
19
|
+
* cursors → stable tokens) before diffing — same normaliser the
|
|
20
|
+
* GraphQL verifier uses. Offline-offline matches byte-for-byte
|
|
21
|
+
* anyway; the normaliser only matters for live-vs-contract.
|
|
22
|
+
*/
|
|
23
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
24
|
+
import { resolve, relative } from 'node:path';
|
|
25
|
+
import { createAdminApi, } from '@essential-apps/shopify-test-shopify-api';
|
|
26
|
+
import { ShopState } from '@essential-apps/shopify-test-storefront';
|
|
27
|
+
import { normaliseResponse } from '../contracts/normalize.js';
|
|
28
|
+
const ADMIN_API_VERSION = '2025-07';
|
|
29
|
+
function parseArgs() {
|
|
30
|
+
const argv = process.argv.slice(2);
|
|
31
|
+
const out = {
|
|
32
|
+
contractsDir: '',
|
|
33
|
+
cwd: process.cwd(),
|
|
34
|
+
};
|
|
35
|
+
for (let i = 0; i < argv.length; i++) {
|
|
36
|
+
const a = argv[i] ?? '';
|
|
37
|
+
if (a === '--dir' && i + 1 < argv.length) {
|
|
38
|
+
out.contractsDir = argv[++i] ?? '';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!out.contractsDir) {
|
|
42
|
+
out.contractsDir = resolve(out.cwd, 'tests/test-offline/contracts/admin-rest');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
out.contractsDir = resolve(out.cwd, out.contractsDir);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
function fillPath(template, params) {
|
|
50
|
+
return template.replace(/\{([^}]+)\}/g, (_, key) => {
|
|
51
|
+
if (!(key in params)) {
|
|
52
|
+
throw new Error(`path template references {${key}} but no value provided`);
|
|
53
|
+
}
|
|
54
|
+
return encodeURIComponent(params[key] ?? '');
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function appendQuery(path, query) {
|
|
58
|
+
if (!query || Object.keys(query).length === 0)
|
|
59
|
+
return path;
|
|
60
|
+
const params = new URLSearchParams();
|
|
61
|
+
for (const [k, v] of Object.entries(query))
|
|
62
|
+
params.set(k, v);
|
|
63
|
+
const joiner = path.includes('?') ? '&' : '?';
|
|
64
|
+
return `${path}${joiner}${params.toString()}`;
|
|
65
|
+
}
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Hono is loosely typed
|
|
67
|
+
function buildOfflineExecutor(state) {
|
|
68
|
+
const app = createAdminApi({ state });
|
|
69
|
+
return async (contract) => {
|
|
70
|
+
const filled = fillPath(contract.path, {
|
|
71
|
+
version: ADMIN_API_VERSION,
|
|
72
|
+
...(contract.pathParams ?? {}),
|
|
73
|
+
});
|
|
74
|
+
const finalPath = appendQuery(filled, contract.query);
|
|
75
|
+
const init = {
|
|
76
|
+
method: contract.method,
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
'X-Shopify-Access-Token': 'mock-access-token',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
if (contract.body !== undefined) {
|
|
83
|
+
init.body = JSON.stringify(contract.body);
|
|
84
|
+
}
|
|
85
|
+
const resp = await app.request(finalPath, init);
|
|
86
|
+
let body = null;
|
|
87
|
+
try {
|
|
88
|
+
body = await resp.json();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// empty / non-JSON
|
|
92
|
+
}
|
|
93
|
+
return { status: resp.status, body };
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Live executor intentionally removed — platform parity (does the
|
|
97
|
+
// mock match real Shopify) is owned by
|
|
98
|
+
// `@essential-apps/shopify-test-conformance`. Consuming-app
|
|
99
|
+
// contract verification only runs against the offline mock.
|
|
100
|
+
/**
|
|
101
|
+
* Deep-diff with normalised first-mismatch reporting. Same shape
|
|
102
|
+
* as the GraphQL verifier — kept independent rather than imported
|
|
103
|
+
* so the REST script can be invoked standalone.
|
|
104
|
+
*/
|
|
105
|
+
function diff(expected, actual, path = '$') {
|
|
106
|
+
if (expected === actual)
|
|
107
|
+
return null;
|
|
108
|
+
if (typeof expected !== typeof actual ||
|
|
109
|
+
expected === null ||
|
|
110
|
+
actual === null) {
|
|
111
|
+
return `${path}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`;
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(expected)) {
|
|
114
|
+
if (!Array.isArray(actual))
|
|
115
|
+
return `${path}: expected array, got object`;
|
|
116
|
+
if (expected.length !== actual.length) {
|
|
117
|
+
return `${path}: expected length ${expected.length}, got ${actual.length}`;
|
|
118
|
+
}
|
|
119
|
+
for (let i = 0; i < expected.length; i++) {
|
|
120
|
+
const d = diff(expected[i], actual[i], `${path}[${i}]`);
|
|
121
|
+
if (d)
|
|
122
|
+
return d;
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
if (typeof expected === 'object') {
|
|
127
|
+
const e = expected;
|
|
128
|
+
const a = actual;
|
|
129
|
+
const allKeys = new Set([...Object.keys(e), ...Object.keys(a)]);
|
|
130
|
+
for (const k of allKeys) {
|
|
131
|
+
if (!(k in e))
|
|
132
|
+
return `${path}.${k}: unexpected key`;
|
|
133
|
+
if (!(k in a))
|
|
134
|
+
return `${path}.${k}: missing key`;
|
|
135
|
+
const d = diff(e[k], a[k], `${path}.${k}`);
|
|
136
|
+
if (d)
|
|
137
|
+
return d;
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return `${path}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`;
|
|
142
|
+
}
|
|
143
|
+
async function main() {
|
|
144
|
+
const args = parseArgs();
|
|
145
|
+
let entries;
|
|
146
|
+
try {
|
|
147
|
+
entries = readdirSync(args.contractsDir);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
console.error(`[verify-rest] no contracts directory at ${args.contractsDir}. ` +
|
|
151
|
+
`Run \`npm run test:online:capture-rest-contracts\` first.`);
|
|
152
|
+
process.exit(2);
|
|
153
|
+
}
|
|
154
|
+
const contractFiles = entries.filter((f) => f.endsWith('.json'));
|
|
155
|
+
if (contractFiles.length === 0) {
|
|
156
|
+
console.error(`[verify-rest] no contracts found in ${args.contractsDir}`);
|
|
157
|
+
process.exit(2);
|
|
158
|
+
}
|
|
159
|
+
const state = buildSeededState();
|
|
160
|
+
const executor = buildOfflineExecutor(state);
|
|
161
|
+
let pass = 0;
|
|
162
|
+
let drift = 0;
|
|
163
|
+
let skipped = 0;
|
|
164
|
+
const failures = [];
|
|
165
|
+
for (const f of contractFiles) {
|
|
166
|
+
const path = resolve(args.contractsDir, f);
|
|
167
|
+
let st;
|
|
168
|
+
try {
|
|
169
|
+
st = statSync(path);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (!st.isFile())
|
|
175
|
+
continue;
|
|
176
|
+
const contract = JSON.parse(readFileSync(path, 'utf8'));
|
|
177
|
+
if (contract.warning) {
|
|
178
|
+
skipped++;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
let actual;
|
|
182
|
+
try {
|
|
183
|
+
actual = await executor(contract);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
drift++;
|
|
187
|
+
failures.push({ contract: f, diff: `executor threw: ${err.message}` });
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// Status-code mismatch is a hard diff — surface it directly.
|
|
191
|
+
if (actual.status !== contract.response.status) {
|
|
192
|
+
drift++;
|
|
193
|
+
failures.push({
|
|
194
|
+
contract: f,
|
|
195
|
+
diff: `$.status: expected ${contract.response.status}, got ${actual.status}`,
|
|
196
|
+
});
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
// Body diff — normalise both sides first (same rationale as
|
|
200
|
+
// GraphQL verify; see contracts/normalize.ts).
|
|
201
|
+
const expectedNorm = normaliseResponse(contract.response.body);
|
|
202
|
+
const actualNorm = normaliseResponse(actual.body);
|
|
203
|
+
const d = diff(expectedNorm, actualNorm, '$.body');
|
|
204
|
+
if (d === null) {
|
|
205
|
+
pass++;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
drift++;
|
|
209
|
+
failures.push({ contract: f, diff: d });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
console.log(`[verify-rest]: ${pass} pass, ${drift} drift, ${skipped} skipped`);
|
|
213
|
+
if (failures.length > 0) {
|
|
214
|
+
console.log('');
|
|
215
|
+
console.log('[verify-rest] drift:');
|
|
216
|
+
for (const f of failures) {
|
|
217
|
+
console.log(` ${relative(args.cwd, resolve(args.contractsDir, f.contract))}`);
|
|
218
|
+
console.log(` ${f.diff}`);
|
|
219
|
+
}
|
|
220
|
+
console.log('');
|
|
221
|
+
console.log('If the mock is correct and the contract is stale, regenerate with `npm run test:online:capture-rest-contracts`.');
|
|
222
|
+
}
|
|
223
|
+
process.exit(drift === 0 ? 0 : 1);
|
|
224
|
+
}
|
|
225
|
+
function buildSeededState() {
|
|
226
|
+
return new ShopState({
|
|
227
|
+
shop: {
|
|
228
|
+
domain: 'test-shop.myshopify.com',
|
|
229
|
+
permanent_domain: 'test-shop.myshopify.com',
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
main().catch((err) => {
|
|
234
|
+
console.error(err);
|
|
235
|
+
process.exit(2);
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=verifyRestContracts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyRestContracts.js","sourceRoot":"","sources":["../../src/scripts/verifyRestContracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ConfigEnv, type UserConfig } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Vite config used to serve a consuming app's backend for the
|
|
4
|
+
* OFFLINE-FULL suite via `vite dev` (instead of a prod build +
|
|
5
|
+
* remix-serve). `runOfflineFullTests` boots `vite --config <this>`.
|
|
6
|
+
*
|
|
7
|
+
* This is what makes offline onboarding zero-app-touch on the build
|
|
8
|
+
* side. A prod build runs the app's own vite.config, which for Vercel-
|
|
9
|
+
* hosted apps applies `vercelPreset()` and shards the server build so
|
|
10
|
+
* `remix-serve` can't boot it (the "vanilla build" problem). Build-only
|
|
11
|
+
* presets are INERT in dev, so serving via `vite dev` sidesteps it
|
|
12
|
+
* with no change to the app's vite.config.
|
|
13
|
+
*
|
|
14
|
+
* It loads the app's OWN config and overlays the offline necessities:
|
|
15
|
+
* - `server.hmr = false`: Vite dev injects HMR <script>/<link> tags
|
|
16
|
+
* that aren't in the SSR HTML → breaks React-18 hydration. Disabling
|
|
17
|
+
* HMR is what historically forced offline onto a prod build; turning
|
|
18
|
+
* it off here lets us serve via dev safely.
|
|
19
|
+
* - strip `basic-ssl`: the offline edge proxy + mocks expect a plain
|
|
20
|
+
* HTTP backend. Apps that add basicSsl in test mode would otherwise
|
|
21
|
+
* serve HTTPS. basic-ssl is a top-level plugin, so it's filterable
|
|
22
|
+
* (the Vercel preset isn't — it lives inside the remix() plugin —
|
|
23
|
+
* but it's build-only, so dev doesn't care). Dropping the plugin
|
|
24
|
+
* means no `server.https` is set, so the dev server is plain HTTP.
|
|
25
|
+
* - `optimizeDeps.entries`: pre-bundle every route's deps at startup
|
|
26
|
+
* so the first in-test navigation doesn't trigger Vite's on-demand
|
|
27
|
+
* re-optimize + iframe reload (same fix as the online suite).
|
|
28
|
+
*
|
|
29
|
+
* Generic + additive: never rewrites the app's plugins beyond dropping
|
|
30
|
+
* basic-ssl. Override the optimize glob with
|
|
31
|
+
* TEST_OFFLINE_VITE_OPTIMIZE_ENTRIES for apps with an unusual layout.
|
|
32
|
+
*/
|
|
33
|
+
export default function viteOfflineConfig(configEnv: ConfigEnv): Promise<UserConfig>;
|
|
34
|
+
//# sourceMappingURL=offlineConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offlineConfig.d.ts","sourceRoot":"","sources":["../../src/vite/offlineConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAA8B,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAgCzF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { loadConfigFromFile, mergeConfig } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Vite config used to serve a consuming app's backend for the
|
|
4
|
+
* OFFLINE-FULL suite via `vite dev` (instead of a prod build +
|
|
5
|
+
* remix-serve). `runOfflineFullTests` boots `vite --config <this>`.
|
|
6
|
+
*
|
|
7
|
+
* This is what makes offline onboarding zero-app-touch on the build
|
|
8
|
+
* side. A prod build runs the app's own vite.config, which for Vercel-
|
|
9
|
+
* hosted apps applies `vercelPreset()` and shards the server build so
|
|
10
|
+
* `remix-serve` can't boot it (the "vanilla build" problem). Build-only
|
|
11
|
+
* presets are INERT in dev, so serving via `vite dev` sidesteps it
|
|
12
|
+
* with no change to the app's vite.config.
|
|
13
|
+
*
|
|
14
|
+
* It loads the app's OWN config and overlays the offline necessities:
|
|
15
|
+
* - `server.hmr = false`: Vite dev injects HMR <script>/<link> tags
|
|
16
|
+
* that aren't in the SSR HTML → breaks React-18 hydration. Disabling
|
|
17
|
+
* HMR is what historically forced offline onto a prod build; turning
|
|
18
|
+
* it off here lets us serve via dev safely.
|
|
19
|
+
* - strip `basic-ssl`: the offline edge proxy + mocks expect a plain
|
|
20
|
+
* HTTP backend. Apps that add basicSsl in test mode would otherwise
|
|
21
|
+
* serve HTTPS. basic-ssl is a top-level plugin, so it's filterable
|
|
22
|
+
* (the Vercel preset isn't — it lives inside the remix() plugin —
|
|
23
|
+
* but it's build-only, so dev doesn't care). Dropping the plugin
|
|
24
|
+
* means no `server.https` is set, so the dev server is plain HTTP.
|
|
25
|
+
* - `optimizeDeps.entries`: pre-bundle every route's deps at startup
|
|
26
|
+
* so the first in-test navigation doesn't trigger Vite's on-demand
|
|
27
|
+
* re-optimize + iframe reload (same fix as the online suite).
|
|
28
|
+
*
|
|
29
|
+
* Generic + additive: never rewrites the app's plugins beyond dropping
|
|
30
|
+
* basic-ssl. Override the optimize glob with
|
|
31
|
+
* TEST_OFFLINE_VITE_OPTIMIZE_ENTRIES for apps with an unusual layout.
|
|
32
|
+
*/
|
|
33
|
+
export default async function viteOfflineConfig(configEnv) {
|
|
34
|
+
const root = process.cwd();
|
|
35
|
+
const loaded = await loadConfigFromFile(configEnv, undefined, root);
|
|
36
|
+
if (!loaded?.config) {
|
|
37
|
+
throw new Error(`viteOfflineConfig: could not load the app's Vite config from ${root}. ` +
|
|
38
|
+
`Expected a vite.config.{ts,js,mjs,mts,…} at the repo root.`);
|
|
39
|
+
}
|
|
40
|
+
const appConfig = loaded.config;
|
|
41
|
+
// Drop basic-ssl (→ plain HTTP). Flatten one level since plugin
|
|
42
|
+
// entries can be nested arrays; keep everything that isn't basic-ssl
|
|
43
|
+
// (incl. falsy/Promise entries, which Vite tolerates).
|
|
44
|
+
const plugins = (appConfig.plugins ?? [])
|
|
45
|
+
.flat(Infinity)
|
|
46
|
+
.filter((p) => {
|
|
47
|
+
const name = p?.name;
|
|
48
|
+
return !(name && name.includes('basic-ssl'));
|
|
49
|
+
});
|
|
50
|
+
const entries = process.env['TEST_OFFLINE_VITE_OPTIMIZE_ENTRIES']
|
|
51
|
+
? process.env['TEST_OFFLINE_VITE_OPTIMIZE_ENTRIES']
|
|
52
|
+
.split(',')
|
|
53
|
+
.map((s) => s.trim())
|
|
54
|
+
.filter(Boolean)
|
|
55
|
+
: ['app/**/*.{ts,tsx,jsx,js}', '!app/**/*.server.*'];
|
|
56
|
+
return mergeConfig({ ...appConfig, plugins }, {
|
|
57
|
+
optimizeDeps: { entries },
|
|
58
|
+
server: { hmr: false },
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=offlineConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offlineConfig.js","sourceRoot":"","sources":["../../src/vite/offlineConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAmC,MAAM,MAAM,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAoB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,gEAAgE,IAAI,IAAI;YACtE,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;IAEhC,gEAAgE;IAChE,qEAAqE;IACrE,uDAAuD;IACvD,MAAM,OAAO,GAAI,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAe;SACrD,IAAI,CAAC,QAAa,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACZ,MAAM,IAAI,GAAI,CAA0C,EAAE,IAAI,CAAC;QAC/D,OAAO,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;IAC/C,CAAC,CAA0B,CAAC;IAE9B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC;QAC/D,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC;aAC9C,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;QACpB,CAAC,CAAC,CAAC,0BAA0B,EAAE,oBAAoB,CAAC,CAAC;IAEvD,OAAO,WAAW,CAAC,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,EAAE;QAC5C,YAAY,EAAE,EAAE,OAAO,EAAE;QACzB,MAAM,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE;KACF,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ConfigEnv, type UserConfig } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Vite config used ONLY to serve the app backend for the ONLINE test
|
|
4
|
+
* suite — `runTests.ts` boots the dev server with
|
|
5
|
+
* `vite --config <this file>`. It is never referenced by an app's own
|
|
6
|
+
* `vite dev` / `vite build`, so it cannot change any app's production
|
|
7
|
+
* or local-dev behaviour. (Offline-full serves a production build via
|
|
8
|
+
* remix-serve; conformance runs VM probes — neither uses Vite dev, so
|
|
9
|
+
* this is online-only.)
|
|
10
|
+
*
|
|
11
|
+
* What it does: load the consuming app's OWN Vite config (auto-
|
|
12
|
+
* discovered from cwd) and merge `optimizeDeps.entries` on top so Vite
|
|
13
|
+
* crawls every route at server startup and pre-bundles all their
|
|
14
|
+
* client deps in the FIRST optimize pass.
|
|
15
|
+
*
|
|
16
|
+
* Why: in dev, Vite discovers a route's deps lazily — on the first
|
|
17
|
+
* navigation to that route — then re-optimizes and FORCE-RELOADS the
|
|
18
|
+
* page to pick up the freshly pre-bundled deps. Inside the embedded
|
|
19
|
+
* app iframe that reload tears the page down mid-test. Observed as the
|
|
20
|
+
* funnels "placement type list shows all 4 placements" flake: the
|
|
21
|
+
* first hit to /app/funnels/new pulls in react-hook-form / @dnd-kit /
|
|
22
|
+
* zod, Vite reloads, and the content assertion times out; the retry is
|
|
23
|
+
* fast because the deps are now warm. Crawling every route up front
|
|
24
|
+
* leaves nothing to discover on navigation, so there is no reload.
|
|
25
|
+
*
|
|
26
|
+
* Generic + safe for every consuming app:
|
|
27
|
+
* - additive: only ADDS optimizeDeps.entries (mergeConfig concatenates
|
|
28
|
+
* arrays); never removes or rewrites the app's plugins/options.
|
|
29
|
+
* - auto-discovers the app config (any extension) — no path assumption.
|
|
30
|
+
* - the glob is a Remix-convention default; if it matches nothing it's
|
|
31
|
+
* a harmless no-op (no breakage, just no speed-up).
|
|
32
|
+
* - `.server.*` files are excluded so server-only modules aren't
|
|
33
|
+
* dragged into the client dep scan.
|
|
34
|
+
* - override the glob with TEST_ONLINE_VITE_OPTIMIZE_ENTRIES
|
|
35
|
+
* (comma-separated) for apps with an unusual route layout.
|
|
36
|
+
*
|
|
37
|
+
* `runTests.ts` only passes `--config` to this file when the optimize
|
|
38
|
+
* is enabled; TEST_ONLINE_VITE_OPTIMIZE_ALL=0 boots bare `vite` with
|
|
39
|
+
* the app config untouched (kill switch).
|
|
40
|
+
*/
|
|
41
|
+
export default function viteOnlineConfig(configEnv: ConfigEnv): Promise<UserConfig>;
|
|
42
|
+
//# sourceMappingURL=onlineConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onlineConfig.d.ts","sourceRoot":"","sources":["../../src/vite/onlineConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAA8B,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAkBxF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { loadConfigFromFile, mergeConfig } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Vite config used ONLY to serve the app backend for the ONLINE test
|
|
4
|
+
* suite — `runTests.ts` boots the dev server with
|
|
5
|
+
* `vite --config <this file>`. It is never referenced by an app's own
|
|
6
|
+
* `vite dev` / `vite build`, so it cannot change any app's production
|
|
7
|
+
* or local-dev behaviour. (Offline-full serves a production build via
|
|
8
|
+
* remix-serve; conformance runs VM probes — neither uses Vite dev, so
|
|
9
|
+
* this is online-only.)
|
|
10
|
+
*
|
|
11
|
+
* What it does: load the consuming app's OWN Vite config (auto-
|
|
12
|
+
* discovered from cwd) and merge `optimizeDeps.entries` on top so Vite
|
|
13
|
+
* crawls every route at server startup and pre-bundles all their
|
|
14
|
+
* client deps in the FIRST optimize pass.
|
|
15
|
+
*
|
|
16
|
+
* Why: in dev, Vite discovers a route's deps lazily — on the first
|
|
17
|
+
* navigation to that route — then re-optimizes and FORCE-RELOADS the
|
|
18
|
+
* page to pick up the freshly pre-bundled deps. Inside the embedded
|
|
19
|
+
* app iframe that reload tears the page down mid-test. Observed as the
|
|
20
|
+
* funnels "placement type list shows all 4 placements" flake: the
|
|
21
|
+
* first hit to /app/funnels/new pulls in react-hook-form / @dnd-kit /
|
|
22
|
+
* zod, Vite reloads, and the content assertion times out; the retry is
|
|
23
|
+
* fast because the deps are now warm. Crawling every route up front
|
|
24
|
+
* leaves nothing to discover on navigation, so there is no reload.
|
|
25
|
+
*
|
|
26
|
+
* Generic + safe for every consuming app:
|
|
27
|
+
* - additive: only ADDS optimizeDeps.entries (mergeConfig concatenates
|
|
28
|
+
* arrays); never removes or rewrites the app's plugins/options.
|
|
29
|
+
* - auto-discovers the app config (any extension) — no path assumption.
|
|
30
|
+
* - the glob is a Remix-convention default; if it matches nothing it's
|
|
31
|
+
* a harmless no-op (no breakage, just no speed-up).
|
|
32
|
+
* - `.server.*` files are excluded so server-only modules aren't
|
|
33
|
+
* dragged into the client dep scan.
|
|
34
|
+
* - override the glob with TEST_ONLINE_VITE_OPTIMIZE_ENTRIES
|
|
35
|
+
* (comma-separated) for apps with an unusual route layout.
|
|
36
|
+
*
|
|
37
|
+
* `runTests.ts` only passes `--config` to this file when the optimize
|
|
38
|
+
* is enabled; TEST_ONLINE_VITE_OPTIMIZE_ALL=0 boots bare `vite` with
|
|
39
|
+
* the app config untouched (kill switch).
|
|
40
|
+
*/
|
|
41
|
+
export default async function viteOnlineConfig(configEnv) {
|
|
42
|
+
const root = process.cwd();
|
|
43
|
+
const loaded = await loadConfigFromFile(configEnv, undefined, root);
|
|
44
|
+
if (!loaded?.config) {
|
|
45
|
+
throw new Error(`viteOnlineConfig: could not load the app's Vite config from ${root}. ` +
|
|
46
|
+
`Expected a vite.config.{ts,js,mjs,mts,…} at the repo root.`);
|
|
47
|
+
}
|
|
48
|
+
const entries = process.env['TEST_ONLINE_VITE_OPTIMIZE_ENTRIES']
|
|
49
|
+
? process.env['TEST_ONLINE_VITE_OPTIMIZE_ENTRIES']
|
|
50
|
+
.split(',')
|
|
51
|
+
.map((s) => s.trim())
|
|
52
|
+
.filter(Boolean)
|
|
53
|
+
: ['app/**/*.{ts,tsx,jsx,js}', '!app/**/*.server.*'];
|
|
54
|
+
return mergeConfig(loaded.config, { optimizeDeps: { entries } });
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=onlineConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onlineConfig.js","sourceRoot":"","sources":["../../src/vite/onlineConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAmC,MAAM,MAAM,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAoB;IACjE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,+DAA+D,IAAI,IAAI;YACrE,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC;QAC9D,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC;aAC7C,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;QACpB,CAAC,CAAC,CAAC,0BAA0B,EAAE,oBAAoB,CAAC,CAAC;IAEvD,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAuB,CAAC,CAAC;AACxF,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Self-contained test image: Playwright (Node + Chromium) + Postgres.
|
|
2
|
+
# Built via `container build` (Apple's libkrun-based framework).
|
|
3
|
+
# Run via the test runner — see scripts/test/runTests.ts.
|
|
4
|
+
#
|
|
5
|
+
# Architecture: everything runs inside the VM. No host pg dependency.
|
|
6
|
+
# Postgres data lives in a bind-mounted volume so it persists across runs
|
|
7
|
+
# (cuts down per-run setup; per-run isolation is via UUID DB names).
|
|
8
|
+
FROM mcr.microsoft.com/playwright:v1.59.1-jammy
|
|
9
|
+
|
|
10
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
11
|
+
|
|
12
|
+
RUN apt-get update -qq \
|
|
13
|
+
&& apt-get install -y -qq \
|
|
14
|
+
postgresql-14 \
|
|
15
|
+
postgresql-client-14 \
|
|
16
|
+
sudo \
|
|
17
|
+
procps \
|
|
18
|
+
net-tools \
|
|
19
|
+
wget \
|
|
20
|
+
gnupg \
|
|
21
|
+
ca-certificates \
|
|
22
|
+
libnss3-tools \
|
|
23
|
+
x11vnc \
|
|
24
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
25
|
+
|
|
26
|
+
# Install real Google Chrome (stable). Playwright's bundled chromium
|
|
27
|
+
# trips Cloudflare's Turnstile challenge on Linux even with patchright
|
|
28
|
+
# stealth patches; real Chrome renders Turnstile the same way it does
|
|
29
|
+
# on the host, where the challenge auto-clicks cleanly. Note: Google
|
|
30
|
+
# only ships Chrome for Linux amd64 (no ARM64 Linux build), so this
|
|
31
|
+
# image MUST be built with --arch amd64 (Rosetta emulation under Apple
|
|
32
|
+
# Silicon — see packages/runner/src/scripts/buildDockerImage.ts and
|
|
33
|
+
# the `image:build` npm script).
|
|
34
|
+
RUN wget -q -O /tmp/chrome.deb \
|
|
35
|
+
https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
|
|
36
|
+
&& apt-get update -qq \
|
|
37
|
+
&& apt-get install -y -qq /tmp/chrome.deb \
|
|
38
|
+
&& rm -f /tmp/chrome.deb \
|
|
39
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
40
|
+
|
|
41
|
+
# Install cloudflared (quick-tunnel mode, no Cloudflare account
|
|
42
|
+
# needed). Used by the webhook-envelope conformance probes to
|
|
43
|
+
# expose a localhost HTTP receiver on a temporary public URL
|
|
44
|
+
# (https://*.trycloudflare.com) so real Shopify can POST webhooks
|
|
45
|
+
# to it. Lifetime is per-probe-run; the tunnel is torn down as
|
|
46
|
+
# soon as the webhook arrives + payload is captured.
|
|
47
|
+
RUN wget -q -O /tmp/cloudflared.deb \
|
|
48
|
+
https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb \
|
|
49
|
+
&& apt-get update -qq \
|
|
50
|
+
&& apt-get install -y -qq /tmp/cloudflared.deb \
|
|
51
|
+
&& rm -f /tmp/cloudflared.deb \
|
|
52
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
53
|
+
|
|
54
|
+
ENV PGDATA=/var/lib/postgresql/data
|
|
55
|
+
ENV PG_BIN=/usr/lib/postgresql/14/bin
|
|
56
|
+
|
|
57
|
+
RUN mkdir -p "$PGDATA" \
|
|
58
|
+
&& chown -R postgres:postgres "$PGDATA" \
|
|
59
|
+
&& chmod 700 "$PGDATA"
|
|
60
|
+
|
|
61
|
+
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
|
62
|
+
RUN chmod +x /usr/local/bin/entrypoint.sh
|
|
63
|
+
|
|
64
|
+
WORKDIR /workspace
|
|
65
|
+
|
|
66
|
+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
|
67
|
+
CMD ["bash"]
|