@shopify/cli-hydrogen 7.1.2 → 8.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 (136) hide show
  1. package/dist/commands/hydrogen/build-vite.js +19 -10
  2. package/dist/commands/hydrogen/build.js +10 -2
  3. package/dist/commands/hydrogen/check.js +1 -0
  4. package/dist/commands/hydrogen/codegen.js +1 -0
  5. package/dist/commands/hydrogen/customer-account/push.js +170 -0
  6. package/dist/commands/hydrogen/debug/cpu.js +3 -0
  7. package/dist/commands/hydrogen/deploy.js +121 -36
  8. package/dist/commands/hydrogen/dev-vite.js +128 -59
  9. package/dist/commands/hydrogen/dev.js +108 -51
  10. package/dist/commands/hydrogen/env/list.js +7 -8
  11. package/dist/commands/hydrogen/env/pull.js +17 -1
  12. package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +23 -50
  13. package/dist/commands/hydrogen/generate/route.js +1 -0
  14. package/dist/commands/hydrogen/init.js +45 -17
  15. package/dist/commands/hydrogen/link.js +20 -4
  16. package/dist/commands/hydrogen/list.js +1 -0
  17. package/dist/commands/hydrogen/login.js +1 -0
  18. package/dist/commands/hydrogen/logout.js +1 -0
  19. package/dist/commands/hydrogen/preview.js +31 -16
  20. package/dist/commands/hydrogen/setup/css.js +8 -1
  21. package/dist/commands/hydrogen/setup/markets.js +1 -0
  22. package/dist/commands/hydrogen/setup/vite.js +244 -138
  23. package/dist/commands/hydrogen/setup.js +21 -22
  24. package/dist/commands/hydrogen/shortcut.js +10 -0
  25. package/dist/commands/hydrogen/unlink.js +1 -0
  26. package/dist/commands/hydrogen/upgrade.js +2 -1
  27. package/dist/generator-templates/assets/vite/package.json +3 -4
  28. package/dist/generator-templates/assets/vite/vite.config.js +10 -2
  29. package/dist/generator-templates/starter/CHANGELOG.md +89 -0
  30. package/dist/generator-templates/starter/README.md +3 -44
  31. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -0
  32. package/dist/generator-templates/starter/app/lib/fragments.ts +2 -0
  33. package/dist/generator-templates/starter/app/root.tsx +2 -5
  34. package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +1 -1
  35. package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
  36. package/dist/generator-templates/starter/app/routes/collections.all.tsx +160 -0
  37. package/dist/generator-templates/starter/app/routes/products.$handle.tsx +1 -2
  38. package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +6 -3
  39. package/dist/generator-templates/starter/{remix.env.d.ts → env.d.ts} +8 -2
  40. package/dist/generator-templates/starter/package.json +14 -9
  41. package/dist/generator-templates/starter/server.ts +2 -1
  42. package/dist/generator-templates/starter/storefrontapi.generated.d.ts +59 -3
  43. package/dist/generator-templates/starter/vite.config.ts +21 -0
  44. package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -3
  45. package/dist/lib/check-lockfile.js +12 -18
  46. package/dist/lib/codegen.js +37 -13
  47. package/dist/lib/common.js +50 -0
  48. package/dist/lib/cpu-profiler.js +4 -1
  49. package/dist/lib/dev-shared.js +97 -0
  50. package/dist/lib/environment-variables.js +51 -30
  51. package/dist/lib/file.js +8 -1
  52. package/dist/lib/flags.js +37 -16
  53. package/dist/lib/graphql/admin/customer-application-update.js +29 -0
  54. package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
  55. package/dist/lib/graphql/admin/list-environments.js +1 -0
  56. package/dist/lib/graphql/admin/pull-variables.js +4 -4
  57. package/dist/lib/graphql/admin/test-helper.js +37 -0
  58. package/dist/lib/log.js +86 -13
  59. package/dist/lib/mini-oxygen/common.js +19 -33
  60. package/dist/lib/mini-oxygen/index.js +6 -2
  61. package/dist/lib/mini-oxygen/node.js +43 -31
  62. package/dist/lib/mini-oxygen/workerd.js +72 -165
  63. package/dist/lib/missing-routes.js +1 -1
  64. package/dist/lib/onboarding/common.js +82 -70
  65. package/dist/lib/onboarding/local.js +19 -9
  66. package/dist/lib/onboarding/remote.js +35 -30
  67. package/dist/lib/package-managers.js +24 -0
  68. package/dist/lib/remix-config.js +17 -1
  69. package/dist/lib/request-events.js +6 -1
  70. package/dist/lib/setups/i18n/replacers.js +9 -6
  71. package/dist/lib/setups/routes/generate.js +1 -0
  72. package/dist/lib/shell.js +2 -1
  73. package/dist/lib/shopify-config.js +19 -1
  74. package/dist/lib/template-diff.js +36 -15
  75. package/dist/lib/template-downloader.js +35 -5
  76. package/dist/lib/transpile/morph/typedefs.js +5 -2
  77. package/dist/lib/transpile/project.js +8 -4
  78. package/dist/lib/tunneling.js +44 -0
  79. package/dist/lib/virtual-routes.js +1 -1
  80. package/dist/lib/vite-config.js +39 -9
  81. package/oclif.manifest.json +711 -498
  82. package/package.json +32 -24
  83. package/dist/commands/hydrogen/deploy.test.js +0 -553
  84. package/dist/commands/hydrogen/env/list.test.js +0 -148
  85. package/dist/commands/hydrogen/env/pull.test.js +0 -207
  86. package/dist/commands/hydrogen/env/push__unstable.test.js +0 -383
  87. package/dist/commands/hydrogen/generate/route.test.js +0 -43
  88. package/dist/commands/hydrogen/init.test.js +0 -641
  89. package/dist/commands/hydrogen/link.test.js +0 -187
  90. package/dist/commands/hydrogen/list.test.js +0 -111
  91. package/dist/commands/hydrogen/setup.test.js +0 -61
  92. package/dist/commands/hydrogen/shortcut.test.js +0 -30
  93. package/dist/commands/hydrogen/unlink.test.js +0 -36
  94. package/dist/commands/hydrogen/upgrade.test.js +0 -786
  95. package/dist/generator-templates/starter/remix.config.js +0 -24
  96. package/dist/lib/auth.test.js +0 -157
  97. package/dist/lib/check-lockfile.test.js +0 -81
  98. package/dist/lib/check-version.test.js +0 -86
  99. package/dist/lib/environment-variables.test.js +0 -149
  100. package/dist/lib/file.test.js +0 -68
  101. package/dist/lib/flags.test.js +0 -43
  102. package/dist/lib/get-oxygen-deployment-data.test.js +0 -120
  103. package/dist/lib/gid.test.js +0 -15
  104. package/dist/lib/graphql/admin/client.test.js +0 -76
  105. package/dist/lib/graphql/admin/create-storefront.test.js +0 -64
  106. package/dist/lib/graphql/admin/link-storefront.test.js +0 -38
  107. package/dist/lib/graphql/admin/list-environments.test.js +0 -44
  108. package/dist/lib/graphql/admin/list-storefronts.test.js +0 -44
  109. package/dist/lib/graphql/admin/pull-variables.test.js +0 -43
  110. package/dist/lib/graphql/business-platform/user-account.test.js +0 -80
  111. package/dist/lib/log.test.js +0 -92
  112. package/dist/lib/mini-oxygen/assets.js +0 -134
  113. package/dist/lib/mini-oxygen/mini-oxygen.test.js +0 -214
  114. package/dist/lib/mini-oxygen/workerd-inspector-logs.js +0 -227
  115. package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +0 -200
  116. package/dist/lib/mini-oxygen/workerd-inspector.js +0 -219
  117. package/dist/lib/missing-routes.test.js +0 -45
  118. package/dist/lib/remix-version-check.test.js +0 -39
  119. package/dist/lib/remix-version-interop.test.js +0 -13
  120. package/dist/lib/setups/i18n/domains.test.js +0 -39
  121. package/dist/lib/setups/i18n/replacers.test.js +0 -261
  122. package/dist/lib/setups/i18n/subdomains.test.js +0 -39
  123. package/dist/lib/setups/i18n/subfolders.test.js +0 -39
  124. package/dist/lib/setups/routes/generate.test.js +0 -296
  125. package/dist/lib/shell.test.js +0 -111
  126. package/dist/lib/shopify-config.test.js +0 -199
  127. package/dist/lib/string.test.js +0 -16
  128. package/dist/lib/virtual-routes.test.js +0 -49
  129. package/dist/lib/vite/hydrogen-middleware.js +0 -82
  130. package/dist/lib/vite/mini-oxygen.js +0 -152
  131. package/dist/lib/vite/plugins.d.ts +0 -27
  132. package/dist/lib/vite/plugins.js +0 -139
  133. package/dist/lib/vite/shared.js +0 -10
  134. package/dist/lib/vite/utils.js +0 -55
  135. package/dist/lib/vite/worker-entry.js +0 -1518
  136. /package/dist/generator-templates/starter/{.eslintrc.js → .eslintrc.cjs} +0 -0
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
- "version": "7.1.2",
7
+ "version": "8.0.0",
8
8
  "license": "MIT",
