@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
@@ -1,24 +0,0 @@
1
- /** @type {import('@remix-run/dev').AppConfig} */
2
- module.exports = {
3
- appDirectory: 'app',
4
- ignoredRouteFiles: ['**/.*'],
5
- watchPaths: ['./public', './.env'],
6
- server: './server.ts',
7
- /**
8
- * The following settings are required to deploy Hydrogen apps to Oxygen:
9
- */
10
- publicPath: (process.env.HYDROGEN_ASSET_BASE_URL ?? '/') + 'build/',
11
- assetsBuildDirectory: 'dist/client/build',
12
- serverBuildPath: 'dist/worker/index.js',
13
- serverMainFields: ['browser', 'module', 'main'],
14
- serverConditions: ['worker', process.env.NODE_ENV],
15
- serverDependenciesToBundle: 'all',
16
- serverModuleFormat: 'esm',
17
- serverPlatform: 'neutral',
18
- serverMinify: process.env.NODE_ENV === 'production',
19
- future: {
20
- v3_fetcherPersist: true,
21
- v3_relativeSplatpath: true,
22
- v3_throwAbortReason: true,
23
- },
24
- };
@@ -1,157 +0,0 @@
1
- import { vi, describe, beforeEach, afterEach, it, expect } from 'vitest';
2
- import { ensureAuthenticatedAdmin, ensureAuthenticatedBusinessPlatform } from '@shopify/cli-kit/node/session';
3
- import { renderSelectPrompt } from '@shopify/cli-kit/node/ui';
4
- import { AbortError } from '@shopify/cli-kit/node/error';
5
- import { login } from './auth.js';
6
- import { getUserAccount } from './graphql/business-platform/user-account.js';
7
- import { setUserAccount, getConfig } from './shopify-config.js';
8
-
9
- vi.mock("@shopify/cli-kit/node/session");
10
- vi.mock("@shopify/cli-kit/node/ui");
11
- vi.mock("./graphql/business-platform/user-account.js");
12
- vi.mock("./shopify-config.js");
13
- describe("auth", () => {
14
- const EMAIL = "email";
15
- const SHOP = "my-shop";
16
- const SHOP_DOMAIN = SHOP + ".myshopify.com";
17
- const SHOP_NAME = "My Shop";
18
- const TOKEN = "abc123";
19
- const ROOT = "path/to/project";
20
- const SHOPIFY_CONFIG = {
21
- shop: SHOP_DOMAIN,
22
- shopName: SHOP_NAME,
23
- email: EMAIL
24
- };
25
- const EXPECTED_LOGIN_RESULT = {
26
- config: { shop: SHOP_DOMAIN, shopName: SHOP_NAME, email: EMAIL },
27
- session: {
28
- token: TOKEN,
29
- storeFqdn: SHOP_DOMAIN
30
- }
31
- };
32
- beforeEach(() => {
33
- vi.mocked(setUserAccount).mockImplementation(
34
- (root, account) => Promise.resolve(account)
35
- );
36
- vi.mocked(ensureAuthenticatedAdmin).mockImplementation(
37
- (shop) => Promise.resolve({ token: TOKEN, storeFqdn: shop })
38
- );
39
- vi.mocked(ensureAuthenticatedBusinessPlatform).mockResolvedValue("bp123");
40
- vi.mocked(getUserAccount).mockResolvedValue({
41
- email: "email",
42
- activeShops: [{ name: SHOP_NAME, fqdn: SHOP_DOMAIN }]
43
- });
44
- vi.mocked(getConfig).mockResolvedValue({});
45
- vi.mocked(renderSelectPrompt).mockResolvedValue({
46
- fqdn: SHOP_DOMAIN,
47
- name: SHOP_NAME
48
- });
49
- });
50
- afterEach(() => {
51
- vi.resetAllMocks();
52
- });
53
- describe("login", () => {
54
- it("throws an error when it fails to authenticate", async () => {
55
- vi.mocked(ensureAuthenticatedBusinessPlatform).mockRejectedValueOnce({});
56
- await expect(login(ROOT)).rejects.toThrow(AbortError);
57
- vi.mocked(ensureAuthenticatedAdmin).mockRejectedValueOnce({});
58
- await expect(login(ROOT, SHOP)).rejects.toThrow(AbortError);
59
- });
60
- it("reads shop from local config", async () => {
61
- vi.mocked(getConfig).mockResolvedValue(SHOPIFY_CONFIG);
62
- const result = await login(ROOT);
63
- expect(ensureAuthenticatedBusinessPlatform).not.toHaveBeenCalled();
64
- expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith(SHOP_DOMAIN);
65
- expect(setUserAccount).toHaveBeenCalledWith(
66
- ROOT,
67
- expect.objectContaining({ shop: SHOP_DOMAIN })
68
- );
69
- expect(result).toStrictEqual(EXPECTED_LOGIN_RESULT);
70
- });
71
- it("uses the shop flag argument when passed", async () => {
72
- const ANOTHER_SHOP = "another-shop";
73
- const ANOTHER_SHOP_DOMAIN = "another-shop.myshopify.com";
74
- const ANOTHER_SHOP_NAME = "ANOTHER SHOP";
75
- vi.mocked(getConfig).mockResolvedValue(SHOPIFY_CONFIG);
76
- vi.mocked(renderSelectPrompt).mockResolvedValue({
77
- fqdn: ANOTHER_SHOP_DOMAIN,
78
- name: ANOTHER_SHOP_NAME
79
- });
80
- const result = await login(ROOT, ANOTHER_SHOP);
81
- expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith(
82
- ANOTHER_SHOP_DOMAIN
83
- );
84
- expect(setUserAccount).toHaveBeenCalledWith(
85
- ROOT,
86
- expect.objectContaining({ shop: ANOTHER_SHOP_DOMAIN })
87
- );
88
- expect(result).toStrictEqual({
89
- config: {
90
- shop: ANOTHER_SHOP_DOMAIN,
91
- shopName: ANOTHER_SHOP_NAME,
92
- email: EMAIL
93
- },
94
- session: {
95
- storeFqdn: ANOTHER_SHOP_DOMAIN,
96
- token: TOKEN
97
- }
98
- });
99
- });
100
- it("writes shop to local config and returns it with the admin session", async () => {
101
- const result = await login(ROOT, SHOP);
102
- expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith(SHOP_DOMAIN);
103
- expect(setUserAccount).toHaveBeenCalledWith(
104
- ROOT,
105
- expect.objectContaining({ shop: SHOP_DOMAIN })
106
- );
107
- expect(result).toStrictEqual(EXPECTED_LOGIN_RESULT);
108
- });
109
- it("prompts for shop is not found in arguments and local config", async () => {
110
- const result = await login(ROOT);
111
- expect(ensureAuthenticatedBusinessPlatform).toHaveBeenCalled();
112
- expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith(SHOP_DOMAIN);
113
- expect(setUserAccount).toHaveBeenCalledWith(
114
- ROOT,
115
- expect.objectContaining({ shop: SHOP_DOMAIN })
116
- );
117
- expect(renderSelectPrompt).toHaveBeenCalledWith({
118
- message: expect.any(String),
119
- choices: [
120
- {
121
- label: expect.stringContaining(SHOP_DOMAIN),
122
- value: { fqdn: SHOP_DOMAIN, name: SHOP_NAME }
123
- }
124
- ]
125
- });
126
- expect(result).toStrictEqual(EXPECTED_LOGIN_RESULT);
127
- });
128
- it("ignores local config and forces prompt when indicated", async () => {
129
- vi.mocked(getConfig).mockResolvedValue(SHOPIFY_CONFIG);
130
- const result = await login(ROOT, true);
131
- expect(ensureAuthenticatedBusinessPlatform).toHaveBeenCalled();
132
- expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith(SHOP_DOMAIN);
133
- expect(setUserAccount).toHaveBeenCalledWith(
134
- ROOT,
135
- expect.objectContaining({ shop: SHOP_DOMAIN })
136
- );
137
- expect(renderSelectPrompt).toHaveBeenCalledWith({
138
- message: expect.any(String),
139
- choices: [
140
- {
141
- label: expect.stringContaining(SHOP_DOMAIN),
142
- value: { fqdn: SHOP_DOMAIN, name: SHOP_NAME }
143
- }
144
- ]
145
- });
146
- expect(result).toStrictEqual(EXPECTED_LOGIN_RESULT);
147
- });
148
- it("skips config steps when root argument is not passed", async () => {
149
- const result = await login();
150
- expect(ensureAuthenticatedBusinessPlatform).toHaveBeenCalled();
151
- expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith(SHOP_DOMAIN);
152
- expect(getConfig).not.toHaveBeenCalled();
153
- expect(setUserAccount).not.toHaveBeenCalled();
154
- expect(result).toStrictEqual(EXPECTED_LOGIN_RESULT);
155
- });
156
- });
157
- });
@@ -1,81 +0,0 @@
1
- import { checkLockfileStatus } from './check-lockfile.js';
2
- import { describe, vi, beforeEach, afterEach, it, expect } from 'vitest';
3
- import { inTemporaryDirectory, writeFile } from '@shopify/cli-kit/node/fs';
4
- import { joinPath } from '@shopify/cli-kit/node/path';
5
- import { checkIfIgnoredInGitRepository } from '@shopify/cli-kit/node/git';
6
- import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
7
-
8
- describe("checkLockfileStatus()", () => {
9
- const checkIgnoreMock = vi.fn();
10
- const outputMock = mockAndCaptureOutput();
11
- beforeEach(() => {
12
- vi.mock("@shopify/cli-kit/node/git");
13
- vi.mocked(checkIfIgnoredInGitRepository).mockImplementation(
14
- checkIgnoreMock
15
- );
16
- vi.mocked(checkIgnoreMock).mockResolvedValue([]);
17
- });
18
- afterEach(() => {
19
- vi.restoreAllMocks();
20
- outputMock.clear();
21
- });
22
- describe("when a lockfile is present", () => {
23
- it("does not call displayLockfileWarning", async () => {
24
- await inTemporaryDirectory(async (tmpDir) => {
25
- await writeFile(joinPath(tmpDir, "package-lock.json"), "");
26
- await checkLockfileStatus(tmpDir);
27
- expect(outputMock.warn()).toBe("");
28
- });
29
- });
30
- describe("and it is being ignored by Git", () => {
31
- beforeEach(() => {
32
- vi.mocked(checkIgnoreMock).mockResolvedValue(["package-lock.json"]);
33
- });
34
- it("renders a warning", async () => {
35
- await inTemporaryDirectory(async (tmpDir) => {
36
- await writeFile(joinPath(tmpDir, "package-lock.json"), "");
37
- await checkLockfileStatus(tmpDir);
38
- expect(outputMock.warn()).toMatch(
39
- / warning .+ Lockfile ignored by Git .+/is
40
- );
41
- });
42
- });
43
- });
44
- });
45
- describe("when there are multiple lockfiles", () => {
46
- it("renders a warning", async () => {
47
- await inTemporaryDirectory(async (tmpDir) => {
48
- await writeFile(joinPath(tmpDir, "package-lock.json"), "");
49
- await writeFile(joinPath(tmpDir, "pnpm-lock.yaml"), "");
50
- await checkLockfileStatus(tmpDir);
51
- expect(outputMock.warn()).toMatch(
52
- / warning .+ Multiple lockfiles found .+/is
53
- );
54
- });
55
- });
56
- it("throws when shouldExit is true", async () => {
57
- await inTemporaryDirectory(async (tmpDir) => {
58
- await writeFile(joinPath(tmpDir, "package-lock.json"), "");
59
- await writeFile(joinPath(tmpDir, "pnpm-lock.yaml"), "");
60
- await expect(checkLockfileStatus(tmpDir, true)).rejects.toThrow(
61
- /Multiple lockfiles found/is
62
- );
63
- });
64
- });
65
- });
66
- describe("when a lockfile is missing", () => {
67
- it("renders a warning", async () => {
68
- await inTemporaryDirectory(async (tmpDir) => {
69
- await checkLockfileStatus(tmpDir);
70
- expect(outputMock.warn()).toMatch(/ warning .+ No lockfile found .+/is);
71
- });
72
- });
73
- it("throws when shouldExit is true", async () => {
74
- await inTemporaryDirectory(async (tmpDir) => {
75
- await expect(checkLockfileStatus(tmpDir, true)).rejects.toThrow(
76
- /No lockfile found/is
77
- );
78
- });
79
- });
80
- });
81
- });
@@ -1,86 +0,0 @@
1
- import { checkHydrogenVersion } from './check-version.js';
2
- import { vi, describe, afterEach, it, expect, beforeEach } from 'vitest';
3
- import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
4
- import { checkForNewVersion } from '@shopify/cli-kit/node/node-package-manager';
5
-
6
- vi.mock("@shopify/cli-kit/node/node-package-manager", () => {
7
- return {
8
- checkForNewVersion: vi.fn()
9
- };
10
- });
11
- const requireMock = vi.fn();
12
- vi.mock("node:module", async () => {
13
- const { createRequire } = await vi.importActual(
14
- "node:module"
15
- );
16
- return {
17
- createRequire: (url) => {
18
- const actualRequire = createRequire(url);
19
- requireMock.mockImplementation((mod) => actualRequire(mod));
20
- const require2 = requireMock;
21
- require2.resolve = actualRequire.resolve.bind(actualRequire);
22
- return require2;
23
- }
24
- };
25
- });
26
- describe("checkHydrogenVersion()", () => {
27
- const outputMock = mockAndCaptureOutput();
28
- afterEach(() => {
29
- vi.restoreAllMocks();
30
- outputMock.clear();
31
- });
32
- describe("when a current version is available", () => {
33
- it("calls checkForNewVersion", async () => {
34
- await checkHydrogenVersion("dir");
35
- expect(checkForNewVersion).toHaveBeenCalledWith(
36
- "@shopify/hydrogen",
37
- // Calver
38
- expect.stringMatching(/20\d{2}\.\d{1,2}\.\d{1,3}/)
39
- );
40
- });
41
- describe("and it is up to date", () => {
42
- beforeEach(() => {
43
- vi.mocked(checkForNewVersion).mockResolvedValue(void 0);
44
- });
45
- it("returns undefined", async () => {
46
- expect(await checkHydrogenVersion("dir")).toBe(void 0);
47
- });
48
- });
49
- describe("and it is using @next", () => {
50
- it("returns undefined", async () => {
51
- vi.mocked(checkForNewVersion).mockResolvedValue("2023.1.5");
52
- vi.mocked(requireMock).mockReturnValueOnce({
53
- version: "0.0.0-next-a188915-20230713115118"
54
- });
55
- expect(await checkHydrogenVersion("dir")).toBe(void 0);
56
- });
57
- });
58
- describe("and a new version is available", () => {
59
- beforeEach(() => {
60
- vi.mocked(checkForNewVersion).mockResolvedValue("2023.1.5");
61
- });
62
- it("returns a function", async () => {
63
- expect(await checkHydrogenVersion("dir")).toBeInstanceOf(Function);
64
- });
65
- it("outputs a message to the user with the new version", async () => {
66
- const showUpgrade = await checkHydrogenVersion("dir");
67
- const { currentVersion, newVersion } = showUpgrade();
68
- expect(outputMock.info()).toMatch(
69
- new RegExp(
70
- ` info .+ Upgrade available .+ Version ${newVersion.replaceAll(
71
- ".",
72
- "\\."
73
- )}.+ running v${currentVersion.replaceAll(".", "\\.")}`,
74
- "is"
75
- )
76
- );
77
- });
78
- });
79
- });
80
- describe("when no current version can be found", () => {
81
- it("returns undefined and does not call checkForNewVersion", async () => {
82
- expect(await checkHydrogenVersion("/fake-absolute-dir")).toBe(void 0);
83
- expect(checkForNewVersion).not.toHaveBeenCalled();
84
- });
85
- });
86
- });
@@ -1,149 +0,0 @@
1
- import { vi, describe, beforeEach, afterEach, it, expect } from 'vitest';
2
- import { inTemporaryDirectory, writeFile } from '@shopify/cli-kit/node/fs';
3
- import { joinPath } from '@shopify/cli-kit/node/path';
4
- import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
5
- import { getAllEnvironmentVariables } from './environment-variables.js';
6
- import { getStorefrontEnvVariables } from './graphql/admin/pull-variables.js';
7
- import { login } from './auth.js';
8
-
9
- vi.mock("./auth.js");
10
- vi.mock("./graphql/admin/pull-variables.js");
11
- describe("getAllEnvironmentVariables()", () => {
12
- const ADMIN_SESSION = {
13
- token: "abc123",
14
- storeFqdn: "my-shop"
15
- };
16
- const SHOPIFY_CONFIG = {
17
- shop: "my-shop",
18
- shopName: "My Shop",
19
- email: "email",
20
- storefront: {
21
- id: "gid://shopify/HydrogenStorefront/1",
22
- title: "Hydrogen"
23
- }
24
- };
25
- beforeEach(() => {
26
- vi.mocked(login).mockResolvedValue({
27
- session: ADMIN_SESSION,
28
- config: SHOPIFY_CONFIG
29
- });
30
- vi.mocked(getStorefrontEnvVariables).mockResolvedValue({
31
- id: SHOPIFY_CONFIG.storefront.id,
32
- environmentVariables: [
33
- {
34
- id: "gid://shopify/HydrogenStorefrontEnvironmentVariable/1",
35
- key: "PUBLIC_API_TOKEN",
36
- value: "abc123",
37
- isSecret: false,
38
- readOnly: false
39
- }
40
- ]
41
- });
42
- });
43
- afterEach(() => {
44
- vi.resetAllMocks();
45
- mockAndCaptureOutput().clear();
46
- });
47
- it("calls pullRemoteEnvironmentVariables", async () => {
48
- await inTemporaryDirectory(async (tmpDir) => {
49
- await getAllEnvironmentVariables({
50
- envBranch: "main",
51
- root: tmpDir
52
- });
53
- expect(getStorefrontEnvVariables).toHaveBeenCalledWith(
54
- ADMIN_SESSION,
55
- SHOPIFY_CONFIG.storefront.id,
56
- "main"
57
- );
58
- });
59
- });
60
- it("does not call pullRemoteEnvironmentVariables when indicated", async () => {
61
- await inTemporaryDirectory(async (tmpDir) => {
62
- await getAllEnvironmentVariables({
63
- envBranch: "main",
64
- root: tmpDir,
65
- fetchRemote: false
66
- });
67
- expect(getStorefrontEnvVariables).not.toHaveBeenCalled();
68
- });
69
- });
70
- it("renders a message about injection", async () => {
71
- await inTemporaryDirectory(async (tmpDir) => {
72
- const outputMock = mockAndCaptureOutput();
73
- await getAllEnvironmentVariables({ root: tmpDir });
74
- expect(outputMock.info()).toMatch(
75
- /Environment variables injected into MiniOxygen:/
76
- );
77
- });
78
- });
79
- it("lists all of the variables being used", async () => {
80
- await inTemporaryDirectory(async (tmpDir) => {
81
- const outputMock = mockAndCaptureOutput();
82
- await getAllEnvironmentVariables({ root: tmpDir });
83
- expect(outputMock.info()).toMatch(/PUBLIC_API_TOKEN\s+from Oxygen/);
84
- });
85
- });
86
- it("doest not fail on network errors", async () => {
87
- await inTemporaryDirectory(async (tmpDir) => {
88
- vi.mocked(getStorefrontEnvVariables).mockRejectedValue(
89
- new Error("Network error")
90
- );
91
- const outputMock = mockAndCaptureOutput();
92
- await getAllEnvironmentVariables({ root: tmpDir });
93
- expect(outputMock.info()).not.toMatch(/PUBLIC_API_TOKEN\s+from Oxygen/);
94
- expect(outputMock.warn()).toMatch(/failed to load/i);
95
- });
96
- });
97
- describe("when one of the variables is a secret", () => {
98
- beforeEach(() => {
99
- vi.mocked(getStorefrontEnvVariables).mockResolvedValue({
100
- id: SHOPIFY_CONFIG.storefront.id,
101
- environmentVariables: [
102
- {
103
- id: "gid://shopify/HydrogenStorefrontEnvironmentVariable/1",
104
- key: "PUBLIC_API_TOKEN",
105
- value: "",
106
- isSecret: true,
107
- readOnly: false
108
- }
109
- ]
110
- });
111
- });
112
- it("uses special messaging to alert the user", async () => {
113
- await inTemporaryDirectory(async (tmpDir) => {
114
- const outputMock = mockAndCaptureOutput();
115
- await getAllEnvironmentVariables({ root: tmpDir });
116
- expect(outputMock.info()).toMatch(
117
- /PUBLIC_API_TOKEN\s+from Oxygen \(Marked as secret\)/
118
- );
119
- });
120
- });
121
- });
122
- describe("when there are local variables", () => {
123
- it("includes local variables in the list", async () => {
124
- await inTemporaryDirectory(async (tmpDir) => {
125
- const filePath = joinPath(tmpDir, ".env");
126
- await writeFile(filePath, "LOCAL_TOKEN=1");
127
- const outputMock = mockAndCaptureOutput();
128
- await getAllEnvironmentVariables({ root: tmpDir });
129
- expect(outputMock.info()).toMatch(/LOCAL_TOKEN\s+from local \.env/);
130
- });
131
- });
132
- describe("and they overwrite remote variables", () => {
133
- it("uses special messaging to alert the user", async () => {
134
- await inTemporaryDirectory(async (tmpDir) => {
135
- const filePath = joinPath(tmpDir, ".env");
136
- await writeFile(filePath, "PUBLIC_API_TOKEN=abc");
137
- const outputMock = mockAndCaptureOutput();
138
- await getAllEnvironmentVariables({ root: tmpDir });
139
- expect(outputMock.info()).not.toMatch(
140
- /PUBLIC_API_TOKEN\s+from Oxygen/
141
- );
142
- expect(outputMock.info()).toMatch(
143
- /PUBLIC_API_TOKEN\s+from local \.env/
144
- );
145
- });
146
- });
147
- });
148
- });
149
- });
@@ -1,68 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { replaceFileContent, findFileWithExtension } from './file.js';
3
- import { resolvePath } from '@shopify/cli-kit/node/path';
4
- import { inTemporaryDirectory, writeFile, readFile, mkdir } from '@shopify/cli-kit/node/fs';
5
-
6
- describe("File utils", () => {
7
- describe("replaceFileContent", () => {
8
- it("replaces the content of a file and formats it", async () => {
9
- await inTemporaryDirectory(async (tmpDir) => {
10
- const filepath = resolvePath(tmpDir, "index.js");
11
- await writeFile(
12
- filepath,
13
- 'function foo() { console.log("foo"); return null}'
14
- );
15
- await replaceFileContent(filepath, {}, async (content) => {
16
- return content.replaceAll("foo", "bar");
17
- });
18
- expect(await readFile(filepath)).toBe(
19
- 'function bar() {\n console.log("bar");\n return null;\n}\n'
20
- );
21
- });
22
- });
23
- });
24
- describe("findFileWithExtension", () => {
25
- it("ignores missing files", async () => {
26
- await inTemporaryDirectory(async (tmpDir) => {
27
- expect(findFileWithExtension(tmpDir, "nope")).resolves.toEqual({
28
- filepath: void 0,
29
- extension: void 0,
30
- astType: void 0
31
- });
32
- });
33
- });
34
- it("finds the file with its corresponding extension and astType", async () => {
35
- await inTemporaryDirectory(async (tmpDir) => {
36
- await writeFile(resolvePath(tmpDir, "first.js"), "content");
37
- await writeFile(resolvePath(tmpDir, "second.tsx"), "content");
38
- await writeFile(resolvePath(tmpDir, "third.mjs"), "content");
39
- await writeFile(resolvePath(tmpDir, "fourth"), "content");
40
- await mkdir(resolvePath(tmpDir, "fifth"));
41
- await writeFile(resolvePath(tmpDir, "fifth", "index.ts"), "content");
42
- expect(findFileWithExtension(tmpDir, "first")).resolves.toEqual({
43
- filepath: expect.stringMatching(/first\.js$/),
44
- extension: "js",
45
- astType: "js"
46
- });
47
- expect(findFileWithExtension(tmpDir, "second")).resolves.toEqual({
48
- filepath: expect.stringMatching(/second\.tsx$/),
49
- extension: "tsx",
50
- astType: "tsx"
51
- });
52
- expect(findFileWithExtension(tmpDir, "third")).resolves.toEqual({
53
- filepath: expect.stringMatching(/third\.mjs$/),
54
- extension: "mjs",
55
- astType: "js"
56
- });
57
- expect(findFileWithExtension(tmpDir, "fourth")).resolves.toEqual({
58
- filepath: expect.stringMatching(/fourth$/)
59
- });
60
- expect(findFileWithExtension(tmpDir, "fifth")).resolves.toEqual({
61
- filepath: expect.stringMatching(/fifth\/index\.ts$/),
62
- extension: "ts",
63
- astType: "ts"
64
- });
65
- });
66
- });
67
- });
68
- });
@@ -1,43 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { flagsToCamelObject, parseProcessFlags } from './flags.js';
3
-
4
- describe("CLI flag utils", () => {
5
- it("turns kebab-case flags to camelCase", async () => {
6
- expect(
7
- flagsToCamelObject({
8
- "kebab-case": "value",
9
- "another-kebab-case": "value",
10
- flag: "value"
11
- })
12
- ).toMatchObject({
13
- kebabCase: "value",
14
- anotherKebabCase: "value",
15
- flag: "value"
16
- });
17
- });
18
- it("parses flags from process.argv", async () => {
19
- expect(
20
- parseProcessFlags(
21
- "node ./bin --force --install-deps --template hello-world --path test --language ts".split(
22
- " "
23
- )
24
- )
25
- ).toMatchObject({
26
- force: true,
27
- installDeps: true,
28
- template: "hello-world",
29
- path: "test",
30
- language: "ts"
31
- });
32
- expect(
33
- parseProcessFlags(
34
- "node ./bin -f --no-install-deps --language js".split(" "),
35
- { f: "force" }
36
- )
37
- ).toMatchObject({
38
- force: true,
39
- installDeps: false,
40
- language: "js"
41
- });
42
- });
43
- });