@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,117 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Manual run of the e2e backend WITHOUT Shopify CLI.
4
+ *
5
+ * Used for `npm run test:online:install` (which needs a running backend to
6
+ * complete OAuth) and for local debugging. Mirrors the env-isolation
7
+ * guarantees of runTests.ts but uses a persistent DB
8
+ * (${appName}_e2e_${user}) instead of an ephemeral UUID one — so OAuth
9
+ * tokens persist across runs.
10
+ *
11
+ * Serves on https://localhost:PORT with a self-signed cert (vite +
12
+ * @vitejs/plugin-basic-ssl). No tunnel, no DNS.
13
+ */
14
+ import { spawn, execSync } from 'node:child_process';
15
+ import { existsSync, readFileSync } from 'node:fs';
16
+ import { resolve } from 'node:path';
17
+ import { loadEnv, printEnvSummary } from '@essential-apps/shopify-test-core';
18
+ import { isPortFree } from '../lib/freePort.js';
19
+ const PG_HOST = 'localhost';
20
+ const PG_PORT = '5432';
21
+ function readAppName() {
22
+ const pkgPath = resolve(process.cwd(), 'package.json');
23
+ if (!existsSync(pkgPath)) {
24
+ throw new Error(`No package.json at ${pkgPath}. Run this from the consuming app's repo root.`);
25
+ }
26
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
27
+ if (!pkg.name)
28
+ throw new Error(`package.json at ${pkgPath} has no \`name\` field.`);
29
+ return pkg.name.replace(/^@[^/]+\//, '');
30
+ }
31
+ function dbExists(name) {
32
+ try {
33
+ execSync(`psql -h ${PG_HOST} -p ${PG_PORT} -lqt | cut -d \\| -f 1 | grep -qw ${name}`, {
34
+ stdio: 'ignore',
35
+ });
36
+ return true;
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ }
42
+ async function main() {
43
+ const env = loadEnv();
44
+ printEnvSummary(env);
45
+ if (!env.apiSecret) {
46
+ throw new Error(`SHOPIFY_API_SECRET is not set in .env.test.\n\n` +
47
+ `Get it from Partner Dashboard → Apps → "${env.devAppHandle}" → ` +
48
+ `Configuration → "Client credentials" → "Reveal client secret".\n` +
49
+ `Paste it into .env.test as SHOPIFY_API_SECRET=...`);
50
+ }
51
+ const appUrl = new URL(env.devAppUrl);
52
+ if (appUrl.hostname !== 'localhost' && appUrl.hostname !== '127.0.0.1') {
53
+ throw new Error(`SHOPIFY_APP_URL must be a localhost URL (https://localhost:PORT). Got: ${env.devAppUrl}`);
54
+ }
55
+ if (appUrl.protocol !== 'https:') {
56
+ throw new Error(`SHOPIFY_APP_URL must use https:// — got ${env.devAppUrl}`);
57
+ }
58
+ const port = appUrl.port || '443';
59
+ if (!(await isPortFree(Number(port)))) {
60
+ throw new Error(`Port ${port} is in use. Find what's there: lsof -i :${port}\n` +
61
+ `Or change SHOPIFY_APP_URL in .env.test to a different port (and update Partner Dashboard).`);
62
+ }
63
+ const appName = readAppName();
64
+ const dbPrefix = (process.env['TEST_ONLINE_DB_NAME_PREFIX'] ?? `${appName}_e2e`)
65
+ .toLowerCase()
66
+ .replace(/[^a-z0-9_]/g, '_');
67
+ const PERSISTENT_DB_NAME = `${dbPrefix}_${process.env['USER'] ?? 'local'}`;
68
+ const user = process.env['USER'] ?? '';
69
+ const url = `postgresql://${user}@${PG_HOST}:${PG_PORT}/${PERSISTENT_DB_NAME}`;
70
+ console.log(`[dev-e2e] Persistent DB: ${url}`);
71
+ console.log(`[dev-e2e] Backend: ${env.devAppUrl} (vite https, self-signed cert)`);
72
+ console.log('');
73
+ if (!dbExists(PERSISTENT_DB_NAME)) {
74
+ console.log(`[dev-e2e] createdb ${PERSISTENT_DB_NAME}…`);
75
+ execSync(`createdb -h ${PG_HOST} -p ${PG_PORT} ${PERSISTENT_DB_NAME}`, {
76
+ stdio: 'inherit',
77
+ });
78
+ }
79
+ else {
80
+ console.log(`[dev-e2e] DB ${PERSISTENT_DB_NAME} exists, reusing.`);
81
+ }
82
+ const backendEnv = {
83
+ PATH: process.env['PATH'] ?? '',
84
+ // See runOfflineFullTests.ts for the long-form note — empty HOME
85
+ // makes npm write its cache to literal `~/.npm` in cwd.
86
+ HOME: process.env['HOME'] || '/root',
87
+ USER: process.env['USER'] ?? '',
88
+ NODE_ENV: 'test',
89
+ DATABASE_URL: url,
90
+ DIRECT_URL: url,
91
+ SHOPIFY_API_KEY: env.devClientId,
92
+ SHOPIFY_API_SECRET: env.apiSecret,
93
+ SCOPES: env.scopes,
94
+ SHOPIFY_APP_URL: env.devAppUrl,
95
+ PORT: port,
96
+ HOST: env.devAppUrl,
97
+ };
98
+ console.log('[dev-e2e] prisma migrate deploy…');
99
+ execSync('npx prisma migrate deploy', { stdio: 'inherit', env: backendEnv });
100
+ console.log('');
101
+ console.log('[dev-e2e] booting Remix dev server (vite, no tunnel)…');
102
+ console.log(` Open ${env.devAppUrl} (accept self-signed cert warning once).`);
103
+ console.log(' Ctrl-C to stop.');
104
+ console.log('');
105
+ const dev = spawn('npx', ['vite', '--port', port, '--strictPort', '--host', '0.0.0.0'], {
106
+ stdio: 'inherit',
107
+ env: backendEnv,
108
+ });
109
+ dev.on('exit', (code) => process.exit(code ?? 0));
110
+ process.on('SIGINT', () => dev.kill('SIGINT'));
111
+ process.on('SIGTERM', () => dev.kill('SIGTERM'));
112
+ }
113
+ main().catch((err) => {
114
+ console.error(err);
115
+ process.exit(1);
116
+ });
117
+ //# sourceMappingURL=devE2eBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devE2eBackend.js","sourceRoot":"","sources":["../../src/scripts/devE2eBackend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=devOnlineBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devOnlineBackend.d.ts","sourceRoot":"","sources":["../../src/scripts/devOnlineBackend.ts"],"names":[],"mappings":""}
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Manual run of the online backend WITHOUT Shopify CLI.
4
+ *
5
+ * Used for `npm run test:online:install` (which needs a running backend to
6
+ * complete OAuth) and for local debugging. Mirrors the env-isolation
7
+ * guarantees of runTests.ts but uses a persistent DB
8
+ * (${appName}_online_${user}) instead of an ephemeral UUID one — so OAuth
9
+ * tokens persist across runs.
10
+ *
11
+ * Serves on https://localhost:PORT with a self-signed cert (vite +
12
+ * @vitejs/plugin-basic-ssl). No tunnel, no DNS.
13
+ */
14
+ import { spawn, execSync } from 'node:child_process';
15
+ import { existsSync, readFileSync } from 'node:fs';
16
+ import { resolve } from 'node:path';
17
+ import { loadEnv, printEnvSummary } from '@essential-apps/shopify-test-core';
18
+ import { isPortFree } from '../lib/freePort.js';
19
+ const PG_HOST = 'localhost';
20
+ const PG_PORT = '5432';
21
+ function readAppName() {
22
+ const pkgPath = resolve(process.cwd(), 'package.json');
23
+ if (!existsSync(pkgPath)) {
24
+ throw new Error(`No package.json at ${pkgPath}. Run this from the consuming app's repo root.`);
25
+ }
26
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
27
+ if (!pkg.name)
28
+ throw new Error(`package.json at ${pkgPath} has no \`name\` field.`);
29
+ return pkg.name.replace(/^@[^/]+\//, '');
30
+ }
31
+ function dbExists(name) {
32
+ try {
33
+ execSync(`psql -h ${PG_HOST} -p ${PG_PORT} -lqt | cut -d \\| -f 1 | grep -qw ${name}`, {
34
+ stdio: 'ignore',
35
+ });
36
+ return true;
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ }
42
+ async function main() {
43
+ const env = loadEnv();
44
+ printEnvSummary(env);
45
+ if (!env.apiSecret) {
46
+ throw new Error(`SHOPIFY_API_SECRET is not set in .env.test.\n\n` +
47
+ `Get it from Partner Dashboard → Apps → "${env.devAppHandle}" → ` +
48
+ `Configuration → "Client credentials" → "Reveal client secret".\n` +
49
+ `Paste it into .env.test as SHOPIFY_API_SECRET=...`);
50
+ }
51
+ const appUrl = new URL(env.devAppUrl);
52
+ if (appUrl.hostname !== 'localhost' && appUrl.hostname !== '127.0.0.1') {
53
+ throw new Error(`SHOPIFY_APP_URL must be a localhost URL (https://localhost:PORT). Got: ${env.devAppUrl}`);
54
+ }
55
+ if (appUrl.protocol !== 'https:') {
56
+ throw new Error(`SHOPIFY_APP_URL must use https:// — got ${env.devAppUrl}`);
57
+ }
58
+ const port = appUrl.port || '443';
59
+ if (!(await isPortFree(Number(port)))) {
60
+ throw new Error(`Port ${port} is in use. Find what's there: lsof -i :${port}\n` +
61
+ `Or change SHOPIFY_APP_URL in .env.test to a different port (and update Partner Dashboard).`);
62
+ }
63
+ const appName = readAppName();
64
+ const dbPrefix = (process.env['TEST_ONLINE_DB_NAME_PREFIX'] ?? `${appName}_online`)
65
+ .toLowerCase()
66
+ .replace(/[^a-z0-9_]/g, '_');
67
+ const PERSISTENT_DB_NAME = `${dbPrefix}_${process.env['USER'] ?? 'local'}`;
68
+ const user = process.env['USER'] ?? '';
69
+ const url = `postgresql://${user}@${PG_HOST}:${PG_PORT}/${PERSISTENT_DB_NAME}`;
70
+ console.log(`[dev-online] Persistent DB: ${url}`);
71
+ console.log(`[dev-online] Backend: ${env.devAppUrl} (vite https, self-signed cert)`);
72
+ console.log('');
73
+ if (!dbExists(PERSISTENT_DB_NAME)) {
74
+ console.log(`[dev-online] createdb ${PERSISTENT_DB_NAME}…`);
75
+ execSync(`createdb -h ${PG_HOST} -p ${PG_PORT} ${PERSISTENT_DB_NAME}`, {
76
+ stdio: 'inherit',
77
+ });
78
+ }
79
+ else {
80
+ console.log(`[dev-online] DB ${PERSISTENT_DB_NAME} exists, reusing.`);
81
+ }
82
+ const backendEnv = {
83
+ PATH: process.env['PATH'] ?? '',
84
+ // See runOfflineFullTests.ts for the long-form note — empty HOME
85
+ // makes npm write its cache to literal `~/.npm` in cwd.
86
+ HOME: process.env['HOME'] || '/root',
87
+ USER: process.env['USER'] ?? '',
88
+ NODE_ENV: 'test',
89
+ DATABASE_URL: url,
90
+ DIRECT_URL: url,
91
+ SHOPIFY_API_KEY: env.devClientId,
92
+ SHOPIFY_API_SECRET: env.apiSecret,
93
+ SCOPES: env.scopes,
94
+ SHOPIFY_APP_URL: env.devAppUrl,
95
+ PORT: port,
96
+ HOST: env.devAppUrl,
97
+ };
98
+ console.log('[dev-online] prisma migrate deploy…');
99
+ execSync('npx prisma migrate deploy', { stdio: 'inherit', env: backendEnv });
100
+ console.log('');
101
+ console.log('[dev-online] booting Remix dev server (vite, no tunnel)…');
102
+ console.log(` Open ${env.devAppUrl} (accept self-signed cert warning once).`);
103
+ console.log(' Ctrl-C to stop.');
104
+ console.log('');
105
+ const dev = spawn('npx', ['vite', '--port', port, '--strictPort', '--host', '0.0.0.0'], {
106
+ stdio: 'inherit',
107
+ env: backendEnv,
108
+ });
109
+ dev.on('exit', (code) => process.exit(code ?? 0));
110
+ process.on('SIGINT', () => dev.kill('SIGINT'));
111
+ process.on('SIGTERM', () => dev.kill('SIGTERM'));
112
+ }
113
+ main().catch((err) => {
114
+ console.error(err);
115
+ process.exit(1);
116
+ });
117
+ //# sourceMappingURL=devOnlineBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devOnlineBackend.js","sourceRoot":"","sources":["../../src/scripts/devOnlineBackend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=installApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installApp.d.ts","sourceRoot":"","sources":["../../src/scripts/installApp.ts"],"names":[],"mappings":""}
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Playwright-driven app install onto a registered test store. No
4
+ * human clicking, no Chrome PNA flag toggles.
5
+ *
6
+ * The consuming app's dev backend (e.g. `npm run dev:test-online`) MUST be
7
+ * running so the OAuth callback can hit localhost successfully.
8
+ */
9
+ import { existsSync } from 'node:fs';
10
+ import { parseArgs } from 'node:util';
11
+ import { loadEnv, printEnvSummary, storageStatePath, readRegistry, writeRegistry, } from '@essential-apps/shopify-test-core';
12
+ import { launchStealthBrowser } from '../lib/stealthLaunch.js';
13
+ async function main() {
14
+ const { values } = parseArgs({
15
+ options: {
16
+ shop: { type: 'string' },
17
+ headless: { type: 'boolean', default: false },
18
+ },
19
+ });
20
+ const shop = values.shop?.trim();
21
+ if (!shop) {
22
+ console.error('Usage: npm run test:online:install -- --shop <shop>.myshopify.com');
23
+ process.exit(1);
24
+ }
25
+ const env = loadEnv();
26
+ printEnvSummary(env);
27
+ if (!existsSync(storageStatePath)) {
28
+ throw new Error(`Auth state not found at ${storageStatePath}. Run: npm run test:online:auth`);
29
+ }
30
+ const reg = readRegistry();
31
+ const store = reg.stores.find((s) => s.shop === shop);
32
+ if (!store) {
33
+ throw new Error(`Shop not in registry: ${shop}. Run: npm run test:online:add -- --shop ${shop}`);
34
+ }
35
+ if (store.appInstalled) {
36
+ console.log(`Already marked installed in registry. Skipping.`);
37
+ process.exit(0);
38
+ }
39
+ console.log('');
40
+ console.log(`Prerequisites: \`npm run dev:test-online\` must be running in another terminal.`);
41
+ console.log('');
42
+ // patchright's bundled Chromium (the one stealth engine the suite uses —
43
+ // same as the online storePool fixture + captureAuth) patches the CDP
44
+ // leak Cloudflare keys on, so its challenge fires less. PNA/LNA bypass
45
+ // flags are baked into launchStealthBrowser.
46
+ const browser = await launchStealthBrowser({ headless: values.headless ?? false });
47
+ const context = await browser.newContext({
48
+ storageState: storageStatePath,
49
+ ignoreHTTPSErrors: true,
50
+ viewport: { width: 1400, height: 900 },
51
+ });
52
+ await context.addInitScript(() => {
53
+ Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
54
+ });
55
+ const page = await context.newPage();
56
+ page.on('console', (msg) => {
57
+ if (['error', 'warning'].includes(msg.type())) {
58
+ console.log(`[browser console ${msg.type()}] ${msg.text()}`);
59
+ }
60
+ });
61
+ try {
62
+ // First, load any page on our origin so we can run JS in its context.
63
+ console.log(`[install] Loading ${env.devAppUrl}/auth/login to establish origin context…`);
64
+ await page.goto(`${env.devAppUrl}/auth/login`, { waitUntil: 'domcontentloaded' });
65
+ // POST to /auth/login with shop in form body via native form submit
66
+ // (bypasses Remix's <Form> fetch intercept, browser follows the
67
+ // 30x redirect to admin.shopify.com OAuth natively).
68
+ console.log(`[install] Submitting native POST to /auth/login (shop=${shop})…`);
69
+ await page.evaluate((shopParam) => {
70
+ const form = document.createElement('form');
71
+ form.action = '/auth/login';
72
+ form.method = 'POST';
73
+ const input = document.createElement('input');
74
+ input.name = 'shop';
75
+ input.value = shopParam;
76
+ form.appendChild(input);
77
+ document.body.appendChild(form);
78
+ form.submit();
79
+ }, shop);
80
+ // Wait for navigation away from our localhost origin — POST should
81
+ // redirect to admin.shopify.com or accounts.shopify.com.
82
+ await page.waitForURL((u) => !u.toString().includes('localhost:8181'), {
83
+ timeout: 30_000,
84
+ });
85
+ // Redirect chain can bounce through any combo of:
86
+ // accounts.shopify.com/select → account picker
87
+ // admin.shopify.com/login → no_cookie_session bounce
88
+ // admin.shopify.com/store/X/oauth/install → install consent
89
+ // Keep clicking through until we land on the consent screen.
90
+ for (let i = 0; i < 8; i++) {
91
+ await page.waitForLoadState('domcontentloaded').catch(() => { });
92
+ const url = page.url();
93
+ console.log(`[install] At: ${url}`);
94
+ if (url.includes('accounts.shopify.com/select')) {
95
+ const target = env.accountEmail
96
+ ? page.getByText(env.accountEmail, { exact: false }).first()
97
+ : page.locator('[role="link"], a, button').first();
98
+ await target.click({ timeout: 15_000 });
99
+ await page.waitForURL((u) => !u.toString().includes('/select'), {
100
+ timeout: 30_000,
101
+ });
102
+ continue;
103
+ }
104
+ if (url.includes('admin.shopify.com/login')) {
105
+ // The login page should auto-redirect once cookies settle.
106
+ await page.waitForURL((u) => !u.toString().includes('admin.shopify.com/login'), {
107
+ timeout: 30_000,
108
+ });
109
+ continue;
110
+ }
111
+ // We've landed somewhere stable — break and look for install button
112
+ break;
113
+ }
114
+ // Possible terminal states after the redirect chain:
115
+ // 1. /apps/{handle}* — app already installed at Shopify level. Done.
116
+ // 2. /oauth/install — fresh install, click "Install app".
117
+ // 3. /app/grant — scope change requested, click "Update".
118
+ const url = page.url();
119
+ if (url.includes(`/apps/${env.devAppHandle}`)) {
120
+ console.log(`[install] Landed on app page — installation already complete: ${url}`);
121
+ }
122
+ else if (url.includes('/app/grant')) {
123
+ console.log('[install] Scope grant screen — clicking "Update"…');
124
+ await page.getByRole('button', { name: /^update$/i }).first().click();
125
+ await page.waitForURL((u) => u.toString().includes(`/apps/${env.devAppHandle}`), {
126
+ timeout: 90_000,
127
+ });
128
+ }
129
+ else {
130
+ console.log('[install] Looking for "Install app" button…');
131
+ const installButton = page
132
+ .getByRole('button', { name: /^install app$|^install$/i })
133
+ .first();
134
+ await installButton.waitFor({ state: 'visible', timeout: 60_000 });
135
+ console.log('[install] Clicking "Install app"…');
136
+ await installButton.click();
137
+ console.log('[install] Waiting for OAuth callback + app load…');
138
+ await page.waitForURL((u) => u.toString().includes(`/apps/${env.devAppHandle}`), {
139
+ timeout: 90_000,
140
+ });
141
+ }
142
+ await page.waitForLoadState('domcontentloaded');
143
+ console.log('[install] ✓ Install completed');
144
+ store.appInstalled = true;
145
+ writeRegistry(reg);
146
+ console.log(`[install] Marked ${shop} as installed in registry.`);
147
+ }
148
+ catch (err) {
149
+ console.error(`[install] Failed: ${err.message}`);
150
+ console.error(`Final URL: ${page.url()}`);
151
+ await page.screenshot({ path: 'tests/test-online/install-failure.png' }).catch(() => { });
152
+ console.error('Screenshot: tests/test-online/install-failure.png');
153
+ process.exit(1);
154
+ }
155
+ finally {
156
+ await browser.close();
157
+ }
158
+ }
159
+ main().catch((err) => {
160
+ console.error(err);
161
+ process.exit(1);
162
+ });
163
+ //# sourceMappingURL=installApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installApp.js","sourceRoot":"","sources":["../../src/scripts/installApp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=listStores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listStores.d.ts","sourceRoot":"","sources":["../../src/scripts/listStores.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { readRegistry } from '@essential-apps/shopify-test-core';
3
+ const reg = readRegistry();
4
+ if (reg.stores.length === 0) {
5
+ console.log('Pool is empty. Run: npm run test:online:create -- --count 2');
6
+ process.exit(0);
7
+ }
8
+ console.log(`${reg.stores.length} store(s) in pool:`);
9
+ console.log('');
10
+ for (const s of reg.stores) {
11
+ console.log(` ${s.shop}`);
12
+ console.log(` plan : ${s.plan}`);
13
+ console.log(` created : ${s.createdAt ?? '(unknown)'}`);
14
+ console.log(` installed : ${s.appInstalled}`);
15
+ console.log(` status : ${s.status}`);
16
+ console.log('');
17
+ }
18
+ //# sourceMappingURL=listStores.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listStores.js","sourceRoot":"","sources":["../../src/scripts/listStores.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;AAC3B,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;IAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,oBAAoB,CAAC,CAAC;AACtD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAChB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,SAAS,IAAI,WAAW,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=runDocker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runDocker.d.ts","sourceRoot":"","sources":["../../src/scripts/runDocker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Run e2e tests inside Apple's `container` (libkrun-based microVM).
4
+ *
5
+ * Why: macOS-host Chrome can't be hidden reliably while passing
6
+ * Cloudflare's bot management. Running tests in a Linux microVM means
7
+ * the browser exists entirely off-host — no window flashes ever, fully
8
+ * invisible.
9
+ *
10
+ * Architecture:
11
+ * - Image: ${appName}-e2e:latest (built once via the consuming app's
12
+ * tests/e2e/docker/Dockerfile). Default image name is derived
13
+ * from package.json `name`; override via E2E_IMAGE env var.
14
+ * - Bind mounts:
15
+ * - app repo → /workspace
16
+ * - linux node_modules → /workspace/node_modules (cached)
17
+ * - shopify-test repo → same host path inside the container
18
+ * (so symlinks created by `npm install file:...` resolve
19
+ * identically on host and container)
20
+ * - Postgres starts inside the container via the app's entrypoint.sh.
21
+ * - The shopify-test-run-tests CLI runs unchanged inside the
22
+ * container — its localhost:5432 points at the container's pg,
23
+ * not the host's.
24
+ */
25
+ import { spawn } from 'node:child_process';
26
+ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
27
+ import { homedir } from 'node:os';
28
+ import { resolve } from 'node:path';
29
+ const repoRoot = process.cwd();
30
+ function readAppName() {
31
+ const pkgPath = resolve(repoRoot, 'package.json');
32
+ if (!existsSync(pkgPath)) {
33
+ throw new Error(`No package.json at ${pkgPath}. Run this from the consuming app's repo root.`);
34
+ }
35
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
36
+ if (!pkg.name) {
37
+ throw new Error(`package.json at ${pkgPath} has no \`name\` field.`);
38
+ }
39
+ // Strip any npm scope: @essential-apps/foo → foo
40
+ return pkg.name.replace(/^@[^/]+\//, '');
41
+ }
42
+ async function main() {
43
+ const appName = readAppName();
44
+ const image = process.env['E2E_IMAGE'] ?? `${appName}-e2e:latest`;
45
+ // Linux node_modules cache lives OUTSIDE the project tree so neither
46
+ // tsconfig-paths nor Playwright's test discovery sees it.
47
+ const linuxModules = process.env['E2E_LINUX_NODE_MODULES'] ??
48
+ resolve(homedir(), `.cache/${appName}-e2e/node_modules`);
49
+ mkdirSync(linuxModules, { recursive: true });
50
+ const args = [
51
+ 'run',
52
+ '--rm',
53
+ // amd64 + Rosetta — image bundles Google Chrome (Linux amd64-only).
54
+ // Apple `container` runs amd64 images on Apple Silicon via Rosetta.
55
+ '--arch',
56
+ 'amd64',
57
+ '--memory',
58
+ '8192M',
59
+ '--cpus',
60
+ '4',
61
+ '--mount',
62
+ `type=bind,source=${repoRoot},target=/workspace`,
63
+ '--mount',
64
+ `type=bind,source=${linuxModules},target=/workspace/node_modules`,
65
+ '-w',
66
+ '/workspace',
67
+ image,
68
+ 'bash',
69
+ '-c',
70
+ [
71
+ // Use the .env.test we already have; run the built test runner
72
+ // from the @essential-apps/shopify-test-runner package.
73
+ // PG_HOST=127.0.0.1 inside container points at the container's
74
+ // pg started by entrypoint.sh.
75
+ 'node --env-file=.env.test node_modules/@essential-apps/shopify-test-runner/dist/scripts/runTests.js',
76
+ ].join(' && '),
77
+ ];
78
+ console.log('[runDocker] container run', args.slice(0, 12).join(' '), '…');
79
+ const p = spawn('container', args, { stdio: 'inherit' });
80
+ p.on('exit', (code) => process.exit(code ?? 0));
81
+ process.on('SIGINT', () => p.kill('SIGINT'));
82
+ process.on('SIGTERM', () => p.kill('SIGTERM'));
83
+ }
84
+ main().catch((err) => {
85
+ console.error(err);
86
+ process.exit(1);
87
+ });
88
+ //# sourceMappingURL=runDocker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runDocker.js","sourceRoot":"","sources":["../../src/scripts/runDocker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=runDockerAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runDockerAuth.d.ts","sourceRoot":"","sources":["../../src/scripts/runDockerAuth.ts"],"names":[],"mappings":""}