9
9
  "type": "module",
10
10
  "scripts": {
@@ -21,56 +21,65 @@
21
21
  "@types/fs-extra": "^11.0.1",
22
22
  "@types/gunzip-maybe": "^1.4.0",
23
23
  "@types/prettier": "^2.7.2",
24
- "@types/recursive-readdir": "^2.2.1",
25
- "@types/stack-trace": "^0.0.30",
24
+ "@types/source-map-support": "^0.5.10",
26
25
  "@types/tar-fs": "^2.0.1",
27
- "@types/ws": "^8.5.10",
28
26
  "@vitest/coverage-v8": "^1.0.4",
29
27
  "devtools-protocol": "^0.0.1177611",
30
28
  "fast-glob": "^3.2.12",
31
29
  "flame-chart-js": "2.3.2",
32
30
  "get-port": "^7.0.0",
33
31
  "type-fest": "^4.5.0",
34
- "vite": "~5.1.0",
32
+ "vite": "^5.1.0",
35
33
  "vitest": "^1.0.4"
36
34
  },
37
35
  "dependencies": {
38
36
  "@ast-grep/napi": "0.11.0",
39
- "@graphql-codegen/cli": "5.0.1",
40
- "@oclif/core": "3.15.1",
41
- "@shopify/cli-kit": "3.56.3",
42
- "@shopify/hydrogen-codegen": "^0.2.2",
43
- "@shopify/mini-oxygen": "^2.2.5",
44
- "@shopify/oxygen-cli": "^4.3.0",
37
+ "@oclif/core": "3.19.6",
38
+ "@shopify/cli-kit": "3.58.0",
39
+ "@shopify/oxygen-cli": "~4.4.0",
40
+ "@shopify/plugin-cloudflare": "3.58.0",
45
41
  "ansi-escapes": "^6.2.0",
46
42
  "cli-truncate": "^4.0.0",
47
43
  "diff": "^5.1.0",
48
44
  "fs-extra": "^11.1.0",
49
45
  "get-port": "^7.0.0",
50
- "graphql-config": "5.0.3",
51
46
  "gunzip-maybe": "^1.4.2",
52
- "miniflare": "3.20240129.0",
53
47
  "prettier": "^2.8.4",
54
48
  "semver": "^7.5.3",
55
49
  "source-map": "^0.7.4",
56
- "stack-trace": "^1.0.0-pre2",
50
+ "source-map-support": "^0.5.21",
57
51
  "tar-fs": "^2.1.1",
58
- "tempy": "^3.0.0",
52
+ "tempy": "3.0.0",
59
53
  "ts-morph": "20.0.0",
60
- "use-resize-observer": "^9.1.0",
61
- "ws": "^8.16.0"
54
+ "use-resize-observer": "^9.1.0"
62
55
  },
