@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.
- package/dist/commands/hydrogen/build-vite.js +19 -10
- package/dist/commands/hydrogen/build.js +10 -2
- package/dist/commands/hydrogen/check.js +1 -0
- package/dist/commands/hydrogen/codegen.js +1 -0
- package/dist/commands/hydrogen/customer-account/push.js +170 -0
- package/dist/commands/hydrogen/debug/cpu.js +3 -0
- package/dist/commands/hydrogen/deploy.js +121 -36
- package/dist/commands/hydrogen/dev-vite.js +128 -59
- package/dist/commands/hydrogen/dev.js +108 -51
- package/dist/commands/hydrogen/env/list.js +7 -8
- package/dist/commands/hydrogen/env/pull.js +17 -1
- package/dist/commands/hydrogen/env/{push__unstable.js → push.js} +23 -50
- package/dist/commands/hydrogen/generate/route.js +1 -0
- package/dist/commands/hydrogen/init.js +45 -17
- package/dist/commands/hydrogen/link.js +20 -4
- package/dist/commands/hydrogen/list.js +1 -0
- package/dist/commands/hydrogen/login.js +1 -0
- package/dist/commands/hydrogen/logout.js +1 -0
- package/dist/commands/hydrogen/preview.js +31 -16
- package/dist/commands/hydrogen/setup/css.js +8 -1
- package/dist/commands/hydrogen/setup/markets.js +1 -0
- package/dist/commands/hydrogen/setup/vite.js +244 -138
- package/dist/commands/hydrogen/setup.js +21 -22
- package/dist/commands/hydrogen/shortcut.js +10 -0
- package/dist/commands/hydrogen/unlink.js +1 -0
- package/dist/commands/hydrogen/upgrade.js +2 -1
- package/dist/generator-templates/assets/vite/package.json +3 -4
- package/dist/generator-templates/assets/vite/vite.config.js +10 -2
- package/dist/generator-templates/starter/CHANGELOG.md +89 -0
- package/dist/generator-templates/starter/README.md +3 -44
- package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +1 -0
- package/dist/generator-templates/starter/app/lib/fragments.ts +2 -0
- package/dist/generator-templates/starter/app/root.tsx +2 -5
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/account.tsx +1 -1
- package/dist/generator-templates/starter/app/routes/collections.all.tsx +160 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +1 -2
- package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +6 -3
- package/dist/generator-templates/starter/{remix.env.d.ts → env.d.ts} +8 -2
- package/dist/generator-templates/starter/package.json +14 -9
- package/dist/generator-templates/starter/server.ts +2 -1
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +59 -3
- package/dist/generator-templates/starter/vite.config.ts +21 -0
- package/dist/{commands/hydrogen/init.d.ts → init.d.ts} +11 -3
- package/dist/lib/check-lockfile.js +12 -18
- package/dist/lib/codegen.js +37 -13
- package/dist/lib/common.js +50 -0
- package/dist/lib/cpu-profiler.js +4 -1
- package/dist/lib/dev-shared.js +97 -0
- package/dist/lib/environment-variables.js +51 -30
- package/dist/lib/file.js +8 -1
- package/dist/lib/flags.js +37 -16
- package/dist/lib/graphql/admin/customer-application-update.js +29 -0
- package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
- package/dist/lib/graphql/admin/list-environments.js +1 -0
- package/dist/lib/graphql/admin/pull-variables.js +4 -4
- package/dist/lib/graphql/admin/test-helper.js +37 -0
- package/dist/lib/log.js +86 -13
- package/dist/lib/mini-oxygen/common.js +19 -33
- package/dist/lib/mini-oxygen/index.js +6 -2
- package/dist/lib/mini-oxygen/node.js +43 -31
- package/dist/lib/mini-oxygen/workerd.js +72 -165
- package/dist/lib/missing-routes.js +1 -1
- package/dist/lib/onboarding/common.js +82 -70
- package/dist/lib/onboarding/local.js +19 -9
- package/dist/lib/onboarding/remote.js +35 -30
- package/dist/lib/package-managers.js +24 -0
- package/dist/lib/remix-config.js +17 -1
- package/dist/lib/request-events.js +6 -1
- package/dist/lib/setups/i18n/replacers.js +9 -6
- package/dist/lib/setups/routes/generate.js +1 -0
- package/dist/lib/shell.js +2 -1
- package/dist/lib/shopify-config.js +19 -1
- package/dist/lib/template-diff.js +36 -15
- package/dist/lib/template-downloader.js +35 -5
- package/dist/lib/transpile/morph/typedefs.js +5 -2
- package/dist/lib/transpile/project.js +8 -4
- package/dist/lib/tunneling.js +44 -0
- package/dist/lib/virtual-routes.js +1 -1
- package/dist/lib/vite-config.js +39 -9
- package/oclif.manifest.json +711 -498
- package/package.json +32 -24
- package/dist/commands/hydrogen/deploy.test.js +0 -553
- package/dist/commands/hydrogen/env/list.test.js +0 -148
- package/dist/commands/hydrogen/env/pull.test.js +0 -207
- package/dist/commands/hydrogen/env/push__unstable.test.js +0 -383
- package/dist/commands/hydrogen/generate/route.test.js +0 -43
- package/dist/commands/hydrogen/init.test.js +0 -641
- package/dist/commands/hydrogen/link.test.js +0 -187
- package/dist/commands/hydrogen/list.test.js +0 -111
- package/dist/commands/hydrogen/setup.test.js +0 -61
- package/dist/commands/hydrogen/shortcut.test.js +0 -30
- package/dist/commands/hydrogen/unlink.test.js +0 -36
- package/dist/commands/hydrogen/upgrade.test.js +0 -786
- package/dist/generator-templates/starter/remix.config.js +0 -24
- package/dist/lib/auth.test.js +0 -157
- package/dist/lib/check-lockfile.test.js +0 -81
- package/dist/lib/check-version.test.js +0 -86
- package/dist/lib/environment-variables.test.js +0 -149
- package/dist/lib/file.test.js +0 -68
- package/dist/lib/flags.test.js +0 -43
- package/dist/lib/get-oxygen-deployment-data.test.js +0 -120
- package/dist/lib/gid.test.js +0 -15
- package/dist/lib/graphql/admin/client.test.js +0 -76
- package/dist/lib/graphql/admin/create-storefront.test.js +0 -64
- package/dist/lib/graphql/admin/link-storefront.test.js +0 -38
- package/dist/lib/graphql/admin/list-environments.test.js +0 -44
- package/dist/lib/graphql/admin/list-storefronts.test.js +0 -44
- package/dist/lib/graphql/admin/pull-variables.test.js +0 -43
- package/dist/lib/graphql/business-platform/user-account.test.js +0 -80
- package/dist/lib/log.test.js +0 -92
- package/dist/lib/mini-oxygen/assets.js +0 -134
- package/dist/lib/mini-oxygen/mini-oxygen.test.js +0 -214
- package/dist/lib/mini-oxygen/workerd-inspector-logs.js +0 -227
- package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +0 -200
- package/dist/lib/mini-oxygen/workerd-inspector.js +0 -219
- package/dist/lib/missing-routes.test.js +0 -45
- package/dist/lib/remix-version-check.test.js +0 -39
- package/dist/lib/remix-version-interop.test.js +0 -13
- package/dist/lib/setups/i18n/domains.test.js +0 -39
- package/dist/lib/setups/i18n/replacers.test.js +0 -261
- package/dist/lib/setups/i18n/subdomains.test.js +0 -39
- package/dist/lib/setups/i18n/subfolders.test.js +0 -39
- package/dist/lib/setups/routes/generate.test.js +0 -296
- package/dist/lib/shell.test.js +0 -111
- package/dist/lib/shopify-config.test.js +0 -199
- package/dist/lib/string.test.js +0 -16
- package/dist/lib/virtual-routes.test.js +0 -49
- package/dist/lib/vite/hydrogen-middleware.js +0 -82
- package/dist/lib/vite/mini-oxygen.js +0 -152
- package/dist/lib/vite/plugins.d.ts +0 -27
- package/dist/lib/vite/plugins.js +0 -139
- package/dist/lib/vite/shared.js +0 -10
- package/dist/lib/vite/utils.js +0 -55
- package/dist/lib/vite/worker-entry.js +0 -1518
- /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
|
-
};
|
package/dist/lib/auth.test.js
DELETED
|
@@ -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
|
-
});
|
package/dist/lib/file.test.js
DELETED
|
@@ -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
|
-
});
|
package/dist/lib/flags.test.js
DELETED
|
@@ -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
|
-
});
|