@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.
Files changed (265) hide show
  1. package/dist/contracts/normalize.d.ts +61 -0
  2. package/dist/contracts/normalize.d.ts.map +1 -0
  3. package/dist/contracts/normalize.js +99 -0
  4. package/dist/contracts/normalize.js.map +1 -0
  5. package/dist/contracts/normalizeHtml.d.ts +37 -0
  6. package/dist/contracts/normalizeHtml.d.ts.map +1 -0
  7. package/dist/contracts/normalizeHtml.js +89 -0
  8. package/dist/contracts/normalizeHtml.js.map +1 -0
  9. package/dist/edge/cert.d.ts +44 -0
  10. package/dist/edge/cert.d.ts.map +1 -0
  11. package/dist/edge/cert.js +117 -0
  12. package/dist/edge/cert.js.map +1 -0
  13. package/dist/edge/edgeProxy.d.ts +43 -0
  14. package/dist/edge/edgeProxy.d.ts.map +1 -0
  15. package/dist/edge/edgeProxy.js +297 -0
  16. package/dist/edge/edgeProxy.js.map +1 -0
  17. package/dist/edge/nodeShim.d.ts +2 -0
  18. package/dist/edge/nodeShim.d.ts.map +1 -0
  19. package/dist/edge/nodeShim.js +217 -0
  20. package/dist/edge/nodeShim.js.map +1 -0
  21. package/dist/index.d.ts +39 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +36 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/lib/buildSourceBundle.d.ts +56 -0
  26. package/dist/lib/buildSourceBundle.d.ts.map +1 -0
  27. package/dist/lib/buildSourceBundle.js +153 -0
  28. package/dist/lib/buildSourceBundle.js.map +1 -0
  29. package/dist/lib/freePort.d.ts +5 -0
  30. package/dist/lib/freePort.d.ts.map +1 -0
  31. package/dist/lib/freePort.js +33 -0
  32. package/dist/lib/freePort.js.map +1 -0
  33. package/dist/lib/functionBuild.d.ts +99 -0
  34. package/dist/lib/functionBuild.d.ts.map +1 -0
  35. package/dist/lib/functionBuild.js +413 -0
  36. package/dist/lib/functionBuild.js.map +1 -0
  37. package/dist/lib/neonWsProxy.d.ts +41 -0
  38. package/dist/lib/neonWsProxy.d.ts.map +1 -0
  39. package/dist/lib/neonWsProxy.js +101 -0
  40. package/dist/lib/neonWsProxy.js.map +1 -0
  41. package/dist/lib/sourceZipUpload.d.ts +45 -0
  42. package/dist/lib/sourceZipUpload.d.ts.map +1 -0
  43. package/dist/lib/sourceZipUpload.js +129 -0
  44. package/dist/lib/sourceZipUpload.js.map +1 -0
  45. package/dist/lib/stealthLaunch.d.ts +35 -0
  46. package/dist/lib/stealthLaunch.d.ts.map +1 -0
  47. package/dist/lib/stealthLaunch.js +46 -0
  48. package/dist/lib/stealthLaunch.js.map +1 -0
  49. package/dist/lib/storeAutomation.d.ts +22 -0
  50. package/dist/lib/storeAutomation.d.ts.map +1 -0
  51. package/dist/lib/storeAutomation.js +85 -0
  52. package/dist/lib/storeAutomation.js.map +1 -0
  53. package/dist/playwright/baseConfig.d.ts +62 -0
  54. package/dist/playwright/baseConfig.d.ts.map +1 -0
  55. package/dist/playwright/baseConfig.js +68 -0
  56. package/dist/playwright/baseConfig.js.map +1 -0
  57. package/dist/playwright/globalSetup.d.ts +2 -0
  58. package/dist/playwright/globalSetup.d.ts.map +1 -0
  59. package/dist/playwright/globalSetup.js +139 -0
  60. package/dist/playwright/globalSetup.js.map +1 -0
  61. package/dist/playwright/index.d.ts +9 -0
  62. package/dist/playwright/index.d.ts.map +1 -0
  63. package/dist/playwright/index.js +9 -0
  64. package/dist/playwright/index.js.map +1 -0
  65. package/dist/probes/fonts.d.ts +4 -0
  66. package/dist/probes/fonts.d.ts.map +1 -0
  67. package/dist/probes/fonts.js +255 -0
  68. package/dist/probes/fonts.js.map +1 -0
  69. package/dist/probes/mirror.d.ts +4 -0
  70. package/dist/probes/mirror.d.ts.map +1 -0
  71. package/dist/probes/mirror.js +260 -0
  72. package/dist/probes/mirror.js.map +1 -0
  73. package/dist/probes/runProbe.d.ts +3 -0
  74. package/dist/probes/runProbe.d.ts.map +1 -0
  75. package/dist/probes/runProbe.js +219 -0
  76. package/dist/probes/runProbe.js.map +1 -0
  77. package/dist/probes/types.d.ts +72 -0
  78. package/dist/probes/types.d.ts.map +1 -0
  79. package/dist/probes/types.js +2 -0
  80. package/dist/probes/types.js.map +1 -0
  81. package/dist/scripts/_probeSourceUrl.d.ts +3 -0
  82. package/dist/scripts/_probeSourceUrl.d.ts.map +1 -0
  83. package/dist/scripts/_probeSourceUrl.js +119 -0
  84. package/dist/scripts/_probeSourceUrl.js.map +1 -0
  85. package/dist/scripts/addStore.d.ts +3 -0
  86. package/dist/scripts/addStore.d.ts.map +1 -0
  87. package/dist/scripts/addStore.js +46 -0
  88. package/dist/scripts/addStore.js.map +1 -0
  89. package/dist/scripts/buildDockerImage.d.ts +3 -0
  90. package/dist/scripts/buildDockerImage.d.ts.map +1 -0
  91. package/dist/scripts/buildDockerImage.js +60 -0
  92. package/dist/scripts/buildDockerImage.js.map +1 -0
  93. package/dist/scripts/captureAuth.d.ts +3 -0
  94. package/dist/scripts/captureAuth.d.ts.map +1 -0
  95. package/dist/scripts/captureAuth.js +124 -0
  96. package/dist/scripts/captureAuth.js.map +1 -0
  97. package/dist/scripts/captureContracts.d.ts +3 -0
  98. package/dist/scripts/captureContracts.d.ts.map +1 -0
  99. package/dist/scripts/captureContracts.js +517 -0
  100. package/dist/scripts/captureContracts.js.map +1 -0
  101. package/dist/scripts/captureRestContracts.d.ts +3 -0
  102. package/dist/scripts/captureRestContracts.d.ts.map +1 -0
  103. package/dist/scripts/captureRestContracts.js +245 -0
  104. package/dist/scripts/captureRestContracts.js.map +1 -0
  105. package/dist/scripts/checkOperationCoverage.d.ts +3 -0
  106. package/dist/scripts/checkOperationCoverage.d.ts.map +1 -0
  107. package/dist/scripts/checkOperationCoverage.js +302 -0
  108. package/dist/scripts/checkOperationCoverage.js.map +1 -0
  109. package/dist/scripts/cleanupStores.d.ts +3 -0
  110. package/dist/scripts/cleanupStores.d.ts.map +1 -0
  111. package/dist/scripts/cleanupStores.js +77 -0
  112. package/dist/scripts/cleanupStores.js.map +1 -0
  113. package/dist/scripts/createStores.d.ts +3 -0
  114. package/dist/scripts/createStores.d.ts.map +1 -0
  115. package/dist/scripts/createStores.js +66 -0
  116. package/dist/scripts/createStores.js.map +1 -0
  117. package/dist/scripts/deployAppVersion.d.ts +3 -0
  118. package/dist/scripts/deployAppVersion.d.ts.map +1 -0
  119. package/dist/scripts/deployAppVersion.js +591 -0
  120. package/dist/scripts/deployAppVersion.js.map +1 -0
  121. package/dist/scripts/devE2eBackend.d.ts +3 -0
  122. package/dist/scripts/devE2eBackend.d.ts.map +1 -0
  123. package/dist/scripts/devE2eBackend.js +117 -0
  124. package/dist/scripts/devE2eBackend.js.map +1 -0
  125. package/dist/scripts/devOnlineBackend.d.ts +3 -0
  126. package/dist/scripts/devOnlineBackend.d.ts.map +1 -0
  127. package/dist/scripts/devOnlineBackend.js +117 -0
  128. package/dist/scripts/devOnlineBackend.js.map +1 -0
  129. package/dist/scripts/installApp.d.ts +3 -0
  130. package/dist/scripts/installApp.d.ts.map +1 -0
  131. package/dist/scripts/installApp.js +163 -0
  132. package/dist/scripts/installApp.js.map +1 -0
  133. package/dist/scripts/listStores.d.ts +3 -0
  134. package/dist/scripts/listStores.d.ts.map +1 -0
  135. package/dist/scripts/listStores.js +18 -0
  136. package/dist/scripts/listStores.js.map +1 -0
  137. package/dist/scripts/runDocker.d.ts +3 -0
  138. package/dist/scripts/runDocker.d.ts.map +1 -0
  139. package/dist/scripts/runDocker.js +88 -0
  140. package/dist/scripts/runDocker.js.map +1 -0
  141. package/dist/scripts/runDockerAuth.d.ts +3 -0
  142. package/dist/scripts/runDockerAuth.d.ts.map +1 -0
  143. package/dist/scripts/runDockerAuth.js +108 -0
  144. package/dist/scripts/runDockerAuth.js.map +1 -0
  145. package/dist/scripts/runDockerOffline.d.ts +3 -0
  146. package/dist/scripts/runDockerOffline.d.ts.map +1 -0
  147. package/dist/scripts/runDockerOffline.js +129 -0
  148. package/dist/scripts/runDockerOffline.js.map +1 -0
  149. package/dist/scripts/runDockerOfflineExplore.d.ts +3 -0
  150. package/dist/scripts/runDockerOfflineExplore.d.ts.map +1 -0
  151. package/dist/scripts/runDockerOfflineExplore.js +116 -0
  152. package/dist/scripts/runDockerOfflineExplore.js.map +1 -0
  153. package/dist/scripts/runIsolatedDockerOffline.d.ts +3 -0
  154. package/dist/scripts/runIsolatedDockerOffline.d.ts.map +1 -0
  155. package/dist/scripts/runIsolatedDockerOffline.js +351 -0
  156. package/dist/scripts/runIsolatedDockerOffline.js.map +1 -0
  157. package/dist/scripts/runOffline.d.ts +3 -0
  158. package/dist/scripts/runOffline.d.ts.map +1 -0
  159. package/dist/scripts/runOffline.js +521 -0
  160. package/dist/scripts/runOffline.js.map +1 -0
  161. package/dist/scripts/runOfflineE2e.d.ts +3 -0
  162. package/dist/scripts/runOfflineE2e.d.ts.map +1 -0
  163. package/dist/scripts/runOfflineE2e.js +408 -0
  164. package/dist/scripts/runOfflineE2e.js.map +1 -0
  165. package/dist/scripts/runOfflineFullTests.d.ts +3 -0
  166. package/dist/scripts/runOfflineFullTests.d.ts.map +1 -0
  167. package/dist/scripts/runOfflineFullTests.js +1456 -0
  168. package/dist/scripts/runOfflineFullTests.js.map +1 -0
  169. package/dist/scripts/runSupermachine.d.ts +3 -0
  170. package/dist/scripts/runSupermachine.d.ts.map +1 -0
  171. package/dist/scripts/runSupermachine.js +474 -0
  172. package/dist/scripts/runSupermachine.js.map +1 -0
  173. package/dist/scripts/runSupermachineAuth.d.ts +3 -0
  174. package/dist/scripts/runSupermachineAuth.d.ts.map +1 -0
  175. package/dist/scripts/runSupermachineAuth.js +454 -0
  176. package/dist/scripts/runSupermachineAuth.js.map +1 -0
  177. package/dist/scripts/runTests.d.ts +3 -0
  178. package/dist/scripts/runTests.d.ts.map +1 -0
  179. package/dist/scripts/runTests.js +278 -0
  180. package/dist/scripts/runTests.js.map +1 -0
  181. package/dist/scripts/runVm.d.ts +3 -0
  182. package/dist/scripts/runVm.d.ts.map +1 -0
  183. package/dist/scripts/runVm.js +524 -0
  184. package/dist/scripts/runVm.js.map +1 -0
  185. package/dist/scripts/runVmAuth.d.ts +3 -0
  186. package/dist/scripts/runVmAuth.d.ts.map +1 -0
  187. package/dist/scripts/runVmAuth.js +475 -0
  188. package/dist/scripts/runVmAuth.js.map +1 -0
  189. package/dist/scripts/runVmScript.d.ts +3 -0
  190. package/dist/scripts/runVmScript.d.ts.map +1 -0
  191. package/dist/scripts/runVmScript.js +242 -0
  192. package/dist/scripts/runVmScript.js.map +1 -0
  193. package/dist/scripts/setupTestDb.d.ts +3 -0
  194. package/dist/scripts/setupTestDb.d.ts.map +1 -0
  195. package/dist/scripts/setupTestDb.js +61 -0
  196. package/dist/scripts/setupTestDb.js.map +1 -0
  197. package/dist/scripts/verifyContracts.d.ts +3 -0
  198. package/dist/scripts/verifyContracts.d.ts.map +1 -0
  199. package/dist/scripts/verifyContracts.js +258 -0
  200. package/dist/scripts/verifyContracts.js.map +1 -0
  201. package/dist/scripts/verifyRestContracts.d.ts +3 -0
  202. package/dist/scripts/verifyRestContracts.d.ts.map +1 -0
  203. package/dist/scripts/verifyRestContracts.js +237 -0
  204. package/dist/scripts/verifyRestContracts.js.map +1 -0
  205. package/dist/vite/offlineConfig.d.ts +34 -0
  206. package/dist/vite/offlineConfig.d.ts.map +1 -0
  207. package/dist/vite/offlineConfig.js +61 -0
  208. package/dist/vite/offlineConfig.js.map +1 -0
  209. package/dist/vite/onlineConfig.d.ts +42 -0
  210. package/dist/vite/onlineConfig.d.ts.map +1 -0
  211. package/dist/vite/onlineConfig.js +56 -0
  212. package/dist/vite/onlineConfig.js.map +1 -0
  213. package/docker/Dockerfile +67 -0
  214. package/docker/Dockerfile.vm +137 -0
  215. package/docker/README.md +50 -0
  216. package/docker/entrypoint.sh +198 -0
  217. package/package.json +85 -0
  218. package/src/contracts/normalize.ts +96 -0
  219. package/src/contracts/normalizeHtml.ts +98 -0
  220. package/src/edge/ca.cnf +14 -0
  221. package/src/edge/ca.crt +22 -0
  222. package/src/edge/ca.key +28 -0
  223. package/src/edge/cert.ts +117 -0
  224. package/src/edge/edgeProxy.ts +390 -0
  225. package/src/edge/server.cnf +28 -0
  226. package/src/edge/server.crt +26 -0
  227. package/src/edge/server.key +28 -0
  228. package/src/index.ts +67 -0
  229. package/src/lib/buildSourceBundle.ts +197 -0
  230. package/src/lib/freePort.ts +33 -0
  231. package/src/lib/functionBuild.ts +490 -0
  232. package/src/lib/neonWsProxy.ts +124 -0
  233. package/src/lib/sourceZipUpload.ts +168 -0
  234. package/src/lib/stealthLaunch.ts +57 -0
  235. package/src/lib/storeAutomation.ts +110 -0
  236. package/src/playwright/baseConfig.ts +120 -0
  237. package/src/playwright/globalSetup.ts +179 -0
  238. package/src/playwright/index.ts +11 -0
  239. package/src/probes/fonts.ts +279 -0
  240. package/src/probes/mirror.ts +283 -0
  241. package/src/probes/runProbe.ts +257 -0
  242. package/src/probes/types.ts +73 -0
  243. package/src/scripts/addStore.ts +59 -0
  244. package/src/scripts/buildDockerImage.ts +66 -0
  245. package/src/scripts/captureAuth.ts +145 -0
  246. package/src/scripts/captureContracts.ts +675 -0
  247. package/src/scripts/captureRestContracts.ts +319 -0
  248. package/src/scripts/checkOperationCoverage.ts +365 -0
  249. package/src/scripts/cleanupStores.ts +91 -0
  250. package/src/scripts/createStores.ts +77 -0
  251. package/src/scripts/deployAppVersion.ts +692 -0
  252. package/src/scripts/devOnlineBackend.ts +141 -0
  253. package/src/scripts/installApp.ts +188 -0
  254. package/src/scripts/listStores.ts +19 -0
  255. package/src/scripts/runDockerAuth.ts +120 -0
  256. package/src/scripts/runOffline.ts +577 -0
  257. package/src/scripts/runOfflineFullTests.ts +1634 -0
  258. package/src/scripts/runTests.ts +306 -0
  259. package/src/scripts/runVm.ts +562 -0
  260. package/src/scripts/runVmAuth.ts +541 -0
  261. package/src/scripts/runVmScript.ts +282 -0
  262. package/src/scripts/setupTestDb.ts +71 -0
  263. package/src/scripts/verifyContracts.ts +310 -0
  264. package/src/scripts/verifyRestContracts.ts +275 -0
  265. 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"]