63
56
  "optionalDependencies": {
64
57
  "@parcel/watcher": "^2.3.0"
65
58
  },
66
59
  "peerDependencies": {
60
+ "@graphql-codegen/cli": "^5.0.2",
67
61
  "@remix-run/dev": "^2.1.0",
68
- "vite": "~5.1.0"
62
+ "@shopify/hydrogen-codegen": "^0.3.0",
63
+ "@shopify/mini-oxygen": "^3.0.0",
64
+ "graphql-config": "^5.0.3",
65
+ "vite": "^5.1.0"
69
66
  },
70
67
  "peerDependenciesMeta": {
68
+ "@graphql-codegen/cli": {
69
+ "optional": true
70
+ },
71
71
  "@remix-run/dev": {
72
72
  "optional": true
73
73
  },
74
+ "@shopify/hydrogen-codegen": {
75
+ "optional": true
76
+ },
77
+ "@shopify/mini-oxygen": {
78
+ "optional": true
79
+ },
80
+ "graphql-config": {
81
+ "optional": true
82
+ },
74
83
  "vite": {
75
84
  "optional": true
76
85
  }
@@ -79,12 +88,8 @@
79
88
  "exports": {
80
89
  "./package.json": "./package.json",
81
90
  "./commands/hydrogen/init": {
82
- "types": "./dist/commands/hydrogen/init.d.ts",
91
+ "types": "./dist/init.d.ts",
83
92
  "default": "./dist/commands/hydrogen/init.js"
84
- },
85
- "./experimental-vite": {
86
- "types": "./dist/lib/vite/plugins.d.ts",
87
- "default": "./dist/lib/vite/plugins.js"
88
93
  }
89
94
  },
90
95
  "files": [
@@ -115,6 +120,9 @@
115
120
  "hydrogen:setup": {
116
121
  "description": "Scaffolds new functionality."
117
122
  }
118
- }
123
+ },
124
+ "plugins": [
125
+ "@shopify/plugin-cloudflare"
126
+ ]
119
127
  }
