@zuplo/cli 6.68.10 → 6.68.15
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/link.integration.test.js +59 -1
- package/dist/__tests__/integration/link.integration.test.js.map +1 -1
- package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js +81 -0
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js.map +1 -0
- package/dist/__tests__/populate.test.js +61 -18
- package/dist/__tests__/populate.test.js.map +1 -1
- package/dist/cmds/link.d.ts.map +1 -1
- package/dist/cmds/link.js +2 -0
- package/dist/cmds/link.js.map +1 -1
- package/dist/common/middleware/get-account-param.d.ts.map +1 -1
- package/dist/common/middleware/get-account-param.js +12 -0
- package/dist/common/middleware/get-account-param.js.map +1 -1
- package/dist/common/middleware/get-environment-param.d.ts.map +1 -1
- package/dist/common/middleware/get-environment-param.js +1 -1
- package/dist/common/middleware/get-environment-param.js.map +1 -1
- package/dist/common/middleware/get-project-param.d.ts.map +1 -1
- package/dist/common/middleware/get-project-param.js +12 -0
- package/dist/common/middleware/get-project-param.js.map +1 -1
- package/dist/common/populate.js.map +1 -1
- package/dist/common/read-linked-config.d.ts +13 -0
- package/dist/common/read-linked-config.d.ts.map +1 -0
- package/dist/common/read-linked-config.js +56 -0
- package/dist/common/read-linked-config.js.map +1 -0
- package/dist/common/read-linked-config.test.d.ts +2 -0
- package/dist/common/read-linked-config.test.d.ts.map +1 -0
- package/dist/common/read-linked-config.test.js +238 -0
- package/dist/common/read-linked-config.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import nock from "nock";
|
|
2
2
|
import yargs from "yargs/yargs";
|
|
3
3
|
import linkCommand from "../../cmds/link.js";
|
|
4
|
+
import { confirmLinkedValue, readLinkedConfig, } from "../../common/read-linked-config.js";
|
|
4
5
|
import { cleanupTest, RequestCapture, setupAuthenticatedNock, setupTestEnvironment, TEST_ACCOUNT_NAME, TEST_API_BASE, TEST_AUTH_TOKEN, TEST_PROJECT_NAME, } from "./test-utils.js";
|
|
6
|
+
jest.mock("../../common/read-linked-config.js", () => ({
|
|
7
|
+
__esModule: true,
|
|
8
|
+
confirmLinkedValue: jest.fn().mockResolvedValue(true),
|
|
9
|
+
readLinkedConfig: jest.fn().mockResolvedValue({}),
|
|
10
|
+
USE_LINKED_DETAILS: "useLinkedDetails",
|
|
11
|
+
ignoreLinkedDetails: jest
|
|
12
|
+
.fn()
|
|
13
|
+
.mockImplementation((argv) => {
|
|
14
|
+
argv["useLinkedDetails"] = false;
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
5
17
|
jest.mock("../../common/validators/file-system-validator.js", () => ({
|
|
6
18
|
ZuploProjectValidator: jest.fn().mockImplementation(() => ({
|
|
7
19
|
validate: jest.fn().mockResolvedValue(true),
|
|
@@ -202,7 +214,7 @@ describe("Link Command Integration Tests", () => {
|
|
|
202
214
|
expect(deploymentsScope.isDone()).toBe(true);
|
|
203
215
|
const capturedRequests = requestCapture.getRequests();
|
|
204
216
|
expect(capturedRequests.length).toBeGreaterThan(0);
|
|
205
|
-
expect(mockPrintCriticalFailure).toHaveBeenCalledWith(expect.stringContaining("
|
|
217
|
+
expect(mockPrintCriticalFailure).toHaveBeenCalledWith(expect.stringContaining("any environments"));
|
|
206
218
|
});
|
|
207
219
|
});
|
|
208
220
|
describe("Error handling", () => {
|
|
@@ -316,5 +328,51 @@ describe("Link Command Integration Tests", () => {
|
|
|
316
328
|
expect(capturedRequests).toMatchSnapshot("link-headers-validation");
|
|
317
329
|
});
|
|
318
330
|
});
|
|
331
|
+
describe("Link always re-prompts from scratch", () => {
|
|
332
|
+
it("should not offer linked account/project/environment even when .env.zuplo is present", async () => {
|
|
333
|
+
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
334
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
335
|
+
projectName: TEST_PROJECT_NAME,
|
|
336
|
+
});
|
|
337
|
+
jest
|
|
338
|
+
.mocked(confirmLinkedValue)
|
|
339
|
+
.mockRejectedValue(new Error("link should never call confirmLinkedValue"));
|
|
340
|
+
const accountsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
341
|
+
.get("/v1/accounts")
|
|
342
|
+
.reply(200, {
|
|
343
|
+
data: [{ name: TEST_ACCOUNT_NAME }],
|
|
344
|
+
});
|
|
345
|
+
const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
346
|
+
.get("/v1/projects")
|
|
347
|
+
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
348
|
+
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
349
|
+
const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
350
|
+
.get("/v1/environments")
|
|
351
|
+
.query({
|
|
352
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
353
|
+
projectName: TEST_PROJECT_NAME,
|
|
354
|
+
})
|
|
355
|
+
.reply(200, {
|
|
356
|
+
data: [
|
|
357
|
+
{
|
|
358
|
+
name: "development",
|
|
359
|
+
environmentType: "development",
|
|
360
|
+
branchName: "main",
|
|
361
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
362
|
+
projectName: TEST_PROJECT_NAME,
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
});
|
|
366
|
+
const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
367
|
+
.get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`)
|
|
368
|
+
.reply(200, { data: [] });
|
|
369
|
+
await executeLinkCommand({ dir: "." });
|
|
370
|
+
expect(accountsScope.isDone()).toBe(true);
|
|
371
|
+
expect(projectsScope.isDone()).toBe(true);
|
|
372
|
+
expect(environmentsScope.isDone()).toBe(true);
|
|
373
|
+
expect(deploymentsScope.isDone()).toBe(true);
|
|
374
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
375
|
+
});
|
|
376
|
+
});
|
|
319
377
|
});
|
|
320
378
|
//# sourceMappingURL=link.integration.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/link.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the link command\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport yargs from \"yargs/yargs\";\nimport linkCommand from \"../../cmds/link.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 ZuploProjectValidator: jest.fn().mockImplementation(() => ({\n validate: jest.fn().mockResolvedValue(true),\n })),\n}));\n\n// Mock link population functions to prevent file system operations\njest.mock(\"../../common/populate.js\", () => ({\n pullSystemConfig: jest.fn().mockResolvedValue(undefined),\n pullLocalConfig: jest.fn().mockResolvedValue(undefined),\n safeMergeConfig: jest.fn().mockResolvedValue(undefined),\n}));\n\n/**\n * Execute link command with given arguments using actual yargs command\n */\nasync function executeLinkCommand(args: {\n account?: string;\n project?: string;\n \"api-key\"?: string;\n environment?: string;\n dir?: string;\n}) {\n const yargsInstance = yargs([])\n .command(linkCommand)\n .help(false)\n .version(false)\n .exitProcess(false);\n\n // Build command line arguments\n const commandArgs = [\"link\"];\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.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 mockPrintCriticalFailure = jest.mocked(\n require(\"../../common/output.js\").printCriticalFailureToConsoleAndExit\n);\n\ndescribe(\"Link 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\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n describe(\"Link with project and environment specified\", () => {\n it(\"should skip API calls when project and environment are provided\", async () => {\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n environment: \"development\",\n dir: \".\",\n });\n\n // Verify successful linking message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n `Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`\n )\n );\n\n // No HTTP requests should be made when all params are provided\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toEqual([]);\n });\n });\n\n describe(\"Link with automatic project selection\", () => {\n it(\"should intercept GET request to list projects\", async () => {\n const mockProjectsResponse = {\n data: [\n {\n name: TEST_PROJECT_NAME,\n accountName: TEST_ACCOUNT_NAME,\n description: \"Test project\",\n createdAt: \"2024-01-01T00:00:00Z\",\n },\n ],\n };\n\n const mockEnvironmentsResponse = {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n },\n ],\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(200, mockEnvironmentsResponse);\n\n // Mock the deployments endpoint (used to surface working-copy deployments)\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n `Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`\n )\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"link-automatic-selection-requests\"\n );\n });\n\n it(\"should handle multiple projects and prompt selection\", async () => {\n const mockProjectsResponse = {\n data: [\n { name: \"project-1\", accountName: TEST_ACCOUNT_NAME },\n { name: \"project-2\", accountName: TEST_ACCOUNT_NAME },\n ],\n };\n\n const mockEnvironmentsResponse = {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: \"project-1\", // inquirer mock will select first project\n },\n ],\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments (will use first project from inquirer mock)\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: \"project-1\",\n })\n .reply(200, mockEnvironmentsResponse);\n\n // Mock the deployments endpoint (used to surface working-copy deployments)\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/project-1/deployments`)\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"link-multiple-projects-requests\"\n );\n });\n });\n\n describe(\"Link error handling\", () => {\n it(\"should fail when no environments exist\", async () => {\n const mockProjectsResponse = {\n data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],\n };\n\n const mockEmptyEnvironmentsResponse = { data: [] };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the environments call (returns empty)\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(200, mockEmptyEnvironmentsResponse);\n\n // Mock the deployments endpoint (also returns empty - no working copies either)\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n // Should throw because there are no environments to link against\n await expect(\n executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests.length).toBeGreaterThan(0);\n\n // Verify the critical failure was called with the right message\n expect(mockPrintCriticalFailure).toHaveBeenCalledWith(\n expect.stringContaining(\"preview or production environments\")\n );\n });\n });\n\n describe(\"Error handling\", () => {\n it(\"should handle projects list failure\", async () => {\n const errorResponse = {\n error: \"Unauthorized\",\n message: \"Invalid API key\",\n statusCode: 401,\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(401, errorResponse);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n // Expect the function to throw (simulating process exit)\n await expect(\n executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(scope.isDone()).toBe(true);\n expect(mockPrintCriticalFailure).toHaveBeenCalled();\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"link-projects-error-requests\");\n });\n\n it(\"should handle environments list failure\", async () => {\n const mockProjectsResponse = {\n data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],\n };\n\n const errorResponse = {\n error: \"Forbidden\",\n message: \"Access denied to project\",\n statusCode: 403,\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments (will fail)\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(403, errorResponse);\n\n [projectsScope, environmentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n // Expect the function to throw (simulating process exit)\n await expect(\n executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(mockPrintCriticalFailure).toHaveBeenCalled();\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"link-environments-error-requests\"\n );\n });\n });\n\n describe(\"Request validation\", () => {\n it(\"should include correct headers for API requests\", async () => {\n const mockProjectsResponse = {\n data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],\n };\n\n const mockEnvironmentsResponse = {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n },\n ],\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = nock(TEST_API_BASE)\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments\n const environmentsScope = nock(TEST_API_BASE)\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, mockEnvironmentsResponse);\n\n // Mock the deployments endpoint (used to surface working-copy deployments)\n const deploymentsScope = nock(TEST_API_BASE)\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"link-headers-validation\");\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"link.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/link.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the link command\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport yargs from \"yargs/yargs\";\nimport linkCommand from \"../../cmds/link.js\";\nimport {\n confirmLinkedValue,\n readLinkedConfig,\n} from \"../../common/read-linked-config.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 read-linked-config so tests can control linked state without touching the filesystem.\n// Default: no linked values and confirmLinkedValue always confirms — overridden per-test as needed.\njest.mock(\"../../common/read-linked-config.js\", () => ({\n __esModule: true,\n confirmLinkedValue: jest.fn().mockResolvedValue(true),\n readLinkedConfig: jest.fn().mockResolvedValue({}),\n USE_LINKED_DETAILS: \"useLinkedDetails\",\n ignoreLinkedDetails: jest\n .fn()\n .mockImplementation((argv: Record<string, unknown>) => {\n argv[\"useLinkedDetails\"] = false;\n }),\n}));\n\n// Mock file system validator\njest.mock(\"../../common/validators/file-system-validator.js\", () => ({\n ZuploProjectValidator: jest.fn().mockImplementation(() => ({\n validate: jest.fn().mockResolvedValue(true),\n })),\n}));\n\n// Mock link population functions to prevent file system operations\njest.mock(\"../../common/populate.js\", () => ({\n pullSystemConfig: jest.fn().mockResolvedValue(undefined),\n pullLocalConfig: jest.fn().mockResolvedValue(undefined),\n safeMergeConfig: jest.fn().mockResolvedValue(undefined),\n}));\n\n/**\n * Execute link command with given arguments using actual yargs command\n */\nasync function executeLinkCommand(args: {\n account?: string;\n project?: string;\n \"api-key\"?: string;\n environment?: string;\n dir?: string;\n}) {\n const yargsInstance = yargs([])\n .command(linkCommand)\n .help(false)\n .version(false)\n .exitProcess(false);\n\n // Build command line arguments\n const commandArgs = [\"link\"];\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.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 mockPrintCriticalFailure = jest.mocked(\n require(\"../../common/output.js\").printCriticalFailureToConsoleAndExit\n);\n\ndescribe(\"Link 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\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n describe(\"Link with project and environment specified\", () => {\n it(\"should skip API calls when project and environment are provided\", async () => {\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n project: TEST_PROJECT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n environment: \"development\",\n dir: \".\",\n });\n\n // Verify successful linking message\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n `Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`\n )\n );\n\n // No HTTP requests should be made when all params are provided\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toEqual([]);\n });\n });\n\n describe(\"Link with automatic project selection\", () => {\n it(\"should intercept GET request to list projects\", async () => {\n const mockProjectsResponse = {\n data: [\n {\n name: TEST_PROJECT_NAME,\n accountName: TEST_ACCOUNT_NAME,\n description: \"Test project\",\n createdAt: \"2024-01-01T00:00:00Z\",\n },\n ],\n };\n\n const mockEnvironmentsResponse = {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n },\n ],\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(200, mockEnvironmentsResponse);\n\n // Mock the deployments endpoint (used to surface working-copy deployments)\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n expect(mockPrintResult).toHaveBeenCalledWith(\n expect.stringContaining(\n `Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`\n )\n );\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"link-automatic-selection-requests\"\n );\n });\n\n it(\"should handle multiple projects and prompt selection\", async () => {\n const mockProjectsResponse = {\n data: [\n { name: \"project-1\", accountName: TEST_ACCOUNT_NAME },\n { name: \"project-2\", accountName: TEST_ACCOUNT_NAME },\n ],\n };\n\n const mockEnvironmentsResponse = {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: \"project-1\", // inquirer mock will select first project\n },\n ],\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments (will use first project from inquirer mock)\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: \"project-1\",\n })\n .reply(200, mockEnvironmentsResponse);\n\n // Mock the deployments endpoint (used to surface working-copy deployments)\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/project-1/deployments`)\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"link-multiple-projects-requests\"\n );\n });\n });\n\n describe(\"Link error handling\", () => {\n it(\"should fail when no environments exist\", async () => {\n const mockProjectsResponse = {\n data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],\n };\n\n const mockEmptyEnvironmentsResponse = { data: [] };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the environments call (returns empty)\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(200, mockEmptyEnvironmentsResponse);\n\n // Mock the deployments endpoint (also returns empty - no working copies either)\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n // Should throw because there are no environments to link against\n await expect(\n executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests.length).toBeGreaterThan(0);\n\n // Verify the critical failure was called with the right message\n expect(mockPrintCriticalFailure).toHaveBeenCalledWith(\n expect.stringContaining(\"any environments\")\n );\n });\n });\n\n describe(\"Error handling\", () => {\n it(\"should handle projects list failure\", async () => {\n const errorResponse = {\n error: \"Unauthorized\",\n message: \"Invalid API key\",\n statusCode: 401,\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const scope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(401, errorResponse);\n\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n\n // Expect the function to throw (simulating process exit)\n await expect(\n executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(scope.isDone()).toBe(true);\n expect(mockPrintCriticalFailure).toHaveBeenCalled();\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"link-projects-error-requests\");\n });\n\n it(\"should handle environments list failure\", async () => {\n const mockProjectsResponse = {\n data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],\n };\n\n const errorResponse = {\n error: \"Forbidden\",\n message: \"Access denied to project\",\n statusCode: 403,\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments (will fail)\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(403, errorResponse);\n\n [projectsScope, environmentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n // Expect the function to throw (simulating process exit)\n await expect(\n executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n })\n ).rejects.toThrow(\"Process would exit\");\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(mockPrintCriticalFailure).toHaveBeenCalled();\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\n \"link-environments-error-requests\"\n );\n });\n });\n\n describe(\"Request validation\", () => {\n it(\"should include correct headers for API requests\", async () => {\n const mockProjectsResponse = {\n data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],\n };\n\n const mockEnvironmentsResponse = {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n },\n ],\n };\n\n // Mock the middleware call to /v1/projects?accountName=... (fetchProject middleware)\n const projectsScope = nock(TEST_API_BASE)\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, mockProjectsResponse);\n\n // Mock the link handler call to /v1/environments\n const environmentsScope = nock(TEST_API_BASE)\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, mockEnvironmentsResponse);\n\n // Mock the deployments endpoint (used to surface working-copy deployments)\n const deploymentsScope = nock(TEST_API_BASE)\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .matchHeader(\"authorization\", `Bearer ${TEST_AUTH_TOKEN}`)\n .reply(200, { data: [] });\n\n [projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {\n scope.on(\"request\", (req, interceptor, body) => {\n requestCapture.capture(req, interceptor, body);\n });\n });\n\n await executeLinkCommand({\n account: TEST_ACCOUNT_NAME,\n \"api-key\": TEST_AUTH_TOKEN,\n dir: \".\",\n });\n\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n const capturedRequests = requestCapture.getRequests();\n expect(capturedRequests).toMatchSnapshot(\"link-headers-validation\");\n });\n });\n\n describe(\"Link always re-prompts from scratch\", () => {\n it(\"should not offer linked account/project/environment even when .env.zuplo is present\", async () => {\n // Simulate an existing .env.zuplo with fully linked values\n jest.mocked(readLinkedConfig).mockResolvedValue({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n });\n // confirmLinkedValue should never be called — if it is, fail the test immediately\n jest\n .mocked(confirmLinkedValue)\n .mockRejectedValue(\n new Error(\"link should never call confirmLinkedValue\")\n );\n\n // The link command bypasses linked config, so it must go through the full\n // interactive selection flow: accounts → projects → environments.\n const accountsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/accounts\")\n .reply(200, {\n data: [{ name: TEST_ACCOUNT_NAME }],\n });\n\n const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, { data: [{ name: TEST_PROJECT_NAME }] });\n\n const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/environments\")\n .query({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n })\n .reply(200, {\n data: [\n {\n name: \"development\",\n environmentType: \"development\",\n branchName: \"main\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n },\n ],\n });\n\n const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\n `/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`\n )\n .reply(200, { data: [] });\n\n // Run link WITHOUT passing --account (so fetchAccount middleware runs)\n await executeLinkCommand({ dir: \".\" });\n\n // All selection endpoints must have been called — proving link went through\n // the full interactive flow rather than short-circuiting via linked config.\n expect(accountsScope.isDone()).toBe(true);\n expect(projectsScope.isDone()).toBe(true);\n expect(environmentsScope.isDone()).toBe(true);\n expect(deploymentsScope.isDone()).toBe(true);\n\n // confirmLinkedValue must never have been called\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n });\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linked-config-cascade.integration.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/linked-config-cascade.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import nock from "nock";
|
|
2
|
+
import { fetchAccount } from "../../common/middleware/get-account-param.js";
|
|
3
|
+
import { fetchProject } from "../../common/middleware/get-project-param.js";
|
|
4
|
+
import { confirmLinkedValue, readLinkedConfig, USE_LINKED_DETAILS, } from "../../common/read-linked-config.js";
|
|
5
|
+
import { cleanupTest, setupAuthenticatedNock, setupTestEnvironment, TEST_ACCOUNT_NAME, TEST_API_BASE, TEST_AUTH_TOKEN, TEST_PROJECT_NAME, } from "./test-utils.js";
|
|
6
|
+
jest.mock("../../common/read-linked-config.js", () => ({
|
|
7
|
+
__esModule: true,
|
|
8
|
+
confirmLinkedValue: jest.fn().mockResolvedValue(true),
|
|
9
|
+
readLinkedConfig: jest.fn().mockResolvedValue({}),
|
|
10
|
+
USE_LINKED_DETAILS: "useLinkedDetails",
|
|
11
|
+
ignoreLinkedDetails: jest
|
|
12
|
+
.fn()
|
|
13
|
+
.mockImplementation((argv) => {
|
|
14
|
+
argv["useLinkedDetails"] = false;
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
describe("Linked-config cascade decline", () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
setupTestEnvironment();
|
|
20
|
+
nock.disableNetConnect();
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
cleanupTest();
|
|
25
|
+
});
|
|
26
|
+
it("sets useLinkedDetails to false when user declines linked account", async () => {
|
|
27
|
+
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
28
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
29
|
+
});
|
|
30
|
+
jest.mocked(confirmLinkedValue).mockResolvedValue(false);
|
|
31
|
+
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
32
|
+
.get("/v1/accounts")
|
|
33
|
+
.reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });
|
|
34
|
+
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
35
|
+
await fetchAccount(argv);
|
|
36
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
37
|
+
expect(argv[USE_LINKED_DETAILS]).toBe(false);
|
|
38
|
+
expect(argv.account).toBe(TEST_ACCOUNT_NAME);
|
|
39
|
+
});
|
|
40
|
+
it("skips linked project prompt when useLinkedDetails is false", async () => {
|
|
41
|
+
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
42
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
43
|
+
projectName: TEST_PROJECT_NAME,
|
|
44
|
+
});
|
|
45
|
+
jest
|
|
46
|
+
.mocked(confirmLinkedValue)
|
|
47
|
+
.mockRejectedValue(new Error("fetchProject must not call confirmLinkedValue after decline"));
|
|
48
|
+
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
49
|
+
.get("/v1/projects")
|
|
50
|
+
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
51
|
+
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
52
|
+
const argv = {
|
|
53
|
+
authToken: TEST_AUTH_TOKEN,
|
|
54
|
+
account: TEST_ACCOUNT_NAME,
|
|
55
|
+
[USE_LINKED_DETAILS]: false,
|
|
56
|
+
};
|
|
57
|
+
await fetchProject(argv);
|
|
58
|
+
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
59
|
+
expect(argv.project).toBe(TEST_PROJECT_NAME);
|
|
60
|
+
});
|
|
61
|
+
it("full cascade: declining account prevents linked project prompt", async () => {
|
|
62
|
+
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
63
|
+
accountName: TEST_ACCOUNT_NAME,
|
|
64
|
+
projectName: TEST_PROJECT_NAME,
|
|
65
|
+
});
|
|
66
|
+
jest.mocked(confirmLinkedValue).mockResolvedValueOnce(false);
|
|
67
|
+
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
68
|
+
.get("/v1/accounts")
|
|
69
|
+
.reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });
|
|
70
|
+
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
71
|
+
.get("/v1/projects")
|
|
72
|
+
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
73
|
+
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
74
|
+
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
75
|
+
await fetchAccount(argv);
|
|
76
|
+
await fetchProject(argv);
|
|
77
|
+
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
78
|
+
expect(argv[USE_LINKED_DETAILS]).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=linked-config-cascade.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linked-config-cascade.integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/linked-config-cascade.integration.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Integration tests for the linked-config cascade decline behaviour.\n *\n * When a user is prompted \"Use linked account 'X'?\" and answers No, the\n * useLinkedDetails flag is set to false on argv. Every downstream middleware\n * (fetchProject) must respect that flag and skip their own linked-value prompts —\n * so a manually selected account can never be accidentally paired with a stale\n * linked project.\n */\n/// <reference types=\"jest\" />\nimport nock from \"nock\";\nimport { fetchAccount } from \"../../common/middleware/get-account-param.js\";\nimport { fetchProject } from \"../../common/middleware/get-project-param.js\";\nimport {\n confirmLinkedValue,\n readLinkedConfig,\n USE_LINKED_DETAILS,\n} from \"../../common/read-linked-config.js\";\nimport {\n cleanupTest,\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\njest.mock(\"../../common/read-linked-config.js\", () => ({\n __esModule: true,\n confirmLinkedValue: jest.fn().mockResolvedValue(true),\n readLinkedConfig: jest.fn().mockResolvedValue({}),\n USE_LINKED_DETAILS: \"useLinkedDetails\",\n ignoreLinkedDetails: jest\n .fn()\n .mockImplementation((argv: Record<string, unknown>) => {\n argv[\"useLinkedDetails\"] = false;\n }),\n}));\n\ndescribe(\"Linked-config cascade decline\", () => {\n beforeEach(() => {\n setupTestEnvironment();\n nock.disableNetConnect();\n jest.clearAllMocks();\n });\n\n afterEach(() => {\n cleanupTest();\n });\n\n it(\"sets useLinkedDetails to false when user declines linked account\", async () => {\n jest.mocked(readLinkedConfig).mockResolvedValue({\n accountName: TEST_ACCOUNT_NAME,\n });\n // User says No to the linked account prompt\n jest.mocked(confirmLinkedValue).mockResolvedValue(false);\n\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/accounts\")\n .reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });\n\n const argv: Record<string, unknown> = { authToken: TEST_AUTH_TOKEN };\n await fetchAccount(argv);\n\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n expect(argv[USE_LINKED_DETAILS]).toBe(false);\n // account was resolved via the API selection path, not from linked config\n expect(argv.account).toBe(TEST_ACCOUNT_NAME);\n });\n\n it(\"skips linked project prompt when useLinkedDetails is false\", async () => {\n jest.mocked(readLinkedConfig).mockResolvedValue({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n });\n // confirmLinkedValue should never be reached for the project step\n jest\n .mocked(confirmLinkedValue)\n .mockRejectedValue(\n new Error(\"fetchProject must not call confirmLinkedValue after decline\")\n );\n\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, { data: [{ name: TEST_PROJECT_NAME }] });\n\n const argv: Record<string, unknown> = {\n authToken: TEST_AUTH_TOKEN,\n account: TEST_ACCOUNT_NAME,\n [USE_LINKED_DETAILS]: false,\n };\n await fetchProject(argv);\n\n expect(confirmLinkedValue).not.toHaveBeenCalled();\n expect(argv.project).toBe(TEST_PROJECT_NAME);\n });\n\n it(\"full cascade: declining account prevents linked project prompt\", async () => {\n jest.mocked(readLinkedConfig).mockResolvedValue({\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n });\n\n // Only the first call (account) returns false — if project middleware calls\n // confirmLinkedValue, the mock will return false again and it'll fall through\n // to the API. The real test is the call count.\n jest.mocked(confirmLinkedValue).mockResolvedValueOnce(false);\n\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/accounts\")\n .reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });\n\n setupAuthenticatedNock(nock(TEST_API_BASE))\n .get(\"/v1/projects\")\n .query({ accountName: TEST_ACCOUNT_NAME })\n .reply(200, { data: [{ name: TEST_PROJECT_NAME }] });\n\n const argv: Record<string, unknown> = { authToken: TEST_AUTH_TOKEN };\n\n await fetchAccount(argv);\n await fetchProject(argv);\n\n // confirmLinkedValue must only have been called once (for the account prompt).\n // The cascade flag prevented the project prompt.\n expect(confirmLinkedValue).toHaveBeenCalledTimes(1);\n expect(argv[USE_LINKED_DETAILS]).toBe(false);\n });\n});\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { beforeEach, describe, it } from "node:test";
|
|
4
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
5
5
|
import { assert } from "chai";
|
|
6
6
|
import { parse as dotenvParse } from "dotenv";
|
|
7
7
|
import { MockAgent, setGlobalDispatcher } from "undici";
|
|
@@ -15,8 +15,50 @@ describe("pullSystemConfig", () => {
|
|
|
15
15
|
mockAgent = new MockAgent();
|
|
16
16
|
mockAgent.disableNetConnect();
|
|
17
17
|
setGlobalDispatcher(mockAgent);
|
|
18
|
-
testDir = join(tmpdir(),
|
|
19
|
-
|
|
18
|
+
testDir = await mkdtemp(join(tmpdir(), "zuplo-test-"));
|
|
19
|
+
});
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await rm(testDir, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
it("should write account and project name to .env.zuplo", async () => {
|
|
24
|
+
const mockPayload = {
|
|
25
|
+
accountName: "test-account",
|
|
26
|
+
projectName: "test-project",
|
|
27
|
+
environmentType: "development",
|
|
28
|
+
systemConfigurations: "config-123",
|
|
29
|
+
};
|
|
30
|
+
mockAgent
|
|
31
|
+
.get(TEST_API_ENDPOINT)
|
|
32
|
+
.intercept({
|
|
33
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/configurations`,
|
|
34
|
+
method: "GET",
|
|
35
|
+
headers: {
|
|
36
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
.reply(200, mockPayload);
|
|
40
|
+
const { pullSystemConfig } = await import("../common/populate.js");
|
|
41
|
+
await pullSystemConfig({
|
|
42
|
+
dir: testDir,
|
|
43
|
+
environment: TEST_ENVIRONMENT,
|
|
44
|
+
authToken: TEST_AUTH_TOKEN,
|
|
45
|
+
});
|
|
46
|
+
const content = await readFile(join(testDir, ".env.zuplo"), "utf-8");
|
|
47
|
+
assert.include(content, "ZUPLO_ACCOUNT_NAME=test-account");
|
|
48
|
+
assert.include(content, "ZUPLO_PROJECT_NAME=test-project");
|
|
49
|
+
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=development");
|
|
50
|
+
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=config-123");
|
|
51
|
+
assert.notInclude(content, "ZUPLO_ENVIRONMENT_NAME");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("pullLocalConfig", () => {
|
|
55
|
+
let mockAgent;
|
|
56
|
+
let testDir;
|
|
57
|
+
beforeEach(async () => {
|
|
58
|
+
mockAgent = new MockAgent();
|
|
59
|
+
mockAgent.disableNetConnect();
|
|
60
|
+
setGlobalDispatcher(mockAgent);
|
|
61
|
+
testDir = await mkdtemp(join(tmpdir(), "zuplo-test-"));
|
|
20
62
|
});
|
|
21
63
|
it("should generate correct .env.zuplo file with system variables", async () => {
|
|
22
64
|
const mockPayload = {
|
|
@@ -35,8 +77,8 @@ describe("pullSystemConfig", () => {
|
|
|
35
77
|
},
|
|
36
78
|
})
|
|
37
79
|
.reply(200, mockPayload);
|
|
38
|
-
const { pullLocalConfig
|
|
39
|
-
await
|
|
80
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
81
|
+
await pullLocalConfig({
|
|
40
82
|
dir: testDir,
|
|
41
83
|
environment: TEST_ENVIRONMENT,
|
|
42
84
|
authToken: TEST_AUTH_TOKEN,
|
|
@@ -50,6 +92,7 @@ describe("pullSystemConfig", () => {
|
|
|
50
92
|
assert.include(content, "ZUPLO_PROJECT_NAME=test-project");
|
|
51
93
|
assert.include(content, "ZUPLO_ENVIRONMENT_TYPE=development");
|
|
52
94
|
assert.include(content, "ZUPLO_SYSTEM_CONFIGURATIONS=config-123");
|
|
95
|
+
assert.notInclude(content, "ZUPLO_ENVIRONMENT_NAME");
|
|
53
96
|
assert.notInclude(content, "# Public Zuplo environment variables");
|
|
54
97
|
assert.notInclude(content, "# Environment variables defined in the Zuplo UI for the environment");
|
|
55
98
|
await rm(testDir, { recursive: true, force: true });
|
|
@@ -76,8 +119,8 @@ describe("pullSystemConfig", () => {
|
|
|
76
119
|
},
|
|
77
120
|
})
|
|
78
121
|
.reply(200, mockPayload);
|
|
79
|
-
const { pullLocalConfig
|
|
80
|
-
await
|
|
122
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
123
|
+
await pullLocalConfig({
|
|
81
124
|
dir: testDir,
|
|
82
125
|
environment: TEST_ENVIRONMENT,
|
|
83
126
|
authToken: TEST_AUTH_TOKEN,
|
|
@@ -120,8 +163,8 @@ describe("pullSystemConfig", () => {
|
|
|
120
163
|
},
|
|
121
164
|
})
|
|
122
165
|
.reply(200, mockPayload);
|
|
123
|
-
const { pullLocalConfig
|
|
124
|
-
await
|
|
166
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
167
|
+
await pullLocalConfig({
|
|
125
168
|
dir: testDir,
|
|
126
169
|
environment: TEST_ENVIRONMENT,
|
|
127
170
|
authToken: TEST_AUTH_TOKEN,
|
|
@@ -156,8 +199,8 @@ describe("pullSystemConfig", () => {
|
|
|
156
199
|
},
|
|
157
200
|
})
|
|
158
201
|
.reply(200, mockPayload);
|
|
159
|
-
const { pullLocalConfig
|
|
160
|
-
await
|
|
202
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
203
|
+
await pullLocalConfig({
|
|
161
204
|
dir: testDir,
|
|
162
205
|
environment: TEST_ENVIRONMENT,
|
|
163
206
|
authToken: TEST_AUTH_TOKEN,
|
|
@@ -193,8 +236,8 @@ describe("pullSystemConfig", () => {
|
|
|
193
236
|
},
|
|
194
237
|
})
|
|
195
238
|
.reply(200, mockPayload);
|
|
196
|
-
const { pullLocalConfig
|
|
197
|
-
await
|
|
239
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
240
|
+
await pullLocalConfig({
|
|
198
241
|
dir: testDir,
|
|
199
242
|
environment: TEST_ENVIRONMENT,
|
|
200
243
|
authToken: TEST_AUTH_TOKEN,
|
|
@@ -230,8 +273,8 @@ describe("pullSystemConfig", () => {
|
|
|
230
273
|
},
|
|
231
274
|
})
|
|
232
275
|
.reply(200, mockPayload);
|
|
233
|
-
const { pullLocalConfig
|
|
234
|
-
await
|
|
276
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
277
|
+
await pullLocalConfig({
|
|
235
278
|
dir: testDir,
|
|
236
279
|
environment: TEST_ENVIRONMENT,
|
|
237
280
|
authToken: TEST_AUTH_TOKEN,
|
|
@@ -275,8 +318,8 @@ describe("pullSystemConfig", () => {
|
|
|
275
318
|
},
|
|
276
319
|
})
|
|
277
320
|
.reply(200, mockPayload);
|
|
278
|
-
const { pullLocalConfig
|
|
279
|
-
await
|
|
321
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
322
|
+
await pullLocalConfig({
|
|
280
323
|
dir: testDir,
|
|
281
324
|
environment: TEST_ENVIRONMENT,
|
|
282
325
|
authToken: TEST_AUTH_TOKEN,
|