@zuplo/cli 6.69.6 → 6.69.8
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/__tests__/integration/confirm-production-deploy.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js +184 -0
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js.map +1 -0
- package/dist/__tests__/integration/deploy.integration.test.js +1 -0
- package/dist/__tests__/integration/deploy.integration.test.js.map +1 -1
- package/dist/__tests__/integration/jest-mocks-setup.js +3 -0
- package/dist/__tests__/integration/jest-mocks-setup.js.map +1 -1
- package/dist/__tests__/integration/whoami.integration.test.js +27 -0
- package/dist/__tests__/integration/whoami.integration.test.js.map +1 -1
- package/dist/bucket/list/handler.d.ts +8 -0
- package/dist/bucket/list/handler.d.ts.map +1 -0
- package/dist/bucket/list/handler.js +54 -0
- package/dist/bucket/list/handler.js.map +1 -0
- package/dist/bucket/models.d.ts +23 -0
- package/dist/bucket/models.d.ts.map +1 -0
- package/dist/bucket/models.js +2 -0
- package/dist/bucket/models.js.map +1 -0
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/cmds/bucket/index.d.ts +4 -0
- package/dist/cmds/bucket/index.d.ts.map +1 -0
- package/dist/cmds/bucket/index.js +9 -0
- package/dist/cmds/bucket/index.js.map +1 -0
- package/dist/cmds/bucket/list.d.ts +9 -0
- package/dist/cmds/bucket/list.d.ts.map +1 -0
- package/dist/cmds/bucket/list.js +60 -0
- package/dist/cmds/bucket/list.js.map +1 -0
- package/dist/cmds/deploy.d.ts.map +1 -1
- package/dist/cmds/deploy.js +4 -1
- package/dist/cmds/deploy.js.map +1 -1
- package/dist/cmds/logout.d.ts +9 -0
- package/dist/cmds/logout.d.ts.map +1 -0
- package/dist/cmds/logout.js +23 -0
- package/dist/cmds/logout.js.map +1 -0
- package/dist/cmds/whoami.d.ts.map +1 -1
- package/dist/cmds/whoami.js +1 -2
- package/dist/cmds/whoami.js.map +1 -1
- package/dist/common/middleware/confirm-production-deploy.d.ts +4 -0
- package/dist/common/middleware/confirm-production-deploy.d.ts.map +1 -0
- package/dist/common/middleware/confirm-production-deploy.js +49 -0
- package/dist/common/middleware/confirm-production-deploy.js.map +1 -0
- package/dist/common/middleware/get-environment-param.d.ts +6 -0
- package/dist/common/middleware/get-environment-param.d.ts.map +1 -1
- package/dist/common/middleware/get-environment-param.js +15 -0
- package/dist/common/middleware/get-environment-param.js.map +1 -1
- package/dist/common/middleware/get-environment-param.test.d.ts +2 -0
- package/dist/common/middleware/get-environment-param.test.d.ts.map +1 -0
- package/dist/common/middleware/get-environment-param.test.js +33 -0
- package/dist/common/middleware/get-environment-param.test.js.map +1 -0
- package/dist/common/output.d.ts +3 -0
- package/dist/common/output.d.ts.map +1 -1
- package/dist/common/output.js +11 -0
- package/dist/common/output.js.map +1 -1
- package/dist/common/read-linked-config.d.ts +6 -1
- package/dist/common/read-linked-config.d.ts.map +1 -1
- package/dist/common/read-linked-config.js +14 -4
- package/dist/common/read-linked-config.js.map +1 -1
- package/dist/common/read-linked-config.test.js +97 -0
- package/dist/common/read-linked-config.test.js.map +1 -1
- package/dist/deploy/environments.d.ts +1 -0
- package/dist/deploy/environments.d.ts.map +1 -1
- package/dist/deploy/environments.js +11 -7
- package/dist/deploy/environments.js.map +1 -1
- package/dist/login/logout.d.ts +5 -0
- package/dist/login/logout.d.ts.map +1 -0
- package/dist/login/logout.js +6 -0
- package/dist/login/logout.js.map +1 -0
- package/dist/login/tokens.d.ts +1 -0
- package/dist/login/tokens.d.ts.map +1 -1
- package/dist/login/tokens.js +16 -1
- package/dist/login/tokens.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/whoami/handler.d.ts +1 -1
- package/dist/whoami/handler.d.ts.map +1 -1
- package/dist/whoami/handler.js +8 -1
- package/dist/whoami/handler.js.map +1 -1
- package/node_modules/@zuplo/core/customer.cli.minified.js +225 -211
- package/node_modules/@zuplo/core/index.minified.js +237 -223
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/editor/node_modules/find-my-way/.github/workflows/node.js.yml +1 -1
- package/node_modules/@zuplo/editor/node_modules/find-my-way/README.md +10 -0
- package/node_modules/@zuplo/editor/node_modules/find-my-way/index.d.ts +6 -0
- package/node_modules/@zuplo/editor/node_modules/find-my-way/index.js +37 -4
- package/node_modules/@zuplo/editor/node_modules/find-my-way/lib/handler-storage.js +2 -2
- package/node_modules/@zuplo/editor/node_modules/find-my-way/package.json +3 -3
- package/node_modules/@zuplo/editor/node_modules/find-my-way/test/repro-issue-414.test.js +57 -0
- package/node_modules/@zuplo/editor/node_modules/find-my-way/test/types/router.test-d.ts +1 -0
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/graphql/index.d.ts +1 -0
- package/node_modules/graphql/language/ast.d.ts +10 -1
- package/node_modules/graphql/language/ast.js +8 -1
- package/node_modules/graphql/language/ast.mjs +8 -1
- package/node_modules/graphql/language/directiveLocation.d.ts +1 -0
- package/node_modules/graphql/language/directiveLocation.js +1 -0
- package/node_modules/graphql/language/directiveLocation.mjs +1 -0
- package/node_modules/graphql/language/index.d.ts +1 -0
- package/node_modules/graphql/language/kinds.d.ts +1 -0
- package/node_modules/graphql/language/kinds.js +1 -0
- package/node_modules/graphql/language/kinds.mjs +1 -0
- package/node_modules/graphql/language/parser.d.ts +14 -0
- package/node_modules/graphql/language/parser.js +33 -0
- package/node_modules/graphql/language/parser.mjs +33 -0
- package/node_modules/graphql/language/predicates.js +3 -1
- package/node_modules/graphql/language/predicates.mjs +5 -1
- package/node_modules/graphql/language/printer.js +13 -1
- package/node_modules/graphql/language/printer.mjs +13 -1
- package/node_modules/graphql/package.json +1 -1
- package/node_modules/graphql/type/directives.d.ts +9 -1
- package/node_modules/graphql/type/directives.js +10 -1
- package/node_modules/graphql/type/directives.mjs +10 -1
- package/node_modules/graphql/type/introspection.js +24 -1
- package/node_modules/graphql/type/introspection.mjs +24 -1
- package/node_modules/graphql/utilities/buildASTSchema.js +4 -0
- package/node_modules/graphql/utilities/buildASTSchema.mjs +4 -0
- package/node_modules/graphql/utilities/buildClientSchema.js +1 -0
- package/node_modules/graphql/utilities/buildClientSchema.mjs +1 -0
- package/node_modules/graphql/utilities/extendSchema.js +58 -3
- package/node_modules/graphql/utilities/extendSchema.mjs +58 -3
- package/node_modules/graphql/utilities/getIntrospectionQuery.d.ts +16 -0
- package/node_modules/graphql/utilities/getIntrospectionQuery.js +31 -38
- package/node_modules/graphql/utilities/getIntrospectionQuery.mjs +31 -38
- package/node_modules/graphql/utilities/introspectionFromSchema.js +1 -0
- package/node_modules/graphql/utilities/introspectionFromSchema.mjs +1 -0
- package/node_modules/graphql/utilities/printSchema.js +1 -0
- package/node_modules/graphql/utilities/printSchema.mjs +1 -0
- package/node_modules/graphql/utilities/valueFromAST.js +12 -2
- package/node_modules/graphql/utilities/valueFromAST.mjs +12 -2
- package/node_modules/graphql/validation/rules/KnownDirectivesRule.js +4 -0
- package/node_modules/graphql/validation/rules/KnownDirectivesRule.mjs +4 -0
- package/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.js +12 -0
- package/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.mjs +12 -0
- package/node_modules/graphql/version.js +3 -3
- package/node_modules/graphql/version.mjs +3 -3
- package/package.json +6 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-production-deploy.integration.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/confirm-production-deploy.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { confirmProductionDeploy } from "../../common/middleware/confirm-production-deploy.js";
|
|
2
|
+
import { ENVIRONMENT_EXPLICIT_KEY, FETCHED_ENVIRONMENTS_KEY, } from "../../common/middleware/get-environment-param.js";
|
|
3
|
+
import { printCancellationToConsoleAndExitGracefully } from "../../common/output.js";
|
|
4
|
+
import { confirmLinkedValue } from "../../common/read-linked-config.js";
|
|
5
|
+
import { isInteractiveTerminal } from "../../common/terminal.js";
|
|
6
|
+
import { cleanupTest, setupTestEnvironment, TEST_ACCOUNT_NAME, TEST_AUTH_TOKEN, TEST_PROJECT_NAME, } from "./test-utils.js";
|
|
7
|
+
jest.mock("../../common/read-linked-config.js", () => ({
|
|
8
|
+
__esModule: true,
|
|
9
|
+
confirmLinkedValue: jest.fn().mockResolvedValue(true),
|
|
10
|
+
}));
|
|
11
|
+
jest.mock("../../common/terminal.js", () => ({
|
|
12
|
+
__esModule: true,
|
|
13
|
+
isInteractiveTerminal: jest.fn().mockReturnValue(true),
|
|
14
|
+
}));
|
|
15
|
+
jest.mock("../../common/output.js", () => ({
|
|
16
|
+
__esModule: true,
|
|
17
|
+
printCancellationToConsoleAndExitGracefully: jest
|
|
18
|
+
.fn()
|
|
19
|
+
.mockImplementation(() => {
|
|
20
|
+
throw new Error("cancelled");
|
|
21
|
+
}),
|
|
22
|
+
}));
|
|
23
|
+
function baseArgv(overrides = {}) {
|
|
24
|
+
return {
|
|
25
|
+
authToken: TEST_AUTH_TOKEN,
|
|
26
|
+
account: TEST_ACCOUNT_NAME,
|
|
27
|
+
project: TEST_PROJECT_NAME,
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
describe("confirmProductionDeploy middleware", () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
setupTestEnvironment();
|
|
34
|
+
jest.clearAllMocks();
|
|
35
|
+
jest.mocked(isInteractiveTerminal).mockReturnValue(true);
|
|
36
|
+
jest.mocked(confirmLinkedValue).mockResolvedValue(true);
|
|
37
|
+
jest
|
|
38
|
+
.mocked(printCancellationToConsoleAndExitGracefully)
|
|
39
|
+
.mockImplementation((() => {
|
|
40
|
+
throw new Error("cancelled");
|
|
41
|
+
}));
|
|
42
|
+
});
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
cleanupTest();
|
|
45
|
+
});
|
|
46
|
+
describe("when the env was inferred from a production branch and the terminal is interactive", () => {
|
|
47
|
+
it("prompts with default No for branch 'main' and proceeds on accept", async () => {
|
|
48
|
+
jest.mocked(confirmLinkedValue).mockResolvedValue(true);
|
|
49
|
+
const argv = baseArgv({
|
|
50
|
+
environment: "main",
|
|
51
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
52
|
+
});
|
|
53
|
+
await confirmProductionDeploy(argv);
|
|
54
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
55
|
+
const [message, options] = jest.mocked(confirmLinkedValue).mock.calls[0];
|
|
56
|
+
expect(message).toContain("'main' production environment");
|
|
57
|
+
expect(message).toContain(`'${TEST_PROJECT_NAME}'`);
|
|
58
|
+
expect(message).toContain(`'${TEST_ACCOUNT_NAME}'`);
|
|
59
|
+
expect(options).toEqual({ defaultYes: false });
|
|
60
|
+
expect(printCancellationToConsoleAndExitGracefully).not.toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
it("cancels via the graceful exit helper when the user declines", async () => {
|
|
63
|
+
jest.mocked(confirmLinkedValue).mockResolvedValue(false);
|
|
64
|
+
const argv = baseArgv({
|
|
65
|
+
environment: "main",
|
|
66
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
67
|
+
});
|
|
68
|
+
await expect(confirmProductionDeploy(argv)).rejects.toThrow("cancelled");
|
|
69
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
70
|
+
expect(printCancellationToConsoleAndExitGracefully).toHaveBeenCalledWith("Deployment cancelled.");
|
|
71
|
+
});
|
|
72
|
+
it("prompts for branch 'master'", async () => {
|
|
73
|
+
const argv = baseArgv({
|
|
74
|
+
environment: "master",
|
|
75
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
76
|
+
});
|
|
77
|
+
await confirmProductionDeploy(argv);
|
|
78
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
79
|
+
});
|
|
80
|
+
it("prompts for branch 'production' without duplicating the word in the message", async () => {
|
|
81
|
+
const argv = baseArgv({
|
|
82
|
+
environment: "production",
|
|
83
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
84
|
+
});
|
|
85
|
+
await confirmProductionDeploy(argv);
|
|
86
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
87
|
+
const [message] = jest.mocked(confirmLinkedValue).mock.calls[0];
|
|
88
|
+
expect(message).toContain("the production environment");
|
|
89
|
+
expect(message).not.toContain("'production' production environment");
|
|
90
|
+
});
|
|
91
|
+
it("prompts when the environment list reports environmentType=production for a non-standard name", async () => {
|
|
92
|
+
const argv = baseArgv({
|
|
93
|
+
environment: "live",
|
|
94
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
95
|
+
[FETCHED_ENVIRONMENTS_KEY]: [
|
|
96
|
+
{
|
|
97
|
+
name: "live",
|
|
98
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
99
|
+
projectName: TEST_PROJECT_NAME,
|
|
100
|
+
createdOn: null,
|
|
101
|
+
branchName: "live",
|
|
102
|
+
environmentType: "production",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
await confirmProductionDeploy(argv);
|
|
107
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("when the env is not production", () => {
|
|
111
|
+
it("does not prompt for a feature branch", async () => {
|
|
112
|
+
const argv = baseArgv({
|
|
113
|
+
environment: "feature/login",
|
|
114
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
115
|
+
});
|
|
116
|
+
await confirmProductionDeploy(argv);
|
|
117
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
118
|
+
});
|
|
119
|
+
it("does not prompt when cached environmentType is not production", async () => {
|
|
120
|
+
const argv = baseArgv({
|
|
121
|
+
environment: "preview-1",
|
|
122
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
123
|
+
[FETCHED_ENVIRONMENTS_KEY]: [
|
|
124
|
+
{
|
|
125
|
+
name: "preview-1",
|
|
126
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
127
|
+
projectName: TEST_PROJECT_NAME,
|
|
128
|
+
createdOn: null,
|
|
129
|
+
branchName: "preview-1",
|
|
130
|
+
environmentType: "preview",
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
await confirmProductionDeploy(argv);
|
|
135
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe("when the user opts out of the prompt", () => {
|
|
139
|
+
it("does not prompt when --environment was passed explicitly", async () => {
|
|
140
|
+
const argv = baseArgv({
|
|
141
|
+
environment: "main",
|
|
142
|
+
[ENVIRONMENT_EXPLICIT_KEY]: true,
|
|
143
|
+
});
|
|
144
|
+
await confirmProductionDeploy(argv);
|
|
145
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
146
|
+
});
|
|
147
|
+
it("does not prompt when --no-prompt is set (argv.prompt === false)", async () => {
|
|
148
|
+
const argv = baseArgv({
|
|
149
|
+
environment: "main",
|
|
150
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
151
|
+
prompt: false,
|
|
152
|
+
});
|
|
153
|
+
await confirmProductionDeploy(argv);
|
|
154
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe("when the terminal is non-interactive (CI/CD)", () => {
|
|
158
|
+
it("does not prompt", async () => {
|
|
159
|
+
jest.mocked(isInteractiveTerminal).mockReturnValue(false);
|
|
160
|
+
const argv = baseArgv({
|
|
161
|
+
environment: "main",
|
|
162
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
163
|
+
});
|
|
164
|
+
await confirmProductionDeploy(argv);
|
|
165
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("when argv.environment is missing or empty", () => {
|
|
169
|
+
it("returns without prompting if environment is undefined", async () => {
|
|
170
|
+
const argv = baseArgv({ [ENVIRONMENT_EXPLICIT_KEY]: false });
|
|
171
|
+
await confirmProductionDeploy(argv);
|
|
172
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
173
|
+
});
|
|
174
|
+
it("returns without prompting if environment is empty string", async () => {
|
|
175
|
+
const argv = baseArgv({
|
|
176
|
+
environment: "",
|
|
177
|
+
[ENVIRONMENT_EXPLICIT_KEY]: false,
|
|
178
|
+
});
|
|
179
|
+
await confirmProductionDeploy(argv);
|
|
180
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
//# sourceMappingURL=confirm-production-deploy.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm-production-deploy.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/confirm-production-deploy.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the confirmProductionDeploy middleware.\n *\n * The middleware adds a Y/n (default No) prompt before deploying to a\n * production environment. It fires only when the terminal is interactive,\n * `--no-prompt` was not set, `--environment` was not passed, and the\n * resolved environment is \"production\" by branch-name heuristic\n * (main/master/production) or by server-reported environmentType when the\n * environments list is already cached. CI/CD is detected automatically via\n * isInteractiveTerminal.\n */\n/// <reference types=\"jest\" />\nimport { confirmProductionDeploy } from \"../../common/middleware/confirm-production-deploy.js\";\nimport {\n ENVIRONMENT_EXPLICIT_KEY,\n FETCHED_ENVIRONMENTS_KEY,\n} from \"../../common/middleware/get-environment-param.js\";\nimport { printCancellationToConsoleAndExitGracefully } from \"../../common/output.js\";\nimport { confirmLinkedValue } from \"../../common/read-linked-config.js\";\nimport { isInteractiveTerminal } from \"../../common/terminal.js\";\nimport {\n cleanupTest,\n setupTestEnvironment,\n TEST_ACCOUNT_NAME,\n TEST_AUTH_TOKEN,\n TEST_PROJECT_NAME,\n} from \"./test-utils.js\";\n\njest.mock(\"../../common/read-linked-config.js\", () => ({\n __esModule: true,\n confirmLinkedValue: jest.fn().mockResolvedValue(true),\n}));\n\njest.mock(\"../../common/terminal.js\", () => ({\n __esModule: true,\n isInteractiveTerminal: jest.fn().mockReturnValue(true),\n}));\n\n// Mock output module — the real one pulls in Sentry which Jest can't load in\n// this ESM test context. The middleware only needs the cancel helper here,\n// substituted with a thrower so we can assert the cancel path without\n// actually exiting the process.\njest.mock(\"../../common/output.js\", () => ({\n __esModule: true,\n printCancellationToConsoleAndExitGracefully: jest\n .fn()\n .mockImplementation(() => {\n throw new Error(\"cancelled\");\n }),\n}));\n\nfunction baseArgv(overrides: Record<string, unknown> = {}) {\n return {\n authToken: TEST_AUTH_TOKEN,\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n ...overrides,\n };\n}\n\ndescribe(\"confirmProductionDeploy middleware\", () => {\n beforeEach(() => {\n setupTestEnvironment();\n jest.clearAllMocks();\n jest.mocked(isInteractiveTerminal).mockReturnValue(true);\n jest.mocked(confirmLinkedValue).mockResolvedValue(true);\n jest\n .mocked(printCancellationToConsoleAndExitGracefully)\n .mockImplementation((() => {\n throw new Error(\"cancelled\");\n }) as never);\n });\n\n afterEach(() => {\n cleanupTest();\n });\n\n describe(\"when the env was inferred from a production branch and the terminal is interactive\", () => {\n it(\"prompts with default No for branch 'main' and proceeds on accept\", async () => {\n jest.mocked(confirmLinkedValue).mockResolvedValue(true);\n\n const argv = baseArgv({\n environment: \"main\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n await confirmProductionDeploy(argv);\n\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n const [message, options] = jest.mocked(confirmLinkedValue).mock.calls[0];\n expect(message).toContain(\"'main' production environment\");\n expect(message).toContain(`'${TEST_PROJECT_NAME}'`);\n expect(message).toContain(`'${TEST_ACCOUNT_NAME}'`);\n expect(options).toEqual({ defaultYes: false });\n expect(\n printCancellationToConsoleAndExitGracefully\n ).not.toHaveBeenCalled();\n });\n\n it(\"cancels via the graceful exit helper when the user declines\", async () => {\n jest.mocked(confirmLinkedValue).mockResolvedValue(false);\n\n const argv = baseArgv({\n environment: \"main\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n await expect(confirmProductionDeploy(argv)).rejects.toThrow(\"cancelled\");\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n expect(printCancellationToConsoleAndExitGracefully).toHaveBeenCalledWith(\n \"Deployment cancelled.\"\n );\n });\n\n it(\"prompts for branch 'master'\", async () => {\n const argv = baseArgv({\n environment: \"master\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n });\n\n it(\"prompts for branch 'production' without duplicating the word in the message\", async () => {\n const argv = baseArgv({\n environment: \"production\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n const [message] = jest.mocked(confirmLinkedValue).mock.calls[0];\n expect(message).toContain(\"the production environment\");\n expect(message).not.toContain(\"'production' production environment\");\n });\n\n it(\"prompts when the environment list reports environmentType=production for a non-standard name\", async () => {\n const argv = baseArgv({\n environment: \"live\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n [FETCHED_ENVIRONMENTS_KEY]: [\n {\n name: \"live\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n createdOn: null,\n branchName: \"live\",\n environmentType: \"production\",\n },\n ],\n });\n\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n });\n });\n\n describe(\"when the env is not production\", () => {\n it(\"does not prompt for a feature branch\", async () => {\n const argv = baseArgv({\n environment: \"feature/login\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n\n it(\"does not prompt when cached environmentType is not production\", async () => {\n const argv = baseArgv({\n environment: \"preview-1\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n [FETCHED_ENVIRONMENTS_KEY]: [\n {\n name: \"preview-1\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n createdOn: null,\n branchName: \"preview-1\",\n environmentType: \"preview\",\n },\n ],\n });\n\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n });\n\n describe(\"when the user opts out of the prompt\", () => {\n it(\"does not prompt when --environment was passed explicitly\", async () => {\n const argv = baseArgv({\n environment: \"main\",\n [ENVIRONMENT_EXPLICIT_KEY]: true,\n });\n\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n\n it(\"does not prompt when --no-prompt is set (argv.prompt === false)\", async () => {\n const argv = baseArgv({\n environment: \"main\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n prompt: false,\n });\n\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n });\n\n describe(\"when the terminal is non-interactive (CI/CD)\", () => {\n it(\"does not prompt\", async () => {\n jest.mocked(isInteractiveTerminal).mockReturnValue(false);\n const argv = baseArgv({\n environment: \"main\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n });\n\n describe(\"when argv.environment is missing or empty\", () => {\n it(\"returns without prompting if environment is undefined\", async () => {\n const argv = baseArgv({ [ENVIRONMENT_EXPLICIT_KEY]: false });\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n\n it(\"returns without prompting if environment is empty string\", async () => {\n const argv = baseArgv({\n environment: \"\",\n [ENVIRONMENT_EXPLICIT_KEY]: false,\n });\n await confirmProductionDeploy(argv);\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n });\n});\n"]}
|
|
@@ -54,6 +54,7 @@ jest.mock("../../deploy/environments.js", () => ({
|
|
|
54
54
|
}),
|
|
55
55
|
UnableToAutoLinkToExistingProject: class extends Error {
|
|
56
56
|
},
|
|
57
|
+
isProductionBranchName: jest.fn().mockReturnValue(false),
|
|
57
58
|
}));
|
|
58
59
|
jest.mock("node:fs", () => ({
|
|
59
60
|
existsSync: jest.fn().mockReturnValue(false),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/deploy.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the deploy command\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport yargs from \"yargs/yargs\";\nimport deployCommand from \"../../cmds/deploy.js\";\nimport {\n cleanupTest,\n RequestCapture,\n setupAuthenticatedNock,\n setupTestEnvironment,\n TEST_ACCOUNT_NAME,\n TEST_API_BASE,\n TEST_AUTH_TOKEN,\n TEST_PROJECT_NAME,\n} from \"./test-utils.js\";\n\n// Mock file system validator\njest.mock(\"../../common/validators/file-system-validator.js\", () => ({\n validDeployDirectoryValidator: {\n validate: jest.fn().mockResolvedValue(true),\n },\n}));\n\n// Mock archive functionality to return predictable metadata\njest.mock(\"../../deploy/archive.js\", () => ({\n archive: jest.fn().mockResolvedValue({\n tarball: \"/tmp/test-archive.tar.gz\",\n metadata: {\n branch: \"main\",\n sha: \"abc123\",\n repoUrl: \"https://github.com/user/repo.git\",\n },\n }),\n generateMetadata: jest.fn().mockResolvedValue({\n branch: \"main\",\n sha: \"abc123\",\n repoUrl: \"https://github.com/user/repo.git\",\n }),\n}));\n\n// Mock file upload but allow the HTTP call to be intercepted\njest.mock(\"../../deploy/file-upload.js\", () => ({\n upload: jest.fn(async ({ uploadUrl }) => {\n // Make actual HTTP call to allow nock interception\n const response = await fetch(uploadUrl, {\n method: \"PUT\",\n body: \"mock-tarball-content\",\n });\n return {\n ok: response.ok,\n status: response.status,\n };\n }),\n}));\n\n// Mock polling functions to simulate deployment success\njest.mock(\"../../deploy/poll-deployment.js\", () => ({\n pollDeployment: jest.fn().mockResolvedValue({\n url: \"https://test-project-main.zuplo.app\",\n logUrl: \"https://portal.zuplo.com/logs/deployment-123\",\n }),\n pollBuild: jest.fn().mockResolvedValue({\n conditionType: \"Complete\",\n }),\n}));\n\n// Mock link functionality for self-hosted\njest.mock(\"../../common/populate.js\", () => ({\n pullSystemConfig: jest.fn().mockResolvedValue(undefined),\n pullLocalConfig: jest.fn().mockResolvedValue(undefined),\n}));\n\n// Mock environment functions\njest.mock(\"../../deploy/environments.js\", () => ({\n retrieveOrCreateEnvironment: jest.fn().mockResolvedValue({\n name: \"development\",\n type: \"development\",\n }),\n UnableToAutoLinkToExistingProject: class extends Error {},\n}));\n\n// Mock file system functions\njest.mock(\"node:fs\", () => ({\n existsSync: jest.fn().mockReturnValue(false),\n readFileSync: jest.fn((filePath: string) => {\n if (filePath.endsWith(\"tls.crt\")) {\n return \"mock-cert-content\";\n }\n if (filePath.endsWith(\"tls.key\")) {\n return \"mock-key-content\";\n }\n return Buffer.from(\"mock-tarball-content\");\n }),\n readdirSync: jest.fn().mockReturnValue([]),\n writeFileSync: jest.fn(),\n}));\n\n/**\n * Execute deploy command with given arguments using actual yargs command\n */\nasync function executeDeployCommand(args: {\n account?: string;\n project?: string;\n \"api-key\"?: string;\n environment?: string;\n \"self-hosted-endpoint\"?: string;\n \"mtls-certificates-dir\"?: string;\n dir?: string;\n}) {\n const yargsInstance = yargs([])\n .command(deployCommand)\n .help(false)\n .version(false)\n .exitProcess(false);\n\n // Build command line arguments\n const commandArgs = [\"deploy\"];\n\n if (args.account) {\n commandArgs.push(\"--account\", args.account);\n }\n\n if (args.project) {\n commandArgs.push(\"--project\", args.project);\n }\n\n if (args[\"api-key\"]) {\n commandArgs.push(\"--api-key\", args[\"api-key\"]);\n }\n\n if (args.environment) {\n commandArgs.push(\"--environment\", args.environment);\n }\n\n if (args[\"self-hosted-endpoint\"]) {\n commandArgs.push(\"--self-hosted-endpoint\", args[\"self-hosted-endpoint\"]);\n }\n\n if (args[\"mtls-certificates-dir\"]) {\n commandArgs.push(\"--mtls-certificates-dir\", args[\"mtls-certificates-dir\"]);\n }\n\n if (args.dir) {\n commandArgs.push(\"--dir\", args.dir);\n }\n\n // Parse and execute the command\n return await yargsInstance.parse(commandArgs);\n}\n\n// Get the mocked functions\nconst mockPrintResult = jest.mocked(\n require(\"../../common/output.js\").printResultToConsoleAndExitGracefully\n);\nconst mockReadFileSync = jest.mocked(require(\"node:fs\").readFileSync);\nconst mockReaddirSync = jest.mocked(require(\"node:fs\").readdirSync);\nconst mockExistsSync = jest.mocked(require(\"node:fs\").existsSync);\n\ndescribe(\"Deploy Command Integration Tests\", () => {\n let requestCapture: RequestCapture;\n\n beforeEach(() => {\n setupTestEnvironment();\n requestCapture = new RequestCapture();\n\n // Disable real HTTP requests\n nock.disableNetConnect();\n\n // Clear mock calls from previous tests\n jest.clearAllMocks();\n\n mockExistsSync.mockReturnValue(false);\n mockReaddirSync.mockReturnValue([]);\n mockReadFileSync.mockImplementation((filePath: string) => {\n if (filePath.endsWith(\"tls.crt\")) {\n return \"mock-cert-content\";\n }\n if (filePath.endsWith(\"tls.key\")) {\n return \"mock-key-content\";\n }\n return Buffer.from(\"mock-tarball-content\");\n });\n });\n\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n describe(\"SaaS deployment\", () => {\n it(\"should intercept POST request to get source upload URL\", async () => {\n const mockUploadUrlResponse = {\n uploadUrl: \"https://storage.example.com/upload/abc123\",\n deploymentId: \"deployment-456\",\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(200, mockUploadUrlResponse);\n\n // Mock the upload to cloud storage\n const uploadScope = nock(\"https://storage.example.com\")\n .put(\"/upload/abc123\")\n .reply(200, { message: \"Upload successful\" });\n\n [scope, uploadScope].forEach((s) => {\n s.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n expect(uploadScope.isDone()).toBe(true);\n\n // Verify successful deployment message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n \"Deployed to https://test-project-main.zuplo.app\"\n ),\n expect.any(Object) // spinner object\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-saas-requests\");\n\n // Verify the source-url request payload\n const sourceUrlRequest = capturedRequests.find(\n (req) => req.path === \"/v1/deployments/source-url\"\n );\n expect(sourceUrlRequest?.method).toBe(\"POST\");\n expect(sourceUrlRequest?.body).toEqual({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n environment: \"main\",\n repositoryUrl: \"https://github.com/user/repo.git\",\n sha: \"abc123\",\n });\n });\n\n it(\"should handle upload URL request failure\", async () => {\n const errorResponse = {\n error: \"Forbidden\",\n message: \"Insufficient permissions\",\n statusCode: 403,\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(403, errorResponse);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await expect(\n executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(scope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-saas-error-requests\");\n });\n });\n\n describe(\"Self-hosted deployment\", () => {\n it(\"should intercept POST request to self-hosted build endpoint\", async () => {\n const selfHostedEndpoint = \"https://my-zuplo.company.com\";\n const mockBuildResponse = {\n buildName: \"build-789\",\n };\n\n const buildScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .post(\"/v1/deployments/build\")\n .reply(200, mockBuildResponse);\n\n // Mock deployment retrieval after build completion\n const deploymentScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .get(\"/v1/deployments/test-project-main\")\n .reply(200, {\n deploymentUrl: \"https://my-zuplo.company.com/test-project-main\",\n });\n\n [buildScope, deploymentScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n \"self-hosted-endpoint\": selfHostedEndpoint,\n dir: \".\",\n });\n\n expect(buildScope.isDone()).toBe(true);\n expect(deploymentScope.isDone()).toBe(true);\n\n // Verify successful deployment message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n \"Deployed to https://my-zuplo.company.com/test-project-main\"\n ),\n expect.any(Object) // spinner object\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-self-hosted-requests\");\n\n // Verify the build request\n const buildRequest = capturedRequests.find(\n (req) => req.path === \"/v1/deployments/build\"\n );\n expect(buildRequest?.method).toBe(\"POST\");\n // Note: FormData body won't be easily testable in snapshots, but we can verify it exists\n expect(buildRequest?.body).toBeDefined();\n }, 60000); // Increase timeout for this complex test\n\n it(\"should handle self-hosted build failure\", async () => {\n const selfHostedEndpoint = \"https://my-zuplo.company.com\";\n const errorResponse = {\n error: \"Bad Request\",\n message: \"Invalid project configuration\",\n statusCode: 400,\n };\n\n const scope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .post(\"/v1/deployments/build\")\n .reply(400, errorResponse);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n \"self-hosted-endpoint\": selfHostedEndpoint,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"deploy-self-hosted-error-requests\"\n );\n }, 60000); // Increase timeout for this test too\n\n it(\"should include mtls certificates from mtls-certificates-dir\", async () => {\n const selfHostedEndpoint = \"https://my-zuplo.company.com\";\n const mockBuildResponse = {\n buildName: \"build-789\",\n };\n let capturedBuildRequestBody = \"\";\n\n mockReaddirSync.mockReturnValue([\n {\n name: \"cert-name-2\",\n isDirectory: () => true,\n },\n {\n name: \"cert-name-1\",\n isDirectory: () => true,\n },\n ]);\n mockReadFileSync.mockImplementation((filePath: string) => {\n if (/cert-name-1[\\\\/]tls\\.crt$/.test(filePath)) {\n return \"CERT_1\";\n }\n if (/cert-name-1[\\\\/]tls\\.key$/.test(filePath)) {\n return \"KEY_1\";\n }\n if (/cert-name-2[\\\\/]tls\\.crt$/.test(filePath)) {\n return \"CERT_2\";\n }\n if (/cert-name-2[\\\\/]tls\\.key$/.test(filePath)) {\n return \"KEY_2\";\n }\n return Buffer.from(\"mock-tarball-content\");\n });\n\n const buildScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .post(\"/v1/deployments/build\", (body) => {\n capturedBuildRequestBody = Buffer.isBuffer(body)\n ? body.toString(\"utf-8\")\n : String(body);\n return true;\n })\n .reply(200, mockBuildResponse);\n\n const deploymentScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .get(\"/v1/deployments/test-project-main\")\n .reply(200, {\n deploymentUrl: \"https://my-zuplo.company.com/test-project-main\",\n });\n\n [buildScope, deploymentScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n \"self-hosted-endpoint\": selfHostedEndpoint,\n \"mtls-certificates-dir\": \"./mtls\",\n dir: \".\",\n });\n\n expect(buildScope.isDone()).toBe(true);\n expect(deploymentScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n const buildRequest = capturedRequests.find(\n (req) => req.path === \"/v1/deployments/build\"\n );\n\n expect(buildRequest?.method).toBe(\"POST\");\n expect(capturedBuildRequestBody).toContain('name=\"mtlsCertificate\"');\n expect(\n (capturedBuildRequestBody.match(/name=\"mtlsCertificate\"/g) || []).length\n ).toBe(2);\n expect(capturedBuildRequestBody).toContain('\"certName\":\"cert-name-1\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsCrt\":\"CERT_1\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsKey\":\"KEY_1\"');\n expect(capturedBuildRequestBody).toContain('\"certName\":\"cert-name-2\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsCrt\":\"CERT_2\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsKey\":\"KEY_2\"');\n\n expect(\n capturedBuildRequestBody.indexOf('\"certName\":\"cert-name-1\"')\n ).toBeLessThan(\n capturedBuildRequestBody.indexOf('\"certName\":\"cert-name-2\"')\n );\n }, 60000);\n });\n\n describe(\"Directory argument handling\", () => {\n it(\"should work when --dir is not specified (uses default)\", async () => {\n const mockUploadUrlResponse = {\n uploadUrl: \"https://storage.example.com/upload/default-test\",\n deploymentId: \"deployment-default\",\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(200, mockUploadUrlResponse);\n\n // Mock the upload to cloud storage\n const uploadScope = nock(\"https://storage.example.com\")\n .put(\"/upload/default-test\")\n .reply(200, { message: \"Upload successful\" });\n\n [scope, uploadScope].forEach((s) => {\n s.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n // Note: Not passing dir argument at all - should default to \".\"\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(scope.isDone()).toBe(true);\n expect(uploadScope.isDone()).toBe(true);\n\n // Verify successful deployment message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n \"Deployed to https://test-project-main.zuplo.app\"\n ),\n expect.any(Object)\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-default-dir-requests\");\n });\n\n it(\"should work with explicit --dir=.\", async () => {\n const mockUploadUrlResponse = {\n uploadUrl: \"https://storage.example.com/upload/explicit-dot\",\n deploymentId: \"deployment-dot\",\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(200, mockUploadUrlResponse);\n\n const uploadScope = nock(\"https://storage.example.com\")\n .put(\"/upload/explicit-dot\")\n .reply(200, { message: \"Upload successful\" });\n\n [scope, uploadScope].forEach((s) => {\n s.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n expect(uploadScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-explicit-dot-requests\");\n });\n });\n\n describe(\"Request validation\", () => {\n it(\"should include correct headers for SaaS deployment\", async () => {\n const mockResponse = {\n uploadUrl: \"https://storage.example.com/upload/abc123\",\n deploymentId: \"deployment-456\",\n };\n\n const scope = nock(TEST_API_BASE)\n .post(\"/v1/deployments/source-url\")\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, mockResponse);\n\n // Mock the upload endpoint\n nock(\"https://storage.example.com\").put(\"/upload/abc123\").reply(200);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-headers-validation\");\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"deploy.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/deploy.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the deploy command\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport yargs from \"yargs/yargs\";\nimport deployCommand from \"../../cmds/deploy.js\";\nimport {\n cleanupTest,\n RequestCapture,\n setupAuthenticatedNock,\n setupTestEnvironment,\n TEST_ACCOUNT_NAME,\n TEST_API_BASE,\n TEST_AUTH_TOKEN,\n TEST_PROJECT_NAME,\n} from \"./test-utils.js\";\n\n// Mock file system validator\njest.mock(\"../../common/validators/file-system-validator.js\", () => ({\n validDeployDirectoryValidator: {\n validate: jest.fn().mockResolvedValue(true),\n },\n}));\n\n// Mock archive functionality to return predictable metadata\njest.mock(\"../../deploy/archive.js\", () => ({\n archive: jest.fn().mockResolvedValue({\n tarball: \"/tmp/test-archive.tar.gz\",\n metadata: {\n branch: \"main\",\n sha: \"abc123\",\n repoUrl: \"https://github.com/user/repo.git\",\n },\n }),\n generateMetadata: jest.fn().mockResolvedValue({\n branch: \"main\",\n sha: \"abc123\",\n repoUrl: \"https://github.com/user/repo.git\",\n }),\n}));\n\n// Mock file upload but allow the HTTP call to be intercepted\njest.mock(\"../../deploy/file-upload.js\", () => ({\n upload: jest.fn(async ({ uploadUrl }) => {\n // Make actual HTTP call to allow nock interception\n const response = await fetch(uploadUrl, {\n method: \"PUT\",\n body: \"mock-tarball-content\",\n });\n return {\n ok: response.ok,\n status: response.status,\n };\n }),\n}));\n\n// Mock polling functions to simulate deployment success\njest.mock(\"../../deploy/poll-deployment.js\", () => ({\n pollDeployment: jest.fn().mockResolvedValue({\n url: \"https://test-project-main.zuplo.app\",\n logUrl: \"https://portal.zuplo.com/logs/deployment-123\",\n }),\n pollBuild: jest.fn().mockResolvedValue({\n conditionType: \"Complete\",\n }),\n}));\n\n// Mock link functionality for self-hosted\njest.mock(\"../../common/populate.js\", () => ({\n pullSystemConfig: jest.fn().mockResolvedValue(undefined),\n pullLocalConfig: jest.fn().mockResolvedValue(undefined),\n}));\n\n// Mock environment functions\njest.mock(\"../../deploy/environments.js\", () => ({\n retrieveOrCreateEnvironment: jest.fn().mockResolvedValue({\n name: \"development\",\n type: \"development\",\n }),\n UnableToAutoLinkToExistingProject: class extends Error {},\n // Used by confirmProductionDeploy middleware. Default to false so the\n // test's default (interactive=false) path is preserved; tests that want\n // to assert the prompt path can override this mock.\n isProductionBranchName: jest.fn().mockReturnValue(false),\n}));\n\n// Mock file system functions\njest.mock(\"node:fs\", () => ({\n existsSync: jest.fn().mockReturnValue(false),\n readFileSync: jest.fn((filePath: string) => {\n if (filePath.endsWith(\"tls.crt\")) {\n return \"mock-cert-content\";\n }\n if (filePath.endsWith(\"tls.key\")) {\n return \"mock-key-content\";\n }\n return Buffer.from(\"mock-tarball-content\");\n }),\n readdirSync: jest.fn().mockReturnValue([]),\n writeFileSync: jest.fn(),\n}));\n\n/**\n * Execute deploy command with given arguments using actual yargs command\n */\nasync function executeDeployCommand(args: {\n account?: string;\n project?: string;\n \"api-key\"?: string;\n environment?: string;\n \"self-hosted-endpoint\"?: string;\n \"mtls-certificates-dir\"?: string;\n dir?: string;\n}) {\n const yargsInstance = yargs([])\n .command(deployCommand)\n .help(false)\n .version(false)\n .exitProcess(false);\n\n // Build command line arguments\n const commandArgs = [\"deploy\"];\n\n if (args.account) {\n commandArgs.push(\"--account\", args.account);\n }\n\n if (args.project) {\n commandArgs.push(\"--project\", args.project);\n }\n\n if (args[\"api-key\"]) {\n commandArgs.push(\"--api-key\", args[\"api-key\"]);\n }\n\n if (args.environment) {\n commandArgs.push(\"--environment\", args.environment);\n }\n\n if (args[\"self-hosted-endpoint\"]) {\n commandArgs.push(\"--self-hosted-endpoint\", args[\"self-hosted-endpoint\"]);\n }\n\n if (args[\"mtls-certificates-dir\"]) {\n commandArgs.push(\"--mtls-certificates-dir\", args[\"mtls-certificates-dir\"]);\n }\n\n if (args.dir) {\n commandArgs.push(\"--dir\", args.dir);\n }\n\n // Parse and execute the command\n return await yargsInstance.parse(commandArgs);\n}\n\n// Get the mocked functions\nconst mockPrintResult = jest.mocked(\n require(\"../../common/output.js\").printResultToConsoleAndExitGracefully\n);\nconst mockReadFileSync = jest.mocked(require(\"node:fs\").readFileSync);\nconst mockReaddirSync = jest.mocked(require(\"node:fs\").readdirSync);\nconst mockExistsSync = jest.mocked(require(\"node:fs\").existsSync);\n\ndescribe(\"Deploy Command Integration Tests\", () => {\n let requestCapture: RequestCapture;\n\n beforeEach(() => {\n setupTestEnvironment();\n requestCapture = new RequestCapture();\n\n // Disable real HTTP requests\n nock.disableNetConnect();\n\n // Clear mock calls from previous tests\n jest.clearAllMocks();\n\n mockExistsSync.mockReturnValue(false);\n mockReaddirSync.mockReturnValue([]);\n mockReadFileSync.mockImplementation((filePath: string) => {\n if (filePath.endsWith(\"tls.crt\")) {\n return \"mock-cert-content\";\n }\n if (filePath.endsWith(\"tls.key\")) {\n return \"mock-key-content\";\n }\n return Buffer.from(\"mock-tarball-content\");\n });\n });\n\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n describe(\"SaaS deployment\", () => {\n it(\"should intercept POST request to get source upload URL\", async () => {\n const mockUploadUrlResponse = {\n uploadUrl: \"https://storage.example.com/upload/abc123\",\n deploymentId: \"deployment-456\",\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(200, mockUploadUrlResponse);\n\n // Mock the upload to cloud storage\n const uploadScope = nock(\"https://storage.example.com\")\n .put(\"/upload/abc123\")\n .reply(200, { message: \"Upload successful\" });\n\n [scope, uploadScope].forEach((s) => {\n s.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n expect(uploadScope.isDone()).toBe(true);\n\n // Verify successful deployment message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n \"Deployed to https://test-project-main.zuplo.app\"\n ),\n expect.any(Object) // spinner object\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-saas-requests\");\n\n // Verify the source-url request payload\n const sourceUrlRequest = capturedRequests.find(\n (req) => req.path === \"/v1/deployments/source-url\"\n );\n expect(sourceUrlRequest?.method).toBe(\"POST\");\n expect(sourceUrlRequest?.body).toEqual({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n environment: \"main\",\n repositoryUrl: \"https://github.com/user/repo.git\",\n sha: \"abc123\",\n });\n });\n\n it(\"should handle upload URL request failure\", async () => {\n const errorResponse = {\n error: \"Forbidden\",\n message: \"Insufficient permissions\",\n statusCode: 403,\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(403, errorResponse);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await expect(\n executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(scope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-saas-error-requests\");\n });\n });\n\n describe(\"Self-hosted deployment\", () => {\n it(\"should intercept POST request to self-hosted build endpoint\", async () => {\n const selfHostedEndpoint = \"https://my-zuplo.company.com\";\n const mockBuildResponse = {\n buildName: \"build-789\",\n };\n\n const buildScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .post(\"/v1/deployments/build\")\n .reply(200, mockBuildResponse);\n\n // Mock deployment retrieval after build completion\n const deploymentScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .get(\"/v1/deployments/test-project-main\")\n .reply(200, {\n deploymentUrl: \"https://my-zuplo.company.com/test-project-main\",\n });\n\n [buildScope, deploymentScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n \"self-hosted-endpoint\": selfHostedEndpoint,\n dir: \".\",\n });\n\n expect(buildScope.isDone()).toBe(true);\n expect(deploymentScope.isDone()).toBe(true);\n\n // Verify successful deployment message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n \"Deployed to https://my-zuplo.company.com/test-project-main\"\n ),\n expect.any(Object) // spinner object\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-self-hosted-requests\");\n\n // Verify the build request\n const buildRequest = capturedRequests.find(\n (req) => req.path === \"/v1/deployments/build\"\n );\n expect(buildRequest?.method).toBe(\"POST\");\n // Note: FormData body won't be easily testable in snapshots, but we can verify it exists\n expect(buildRequest?.body).toBeDefined();\n }, 60000); // Increase timeout for this complex test\n\n it(\"should handle self-hosted build failure\", async () => {\n const selfHostedEndpoint = \"https://my-zuplo.company.com\";\n const errorResponse = {\n error: \"Bad Request\",\n message: \"Invalid project configuration\",\n statusCode: 400,\n };\n\n const scope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .post(\"/v1/deployments/build\")\n .reply(400, errorResponse);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n \"self-hosted-endpoint\": selfHostedEndpoint,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"deploy-self-hosted-error-requests\"\n );\n }, 60000); // Increase timeout for this test too\n\n it(\"should include mtls certificates from mtls-certificates-dir\", async () => {\n const selfHostedEndpoint = \"https://my-zuplo.company.com\";\n const mockBuildResponse = {\n buildName: \"build-789\",\n };\n let capturedBuildRequestBody = \"\";\n\n mockReaddirSync.mockReturnValue([\n {\n name: \"cert-name-2\",\n isDirectory: () => true,\n },\n {\n name: \"cert-name-1\",\n isDirectory: () => true,\n },\n ]);\n mockReadFileSync.mockImplementation((filePath: string) => {\n if (/cert-name-1[\\\\/]tls\\.crt$/.test(filePath)) {\n return \"CERT_1\";\n }\n if (/cert-name-1[\\\\/]tls\\.key$/.test(filePath)) {\n return \"KEY_1\";\n }\n if (/cert-name-2[\\\\/]tls\\.crt$/.test(filePath)) {\n return \"CERT_2\";\n }\n if (/cert-name-2[\\\\/]tls\\.key$/.test(filePath)) {\n return \"KEY_2\";\n }\n return Buffer.from(\"mock-tarball-content\");\n });\n\n const buildScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .post(\"/v1/deployments/build\", (body) => {\n capturedBuildRequestBody = Buffer.isBuffer(body)\n ? body.toString(\"utf-8\")\n : String(body);\n return true;\n })\n .reply(200, mockBuildResponse);\n\n const deploymentScope = setupAuthenticatedNock(nock(selfHostedEndpoint))\n .get(\"/v1/deployments/test-project-main\")\n .reply(200, {\n deploymentUrl: \"https://my-zuplo.company.com/test-project-main\",\n });\n\n [buildScope, deploymentScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n \"self-hosted-endpoint\": selfHostedEndpoint,\n \"mtls-certificates-dir\": \"./mtls\",\n dir: \".\",\n });\n\n expect(buildScope.isDone()).toBe(true);\n expect(deploymentScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n const buildRequest = capturedRequests.find(\n (req) => req.path === \"/v1/deployments/build\"\n );\n\n expect(buildRequest?.method).toBe(\"POST\");\n expect(capturedBuildRequestBody).toContain('name=\"mtlsCertificate\"');\n expect(\n (capturedBuildRequestBody.match(/name=\"mtlsCertificate\"/g) || []).length\n ).toBe(2);\n expect(capturedBuildRequestBody).toContain('\"certName\":\"cert-name-1\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsCrt\":\"CERT_1\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsKey\":\"KEY_1\"');\n expect(capturedBuildRequestBody).toContain('\"certName\":\"cert-name-2\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsCrt\":\"CERT_2\"');\n expect(capturedBuildRequestBody).toContain('\"mtlsKey\":\"KEY_2\"');\n\n expect(\n capturedBuildRequestBody.indexOf('\"certName\":\"cert-name-1\"')\n ).toBeLessThan(\n capturedBuildRequestBody.indexOf('\"certName\":\"cert-name-2\"')\n );\n }, 60000);\n });\n\n describe(\"Directory argument handling\", () => {\n it(\"should work when --dir is not specified (uses default)\", async () => {\n const mockUploadUrlResponse = {\n uploadUrl: \"https://storage.example.com/upload/default-test\",\n deploymentId: \"deployment-default\",\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(200, mockUploadUrlResponse);\n\n // Mock the upload to cloud storage\n const uploadScope = nock(\"https://storage.example.com\")\n .put(\"/upload/default-test\")\n .reply(200, { message: \"Upload successful\" });\n\n [scope, uploadScope].forEach((s) => {\n s.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n // Note: Not passing dir argument at all - should default to \".\"\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(scope.isDone()).toBe(true);\n expect(uploadScope.isDone()).toBe(true);\n\n // Verify successful deployment message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n \"Deployed to https://test-project-main.zuplo.app\"\n ),\n expect.any(Object)\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-default-dir-requests\");\n });\n\n it(\"should work with explicit --dir=.\", async () => {\n const mockUploadUrlResponse = {\n uploadUrl: \"https://storage.example.com/upload/explicit-dot\",\n deploymentId: \"deployment-dot\",\n };\n\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .post(\"/v1/deployments/source-url\")\n .reply(200, mockUploadUrlResponse);\n\n const uploadScope = nock(\"https://storage.example.com\")\n .put(\"/upload/explicit-dot\")\n .reply(200, { message: \"Upload successful\" });\n\n [scope, uploadScope].forEach((s) => {\n s.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n expect(uploadScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-explicit-dot-requests\");\n });\n });\n\n describe(\"Request validation\", () => {\n it(\"should include correct headers for SaaS deployment\", async () => {\n const mockResponse = {\n uploadUrl: \"https://storage.example.com/upload/abc123\",\n deploymentId: \"deployment-456\",\n };\n\n const scope = nock(TEST_API_BASE)\n .post(\"/v1/deployments/source-url\")\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, mockResponse);\n\n // Mock the upload endpoint\n nock(\"https://storage.example.com\").put(\"/upload/abc123\").reply(200);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await executeDeployCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(scope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"deploy-headers-validation\");\n });\n });\n});\n"]}
|
|
@@ -5,6 +5,9 @@ jest.mock("../../common/output.js", () => ({
|
|
|
5
5
|
printResultToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),
|
|
6
6
|
printTableToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),
|
|
7
7
|
printJsonToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),
|
|
8
|
+
printCancellationToConsoleAndExitGracefully: jest
|
|
9
|
+
.fn()
|
|
10
|
+
.mockResolvedValue(undefined),
|
|
8
11
|
printResultToConsole: jest.fn().mockResolvedValue(undefined),
|
|
9
12
|
printJsonToConsole: jest.fn().mockResolvedValue(undefined),
|
|
10
13
|
printDiagnosticsToConsole: jest.fn(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jest-mocks-setup.js","sourceRoot":"","sources":["../../../src/__tests__/integration/jest-mocks-setup.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Jest mocks setup - loaded before all test modules\n * This file contains all the Jest mocks that need to be applied before any modules are imported\n */\nimport type { Ora } from \"ora\";\n\nconst TEST_AUTH_TOKEN = \"test-auth-token-123\";\n\n// Mock all output functions to prevent actual console output and process.exit calls\njest.mock(\"../../common/output.js\", () => ({\n __esModule: true,\n default: jest.fn((argv: unknown) => argv), // setBlocking middleware function\n printResultToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),\n printTableToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),\n printJsonToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),\n printResultToConsole: jest.fn().mockResolvedValue(undefined),\n printJsonToConsole: jest.fn().mockResolvedValue(undefined),\n printDiagnosticsToConsole: jest.fn(),\n printWarningToConsole: jest.fn(),\n printSpinnerToConsole: jest.fn().mockReturnValue({\n stop: jest.fn(),\n succeed: jest.fn(),\n fail: jest.fn(),\n suffixText: \"\",\n } as unknown as Ora),\n printCriticalFailureToConsole: jest.fn(),\n printCriticalFailureToConsoleAndExit: jest.fn().mockImplementation(() => {\n throw new Error(\"Process would exit\");\n }),\n textOrJson: jest.fn((text: string) => {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }),\n}));\n\n// Mock analytics\njest.mock(\"../../common/analytics/lib.js\", () => ({\n captureEvent: jest.fn().mockResolvedValue(undefined),\n}));\n\n// Mock authentication middleware to add authToken\njest.mock(\"../../common/middleware/authentication.js\", () => ({\n authenticate: jest.fn((argv: Record<string, unknown>) => {\n argv.authToken = TEST_AUTH_TOKEN;\n return argv;\n }),\n authenticateNoPrompt: jest.fn((argv: Record<string, unknown>) => {\n argv.authToken = TEST_AUTH_TOKEN;\n return argv;\n }),\n}));\n\n// Mock inquirer prompts to return predictable values for tests\njest.mock(\"@inquirer/prompts\", () => {\n class MockSeparator {\n type = \"separator\";\n separator: string;\n constructor(separator = \"──────────────\") {\n this.separator = separator;\n }\n static isSeparator(item: unknown): boolean {\n return (\n item != null &&\n typeof item === \"object\" &&\n (item as { type?: unknown }).type === \"separator\"\n );\n }\n }\n return {\n Separator: MockSeparator,\n select: jest.fn().mockImplementation(({ choices }) => {\n if (Array.isArray(choices) && choices.length > 0) {\n // Skip separators (no `value`) and null-sentinel choices, then return\n // the first real choice's value.\n const firstReal =\n choices.find(\n (c) =>\n !MockSeparator.isSeparator(c) &&\n (c as { value?: unknown }).value !== null\n ) ?? choices[0];\n return Promise.resolve((firstReal as { value: unknown }).value);\n }\n return Promise.resolve(\"test-default\");\n }),\n input: jest.fn().mockResolvedValue(\"test-new-project\"),\n };\n});\n\n// Mock other middleware to pass through arguments\njest.mock(\"../../common/middleware/user-configuration.js\", () => ({\n configure: jest.fn((argv: unknown) => argv),\n}));\n\njest.mock(\"../../common/middleware/user-identification.js\", () => ({\n identify: jest.fn((argv: unknown) => argv),\n}));\n\n// Mock validators to pass through\njest.mock(\"../../common/validators/lib.js\", () => ({\n YargsChecker: jest.fn().mockImplementation(() => ({\n check: jest.fn().mockResolvedValue(true),\n })),\n}));\n\n// Mock showHelpOnNoSubcommand helper for commands with subcommands\njest.mock(\"../../common/handler.js\", () => ({\n showHelpOnNoSubcommand: jest.fn((configure) => ({\n builder: (yargs: unknown) => (configure as (y: unknown) => unknown)(yargs),\n handler: jest.fn(),\n })),\n}));\n\n// Mock token functions to prevent file system and HTTP calls\njest.mock(\"../../login/tokens.js\", () => ({\n getAuthToken: jest.fn().mockResolvedValue(TEST_AUTH_TOKEN),\n refreshAccessToken: jest.fn().mockResolvedValue({\n access_token: TEST_AUTH_TOKEN,\n id_token: \"mock-id-token\",\n expires_in: 3600,\n token_type: \"Bearer\",\n scope: \"openid profile email\",\n }),\n}));\n"]}
|
|
1
|
+
{"version":3,"file":"jest-mocks-setup.js","sourceRoot":"","sources":["../../../src/__tests__/integration/jest-mocks-setup.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Jest mocks setup - loaded before all test modules\n * This file contains all the Jest mocks that need to be applied before any modules are imported\n */\nimport type { Ora } from \"ora\";\n\nconst TEST_AUTH_TOKEN = \"test-auth-token-123\";\n\n// Mock all output functions to prevent actual console output and process.exit calls\njest.mock(\"../../common/output.js\", () => ({\n __esModule: true,\n default: jest.fn((argv: unknown) => argv), // setBlocking middleware function\n printResultToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),\n printTableToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),\n printJsonToConsoleAndExitGracefully: jest.fn().mockResolvedValue(undefined),\n printCancellationToConsoleAndExitGracefully: jest\n .fn()\n .mockResolvedValue(undefined),\n printResultToConsole: jest.fn().mockResolvedValue(undefined),\n printJsonToConsole: jest.fn().mockResolvedValue(undefined),\n printDiagnosticsToConsole: jest.fn(),\n printWarningToConsole: jest.fn(),\n printSpinnerToConsole: jest.fn().mockReturnValue({\n stop: jest.fn(),\n succeed: jest.fn(),\n fail: jest.fn(),\n suffixText: \"\",\n } as unknown as Ora),\n printCriticalFailureToConsole: jest.fn(),\n printCriticalFailureToConsoleAndExit: jest.fn().mockImplementation(() => {\n throw new Error(\"Process would exit\");\n }),\n textOrJson: jest.fn((text: string) => {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }),\n}));\n\n// Mock analytics\njest.mock(\"../../common/analytics/lib.js\", () => ({\n captureEvent: jest.fn().mockResolvedValue(undefined),\n}));\n\n// Mock authentication middleware to add authToken\njest.mock(\"../../common/middleware/authentication.js\", () => ({\n authenticate: jest.fn((argv: Record<string, unknown>) => {\n argv.authToken = TEST_AUTH_TOKEN;\n return argv;\n }),\n authenticateNoPrompt: jest.fn((argv: Record<string, unknown>) => {\n argv.authToken = TEST_AUTH_TOKEN;\n return argv;\n }),\n}));\n\n// Mock inquirer prompts to return predictable values for tests\njest.mock(\"@inquirer/prompts\", () => {\n class MockSeparator {\n type = \"separator\";\n separator: string;\n constructor(separator = \"──────────────\") {\n this.separator = separator;\n }\n static isSeparator(item: unknown): boolean {\n return (\n item != null &&\n typeof item === \"object\" &&\n (item as { type?: unknown }).type === \"separator\"\n );\n }\n }\n return {\n Separator: MockSeparator,\n select: jest.fn().mockImplementation(({ choices }) => {\n if (Array.isArray(choices) && choices.length > 0) {\n // Skip separators (no `value`) and null-sentinel choices, then return\n // the first real choice's value.\n const firstReal =\n choices.find(\n (c) =>\n !MockSeparator.isSeparator(c) &&\n (c as { value?: unknown }).value !== null\n ) ?? choices[0];\n return Promise.resolve((firstReal as { value: unknown }).value);\n }\n return Promise.resolve(\"test-default\");\n }),\n input: jest.fn().mockResolvedValue(\"test-new-project\"),\n };\n});\n\n// Mock other middleware to pass through arguments\njest.mock(\"../../common/middleware/user-configuration.js\", () => ({\n configure: jest.fn((argv: unknown) => argv),\n}));\n\njest.mock(\"../../common/middleware/user-identification.js\", () => ({\n identify: jest.fn((argv: unknown) => argv),\n}));\n\n// Mock validators to pass through\njest.mock(\"../../common/validators/lib.js\", () => ({\n YargsChecker: jest.fn().mockImplementation(() => ({\n check: jest.fn().mockResolvedValue(true),\n })),\n}));\n\n// Mock showHelpOnNoSubcommand helper for commands with subcommands\njest.mock(\"../../common/handler.js\", () => ({\n showHelpOnNoSubcommand: jest.fn((configure) => ({\n builder: (yargs: unknown) => (configure as (y: unknown) => unknown)(yargs),\n handler: jest.fn(),\n })),\n}));\n\n// Mock token functions to prevent file system and HTTP calls\njest.mock(\"../../login/tokens.js\", () => ({\n getAuthToken: jest.fn().mockResolvedValue(TEST_AUTH_TOKEN),\n refreshAccessToken: jest.fn().mockResolvedValue({\n access_token: TEST_AUTH_TOKEN,\n id_token: \"mock-id-token\",\n expires_in: 3600,\n token_type: \"Bearer\",\n scope: \"openid profile email\",\n }),\n}));\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import nock from "nock";
|
|
2
2
|
import yargs from "yargs/yargs";
|
|
3
3
|
import whoamiCommand from "../../cmds/whoami.js";
|
|
4
|
+
import { getAuthToken } from "../../login/tokens.js";
|
|
4
5
|
import { cleanupTest, RequestCapture, setupAuthenticatedNock, setupTestEnvironment, TEST_API_BASE, TEST_AUTH_TOKEN, } from "./test-utils.js";
|
|
5
6
|
const TEST_SUB = "google-oauth2|123456789";
|
|
6
7
|
const TEST_EMAIL = "user@example.com";
|
|
@@ -75,6 +76,32 @@ describe("Whoami Command Integration Tests", () => {
|
|
|
75
76
|
expect(scope.isDone()).toBe(true);
|
|
76
77
|
expect(mockPrintResult).toHaveBeenCalledWith(`Authenticated as ${TEST_SUB}`);
|
|
77
78
|
});
|
|
79
|
+
it("should fall back to the stored auth token when --api-key is omitted", async () => {
|
|
80
|
+
const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
81
|
+
.get("/v1/who-am-i")
|
|
82
|
+
.matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
|
|
83
|
+
.reply(200, { sub: TEST_SUB, email: TEST_EMAIL });
|
|
84
|
+
await executeWhoamiCommand({});
|
|
85
|
+
expect(scope.isDone()).toBe(true);
|
|
86
|
+
expect(jest.mocked(getAuthToken)).toHaveBeenCalled();
|
|
87
|
+
expect(mockPrintResult).toHaveBeenCalledWith(`Authenticated as ${TEST_EMAIL} (${TEST_SUB})`);
|
|
88
|
+
});
|
|
89
|
+
it("should fall back to the stored auth token when --api-key is empty", async () => {
|
|
90
|
+
const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
91
|
+
.get("/v1/who-am-i")
|
|
92
|
+
.matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
|
|
93
|
+
.reply(200, { sub: TEST_SUB });
|
|
94
|
+
await executeWhoamiCommand({ "api-key": " " });
|
|
95
|
+
expect(scope.isDone()).toBe(true);
|
|
96
|
+
expect(jest.mocked(getAuthToken)).toHaveBeenCalled();
|
|
97
|
+
expect(mockPrintResult).toHaveBeenCalledWith(`Authenticated as ${TEST_SUB}`);
|
|
98
|
+
});
|
|
99
|
+
it("should report logged out when no auth token is available", async () => {
|
|
100
|
+
jest.mocked(getAuthToken).mockResolvedValueOnce(undefined);
|
|
101
|
+
await executeWhoamiCommand({});
|
|
102
|
+
expect(mockPrintResult).toHaveBeenCalledWith("You are logged out");
|
|
103
|
+
expect(mockPrintCriticalFailure).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
78
105
|
it("should fail when the API returns an error", async () => {
|
|
79
106
|
const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
80
107
|
.get("/v1/who-am-i")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whoami.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/whoami.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the whoami command\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport yargs from \"yargs/yargs\";\nimport whoamiCommand from \"../../cmds/whoami.js\";\nimport {\n cleanupTest,\n RequestCapture,\n setupAuthenticatedNock,\n setupTestEnvironment,\n TEST_API_BASE,\n TEST_AUTH_TOKEN,\n} from \"./test-utils.js\";\n\nconst TEST_SUB = \"google-oauth2|123456789\";\nconst TEST_EMAIL = \"user@example.com\";\nconst TEST_ACCOUNT = \"chocolate-blizzard\";\n\nasync function executeWhoamiCommand(args: { \"api-key\"?: string }) {\n const yargsInstance = yargs([])\n .command(whoamiCommand)\n .help(false)\n .version(false)\n .exitProcess(false);\n\n const commandArgs = [\"whoami\"];\n\n if (args[\"api-key\"]) {\n commandArgs.push(\"--api-key\", args[\"api-key\"]);\n }\n\n return await yargsInstance.parse(commandArgs);\n}\n\nconst mockPrintResult = jest.mocked(\n require(\"../../common/output.js\").printResultToConsoleAndExitGracefully\n);\nconst mockPrintCriticalFailure = jest.mocked(\n require(\"../../common/output.js\").printCriticalFailureToConsoleAndExit\n);\n\ndescribe(\"Whoami Command Integration Tests\", () => {\n let requestCapture: RequestCapture;\n\n beforeEach(() => {\n setupTestEnvironment();\n nock.cleanAll();\n requestCapture = new RequestCapture();\n\n nock.disableNetConnect();\n\n jest.clearAllMocks();\n });\n\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n it(\"should print sub when only sub is returned\", async () => {\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .reply(200, { sub: TEST_SUB });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}`\n );\n });\n\n it(\"should include email and account when returned\", async () => {\n setupAuthenticatedNock(nock(TEST_API_BASE)).get(\"/v1/who-am-i\").reply(200, {\n sub: TEST_SUB,\n email: TEST_EMAIL,\n account: TEST_ACCOUNT,\n });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_EMAIL} (${TEST_SUB})\\nAccount: ${TEST_ACCOUNT}`\n );\n });\n\n it(\"should include account without email when only account is returned\", async () => {\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .reply(200, { sub: TEST_SUB, account: TEST_ACCOUNT });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}\\nAccount: ${TEST_ACCOUNT}`\n );\n });\n\n it(\"should include the authorization header\", async () => {\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, { sub: TEST_SUB });\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(scope.isDone()).toBe(true);\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}`\n );\n });\n\n it(\"should fail when the API returns an error\", async () => {\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .reply(401, { error: \"Unauthorized\" });\n\n await expect(\n executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n })\n ).rejects.toThrow(\"Failed to determine current user\");\n\n expect(scope.isDone()).toBe(true);\n expect(mockPrintCriticalFailure).not.toHaveBeenCalled();\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"whoami.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/whoami.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the whoami command\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport yargs from \"yargs/yargs\";\nimport whoamiCommand from \"../../cmds/whoami.js\";\nimport { getAuthToken } from \"../../login/tokens.js\";\nimport {\n cleanupTest,\n RequestCapture,\n setupAuthenticatedNock,\n setupTestEnvironment,\n TEST_API_BASE,\n TEST_AUTH_TOKEN,\n} from \"./test-utils.js\";\n\nconst TEST_SUB = \"google-oauth2|123456789\";\nconst TEST_EMAIL = \"user@example.com\";\nconst TEST_ACCOUNT = \"chocolate-blizzard\";\n\nasync function executeWhoamiCommand(args: { \"api-key\"?: string }) {\n const yargsInstance = yargs([])\n .command(whoamiCommand)\n .help(false)\n .version(false)\n .exitProcess(false);\n\n const commandArgs = [\"whoami\"];\n\n if (args[\"api-key\"]) {\n commandArgs.push(\"--api-key\", args[\"api-key\"]);\n }\n\n return await yargsInstance.parse(commandArgs);\n}\n\nconst mockPrintResult = jest.mocked(\n require(\"../../common/output.js\").printResultToConsoleAndExitGracefully\n);\nconst mockPrintCriticalFailure = jest.mocked(\n require(\"../../common/output.js\").printCriticalFailureToConsoleAndExit\n);\n\ndescribe(\"Whoami Command Integration Tests\", () => {\n let requestCapture: RequestCapture;\n\n beforeEach(() => {\n setupTestEnvironment();\n nock.cleanAll();\n requestCapture = new RequestCapture();\n\n nock.disableNetConnect();\n\n jest.clearAllMocks();\n });\n\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n it(\"should print sub when only sub is returned\", async () => {\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .reply(200, { sub: TEST_SUB });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}`\n );\n });\n\n it(\"should include email and account when returned\", async () => {\n setupAuthenticatedNock(nock(TEST_API_BASE)).get(\"/v1/who-am-i\").reply(200, {\n sub: TEST_SUB,\n email: TEST_EMAIL,\n account: TEST_ACCOUNT,\n });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_EMAIL} (${TEST_SUB})\\nAccount: ${TEST_ACCOUNT}`\n );\n });\n\n it(\"should include account without email when only account is returned\", async () => {\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .reply(200, { sub: TEST_SUB, account: TEST_ACCOUNT });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}\\nAccount: ${TEST_ACCOUNT}`\n );\n });\n\n it(\"should include the authorization header\", async () => {\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, { sub: TEST_SUB });\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n await executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n });\n\n expect(scope.isDone()).toBe(true);\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}`\n );\n });\n\n it(\"should fall back to the stored auth token when --api-key is omitted\", async () => {\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, { sub: TEST_SUB, email: TEST_EMAIL });\n\n await executeWhoamiCommand({});\n\n expect(scope.isDone()).toBe(true);\n expect(jest.mocked(getAuthToken)).toHaveBeenCalled();\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_EMAIL} (${TEST_SUB})`\n );\n });\n\n it(\"should fall back to the stored auth token when --api-key is empty\", async () => {\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, { sub: TEST_SUB });\n\n await executeWhoamiCommand({ \"api-key\": \" \" });\n\n expect(scope.isDone()).toBe(true);\n expect(jest.mocked(getAuthToken)).toHaveBeenCalled();\n expect(mockPrintResult).toHaveBeenCalledWith(\n `Authenticated as ${TEST_SUB}`\n );\n });\n\n it(\"should report logged out when no auth token is available\", async () => {\n jest.mocked(getAuthToken).mockResolvedValueOnce(undefined);\n\n await executeWhoamiCommand({});\n\n expect(mockPrintResult).toHaveBeenCalledWith(\"You are logged out\");\n expect(mockPrintCriticalFailure).not.toHaveBeenCalled();\n });\n\n it(\"should fail when the API returns an error\", async () => {\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/who-am-i\")\n .reply(401, { error: \"Unauthorized\" });\n\n await expect(\n executeWhoamiCommand({\n \"api-key\": TEST_AUTH_TOKEN,\n })\n ).rejects.toThrow(\"Failed to determine current user\");\n\n expect(scope.isDone()).toBe(true);\n expect(mockPrintCriticalFailure).not.toHaveBeenCalled();\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/bucket/list/handler.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAsBD,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,iBAuDzC"}
|