120
128
  }
@@ -1,553 +0,0 @@
1
- import { vi, describe, expect, beforeEach, afterEach, it } from 'vitest';
2
- import { login } from '../../lib/auth.js';
3
- import { getStorefronts } from '../../lib/graphql/admin/link-storefront.js';
4
- import { readAndParseDotEnv } from '@shopify/cli-kit/node/dot-env';
5
- import { AbortError } from '@shopify/cli-kit/node/error';
6
- import { writeFile } from '@shopify/cli-kit/node/fs';
7
- import { renderSelectPrompt, renderSuccess, renderWarning, renderFatalError } from '@shopify/cli-kit/node/ui';
8
- import { ensureIsClean, GitDirectoryNotCleanError, getLatestGitCommit } from '@shopify/cli-kit/node/git';
9
- import { runDeploy, deploymentLogger } from './deploy.js';
10
- import { getOxygenDeploymentData } from '../../lib/get-oxygen-deployment-data.js';
11
- import { createDeploy, parseToken } from '@shopify/oxygen-cli/deploy';
12
- import { ciPlatform } from '@shopify/cli-kit/node/context/local';
13
- import { runBuild } from './build.js';
14
-
15
- vi.mock("@shopify/oxygen-cli/deploy");
16
- vi.mock("@shopify/cli-kit/node/dot-env");
17
- vi.mock("@shopify/cli-kit/node/fs");
18
- vi.mock("@shopify/cli-kit/node/context/local");
19
- vi.mock("../../lib/get-oxygen-deployment-data.js");
20
- vi.mock("./build.js");
21
- vi.mock("../../lib/auth.js");
22
- vi.mock("../../lib/shopify-config.js");
23
- vi.mock("../../lib/graphql/admin/link-storefront.js");
24
- vi.mock("../../lib/graphql/admin/create-storefront.js");
25
- vi.mock("../../lib/graphql/admin/fetch-job.js");
26
- vi.mock("../../lib/shell.js", () => ({ getCliCommand: () => "h2" }));
27
- vi.mock("@shopify/cli-kit/node/output", async () => {
28
- return {
29
- outputContent: () => ({ value: "" }),
30
- outputInfo: () => {
31
- },
32
- outputWarn: () => {
33
- }
34
- };
35
- });
36
- vi.mock("@shopify/cli-kit/node/ui", async () => {
37
- return {
38
- renderFatalError: vi.fn(),
39
- renderSelectPrompt: vi.fn(),
40
- renderSuccess: vi.fn(),
41
- renderTasks: vi.fn(),
42
- renderWarning: vi.fn()
43
- };
44
- });
45
- vi.mock("@shopify/cli-kit/node/git", async () => {
46
- const actual = await vi.importActual("@shopify/cli-kit/node/git");
47
- return {
48
- ...actual,
49
- getLatestGitCommit: vi.fn(),
50
- ensureIsClean: vi.fn()
51
- };
52
- });
53
- describe("deploy", () => {
54
- const ADMIN_SESSION = {
55
- token: "abc123",
56
- storeFqdn: "my-shop.myshopify.com"
57
- };
58
- const FULL_SHOPIFY_CONFIG = {
59
- shop: "my-shop.myshopify.com",
60
- shopName: "My Shop",
61
- email: "email",
62
- storefront: {
63
- id: "gid://shopify/HydrogenStorefront/1",
64
- title: "Hydrogen"
65
- }
66
- };
67
- const UNLINKED_SHOPIFY_CONFIG = {
68
- ...FULL_SHOPIFY_CONFIG,
69
- storefront: void 0
70
- };
71
- const originalExit = process.exit;
72
- const deployParams = {
73
- authBypassToken: true,
74
- defaultEnvironment: false,
75
- force: false,
76
- noVerify: true,
77
- lockfileCheck: false,
78
- jsonOutput: true,
79
- path: "./",
80
- shop: "snowdevil.myshopify.com",
81
- metadataUrl: "https://example.com",
82
- metadataUser: "user",
83
- metadataVersion: "1.0.0"
84
- };
85
- const mockToken = {
86
- accessToken: "some-token",
87
- allowedResource: "some-resource",
88
- appId: "1",
89
- client: "1",
90
- expiresAt: "some-time",
91
- namespace: "some-namespace",
92
- namespaceId: "1"
93
- };
94
- const expectedConfig = {
95
- assetsDir: "dist/client",
96
- bugsnag: true,
97
- defaultEnvironment: false,
98
- deploymentUrl: "https://oxygen.shopifyapps.com",
99
- deploymentToken: mockToken,
100
- generateAuthBypassToken: true,
101
- verificationMaxDuration: 180,
102
- metadata: {
103
- url: deployParams.metadataUrl,
104
- user: deployParams.metadataUser,
105
- version: deployParams.metadataVersion
106
- },
107
- skipVerification: true,
108
- rootPath: deployParams.path,
109
- skipBuild: false,
110
- workerOnly: false,
111
- workerDir: "dist/worker"
112
- };
113
- const expectedHooks = {
114
- buildFunction: expect.any(Function),
115
- onDeploymentCompleted: expect.any(Function),
116
- onDeploymentFailed: expect.any(Function),
117
- onDeploymentCompletedVerificationError: expect.any(Function),
118
- onVerificationComplete: expect.any(Function),
119
- onVerificationError: expect.any(Function),
120
- onUploadFilesStart: expect.any(Function),
121
- onUploadFilesComplete: expect.any(Function),
122
- onUploadFilesError: expect.any(Function)
123
- };
124
- beforeEach(async () => {
125
- process.exit = vi.fn();
126
- vi.mocked(login).mockResolvedValue({
127
- session: ADMIN_SESSION,
128
- config: UNLINKED_SHOPIFY_CONFIG
129
- });
130
- vi.mocked(ciPlatform).mockReturnValue({ isCI: false });
131
- vi.mocked(getStorefronts).mockResolvedValue([
132
- {
133
- ...FULL_SHOPIFY_CONFIG.storefront,
134
- parsedId: "1",
135
- productionUrl: "https://example.com"
136
- }
137
- ]);
138
- vi.mocked(renderSelectPrompt).mockResolvedValue(FULL_SHOPIFY_CONFIG.shop);
139
- vi.mocked(createDeploy).mockResolvedValue({
140
- authBypassToken: "some-token",
141
- url: "https://a-lovely-deployment.com"
142
- });
143
- vi.mocked(getOxygenDeploymentData).mockResolvedValue({
144
- oxygenDeploymentToken: "some-encoded-token",
145
- environments: []
146
- });
147
- vi.mocked(parseToken).mockReturnValue(mockToken);
148
- });
149
- afterEach(() => {
150
- vi.resetAllMocks();
151
- process.exit = originalExit;
152
- });
153
- it("calls getOxygenDeploymentData with the correct parameters", async () => {
154
- await runDeploy(deployParams);
155
- expect(getOxygenDeploymentData).toHaveBeenCalledWith({
156
- root: "./",
157
- flagShop: "snowdevil.myshopify.com"
158
- });
159
- expect(getOxygenDeploymentData).toHaveBeenCalledTimes(1);
160
- });
161
- it("calls createDeploy with the correct parameters", async () => {
162
- await runDeploy(deployParams);
163
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
164
- config: expectedConfig,
165
- hooks: expectedHooks,
166
- logger: deploymentLogger
167
- });
168
- expect(vi.mocked(renderSuccess)).toHaveBeenCalled;
169
- });
170
- it("calls createDeploy with overridden variables in environment file", async () => {
171
- vi.mocked(readAndParseDotEnv).mockResolvedValue({
172
- path: "fake-env-file",
173
- variables: {
174
- "fake-key": "fake-value"
175
- }
176
- });
177
- await runDeploy({
178
- ...deployParams,
179
- environmentFile: "fake-env-file"
180
- });
181
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
182
- config: {
183
- ...expectedConfig,
184
- overriddenEnvironmentVariables: [
185
- {
186
- key: "fake-key",
187
- value: "fake-value",
188
- isSecret: true
189
- }
190
- ]
191
- },
192
- hooks: expectedHooks,
193
- logger: deploymentLogger
194
- });
195
- });
196
- it("errors when there are uncommited changes", async () => {
197
- vi.mocked(ensureIsClean).mockRejectedValue(
198
- new GitDirectoryNotCleanError("Uncommitted changes")
199
- );
200
- await expect(runDeploy(deployParams)).rejects.toThrowError(
201
- "Uncommitted changes detected"
202
- );
203
- expect(vi.mocked(createDeploy)).not.toHaveBeenCalled;
204
- });
205
- it("proceeds with warning and modified description when there are uncommited changes and the force flag is used", async () => {
206
- vi.mocked(ensureIsClean).mockRejectedValue(
207
- new GitDirectoryNotCleanError("Uncommitted changes")
208
- );
209
- vi.mocked(getLatestGitCommit).mockResolvedValue({
210
- hash: "123",
211
- message: "test commit",
212
- date: "2021-01-01",
213
- author_name: "test author",
214
- author_email: "test@author.com",
215
- body: "test body",
216
- refs: "HEAD -> main"
217
- });
218
- await runDeploy({
219
- ...deployParams,
220
- force: true
221
- });
222
- expect(vi.mocked(renderWarning)).toHaveBeenCalledWith({
223
- headline: "No deployment description provided",
224
- body: expect.anything()
225
- });
226
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
227
- config: {
228
- ...expectedConfig,
229
- environmentTag: "main",
230
- metadata: {
231
- ...expectedConfig.metadata,
232
- description: "123 with additional changes"
233
- }
234
- },
235
- hooks: expectedHooks,
236
- logger: deploymentLogger
237
- });
238
- });
239
- it("proceeds with provided description without warning when there are uncommited changes and the force flag is used", async () => {
240
- vi.mocked(ensureIsClean).mockRejectedValue(
241
- new GitDirectoryNotCleanError("Uncommitted changes")
242
- );
243
- vi.mocked(getLatestGitCommit).mockResolvedValue({
244
- hash: "123",
245
- message: "test commit",
246
- date: "2021-01-01",
247
- author_name: "test author",
248
- author_email: "test@author.com",
249
- body: "test body",
250
- refs: "HEAD -> main"
251
- });
252
- await runDeploy({
253
- ...deployParams,
254
- force: true,
255
- metadataDescription: "cool new stuff"
256
- });
257
- expect(vi.mocked(renderWarning)).not.toHaveBeenCalled;
258
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
259
- config: {
260
- ...expectedConfig,
261
- environmentTag: "main",
262
- metadata: {
263
- ...expectedConfig.metadata,
264
- description: "cool new stuff"
265
- }
266
- },
267
- hooks: expectedHooks,
268
- logger: deploymentLogger
269
- });
270
- });
271
- it("calls createDeploy with the checked out branch name", async () => {
272
- vi.mocked(getLatestGitCommit).mockResolvedValue({
273
- hash: "123",
274
- message: "test commit",
275
- date: "2021-01-01",
276
- author_name: "test author",
277
- author_email: "test@author.com",
278
- body: "test body",
279
- refs: "HEAD -> main"
280
- });
281
- await runDeploy(deployParams);
282
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
283
- config: { ...expectedConfig, environmentTag: "main" },
284
- hooks: expectedHooks,
285
- logger: deploymentLogger
286
- });
287
- expect(vi.mocked(renderSuccess)).toHaveBeenCalled;
288
- });
289
- it("calls renderSelectPrompt when there are multiple environments", async () => {
290
- vi.mocked(getOxygenDeploymentData).mockResolvedValue({
291
- oxygenDeploymentToken: "some-encoded-token",
292
- environments: [
293
- { name: "Production", branch: "main", type: "PRODUCTION" },
294
- { name: "Preview", branch: null, type: "PREVIEW" }
295
- ]
296
- });
297
- await runDeploy(deployParams);
298
- expect(vi.mocked(renderSelectPrompt)).toHaveBeenCalledWith({
299
- message: "Select an environment to deploy to",
300
- choices: [
301
- { label: "Production", value: "main" },
302
- { label: "Preview", value: "shopify-preview-environment." }
303
- ]
304
- });
305
- });
306
- describe("when Preview is selected", () => {
307
- it("calls createDeploy with defaultEnvironment and an undefined environmentTag", async () => {
308
- vi.mocked(getLatestGitCommit).mockResolvedValue({
309
- hash: "123",
310
- message: "test commit",
311
- date: "2021-01-01",
312
- author_name: "test author",
313
- author_email: "test@author.com",
314
- body: "test body",
315
- refs: "HEAD -> main"
316
- });
317
- vi.mocked(getOxygenDeploymentData).mockResolvedValue({
318
- oxygenDeploymentToken: "some-encoded-token",
319
- environments: [
320
- { name: "Production", branch: "main", type: "PRODUCTION" },
321
- { name: "Preview", branch: null, type: "PREVIEW" }
322
- ]
323
- });
324
- vi.mocked(renderSelectPrompt).mockResolvedValue(
325
- "shopify-preview-environment."
326
- );
327
- await runDeploy(deployParams);
328
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
329
- config: {
330
- ...expectedConfig,
331
- defaultEnvironment: true,
332
- environmentTag: void 0
333
- },
334
- hooks: expectedHooks,
335
- logger: deploymentLogger
336
- });
337
- });
338
- });
339
- it("passes the lockfileCheck to the build function when the flag is set", async () => {
340
- const params = {
341
- ...deployParams,
342
- lockfileCheck: false
343
- };
344
- vi.mocked(createDeploy).mockImplementationOnce((options) => {
345
- options.hooks?.buildFunction?.("some-cool-asset-path");
346
- return new Promise((resolve, _reject) => {
347
- resolve({ url: "https://a-lovely-deployment.com" });
348
- });
349
- });
350
- await runDeploy(params);
351
- expect(vi.mocked(runBuild)).toHaveBeenCalledWith({
352
- assetPath: "some-cool-asset-path",
353
- directory: params.path,
354
- lockfileCheck: false,
355
- sourcemap: true,
356
- useCodegen: false
357
- });
358
- });
359
- it("passes a build command to createDeploy when the build-command flag is used", async () => {
360
- const params = {
361
- ...deployParams,
362
- buildCommand: "hocus pocus"
363
- };
364
- const { buildFunction: _, ...hooks } = expectedHooks;
365
- await runDeploy(params);
366
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
367
- config: {
368
- ...expectedConfig,
369
- buildCommand: "hocus pocus"
370
- },
371
- hooks,
372
- logger: deploymentLogger
373
- });
374
- });
375
- it("writes a file with JSON content in CI environments", async () => {
376
- vi.mocked(ciPlatform).mockReturnValue({
377
- isCI: true,
378
- name: "github",
379
- metadata: {}
380
- });
381
- const ciDeployParams = {
382
- ...deployParams,
383
- token: "some-token",
384
- metadataDescription: "cool new stuff",
385
- generateAuthBypassToken: true
386
- };
387
- await runDeploy(ciDeployParams);
388
- expect(vi.mocked(writeFile)).toHaveBeenCalledWith(
389
- "h2_deploy_log.json",
390
- JSON.stringify({
391
- authBypassToken: "some-token",
392
- url: "https://a-lovely-deployment.com"
393
- })
394
- );
395
- vi.mocked(writeFile).mockClear();
396
- ciDeployParams.jsonOutput = false;
397
- await runDeploy(ciDeployParams);
398
- expect(vi.mocked(writeFile)).not.toHaveBeenCalled();
399
- });
400
- it("handles error during uploadFiles", async () => {
401
- const mockRenderFatalError = vi.fn();
402
- vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
403
- const error = new Error("Wonky internet!");
404
- vi.mocked(createDeploy).mockImplementation((options) => {
405
- options.hooks?.onUploadFilesStart?.();
406
- options.hooks?.onUploadFilesError?.(error);
407
- return new Promise((_resolve, reject) => {
408
- reject(error);
409
- });
410
- });
411
- try {
412
- await runDeploy(deployParams);
413
- expect(true).toBe(false);
414
- } catch (err) {
415
- if (err instanceof AbortError) {
416
- expect(err.message).toBe(error.message);
417
- expect(err.tryMessage).toBe(
418
- "Check your connection and try again. If the problem persists, try again later or contact support."
419
- );
420
- } else {
421
- expect(true).toBe(false);
422
- }
423
- }
424
- });
425
- it("handles error during deployment routability verification", async () => {
426
- const mockRenderFatalError = vi.fn();
427
- vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
428
- const error = new Error("Cloudflare is down!");
429
- vi.mocked(createDeploy).mockImplementation((options) => {
430
- options.hooks?.onUploadFilesStart?.();
431
- options.hooks?.onUploadFilesComplete?.();
432
- options.hooks?.onVerificationError?.(error);
433
- return new Promise((_resolve, reject) => {
434
- reject(error);
435
- });
436
- });
437
- try {
438
- await runDeploy(deployParams);
439
- expect(true).toBe(false);
440
- } catch (err) {
441
- if (err instanceof AbortError) {
442
- expect(err.message).toBe(error.message);
443
- expect(err.tryMessage).toBe(
444
- "Please verify the deployment status in the Shopify Admin and retry deploying if necessary."
445
- );
446
- } else {
447
- expect(true).toBe(false);
448
- }
449
- }
450
- });
451
- it("handles error during deployment completion verification", async () => {
452
- const mockRenderFatalError = vi.fn();
453
- vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
454
- vi.mocked(createDeploy).mockImplementation((options) => {
455
- options.hooks?.onUploadFilesStart?.();
456
- options.hooks?.onUploadFilesComplete?.();
457
- options.hooks?.onDeploymentCompletedVerificationStart?.();
458
- options.hooks?.onDeploymentFailed?.({
459
- status: "oh shit",
460
- url: "https://a-lovely-deployment.com"
461
- });
462
- return new Promise((_resolve, reject) => {
463
- reject();
464
- });
465
- });
466
- try {
467
- await runDeploy(deployParams);
468
- expect(true).toBe(false);
469
- } catch (err) {
470
- if (err instanceof AbortError) {
471
- expect(err.message).toBe("oh shit");
472
- expect(err.tryMessage).toBe("Retrying the deployment may succeed.");
473
- } else {
474
- expect(true).toBe(false);
475
- }
476
- }
477
- });
478
- describe("next steps", () => {
479
- it("renders a link to the deployment", async () => {
480
- vi.mocked(createDeploy).mockResolvedValue({
481
- url: "https://a-lovely-deployment.com"
482
- });
483
- await runDeploy(deployParams);
484
- expect(vi.mocked(renderSuccess)).toHaveBeenCalledWith({
485
- body: ["Successfully deployed to Oxygen"],
486
- nextSteps: [
487
- [
488
- "Open",
489
- { link: { url: "https://a-lovely-deployment.com" } },
490
- "in your browser to view your deployment."
491
- ]
492
- ]
493
- });
494
- });
495
- it("renders a link to the deployment and shows auth bypass token when one is created", async () => {
496
- vi.mocked(createDeploy).mockResolvedValue({
497
- url: "https://a-lovely-deployment.com",
498
- authBypassToken: "some-token"
499
- });
500
- await runDeploy(deployParams);
501
- expect(vi.mocked(renderSuccess)).toHaveBeenCalledWith({
502
- body: ["Successfully deployed to Oxygen"],
503
- nextSteps: [
504
- [
505
- "Open",
506
- { link: { url: "https://a-lovely-deployment.com" } },
507
- "in your browser to view your deployment."
508
- ],
509
- [
510
- "Use the",
511
- { subdued: "some-token" },
512
- "token to perform end-to-end tests against the deployment."
513
- ]
514
- ]
515
- });
516
- });
517
- describe("when in a CI environment", () => {
518
- it("renders information about h2_deploy_log.json", async () => {
519
- vi.mocked(ciPlatform).mockReturnValue({
520
- isCI: true,
521
- name: "github",
522
- metadata: {}
523
- });
524
- await runDeploy({ ...deployParams, token: "fake-token" });
525
- expect(vi.mocked(renderSuccess)).toHaveBeenCalledWith({
526
- body: ["Successfully deployed to Oxygen"],
527
- nextSteps: [
528
- [
529
- "View the deployment information in",
530
- { subdued: "h2_deploy_log.json" }
531
- ]
532
- ]
533
- });
534
- });
535
- it("renders no next steps if jsonOutput is set to false", async () => {
536
- vi.mocked(ciPlatform).mockReturnValue({
537
- isCI: true,
538
- name: "github",
539
- metadata: {}
540
- });
541
- await runDeploy({
542
- ...deployParams,
543
- token: "fake-token",
544
- jsonOutput: false
545
- });
546
- expect(vi.mocked(renderSuccess)).toHaveBeenCalledWith({
547
- body: ["Successfully deployed to Oxygen"],
548
- nextSteps: []
549
- });
550
- });
551
- });
552
- });
553
- });