@zuplo/cli 7.10.0 → 7.11.1
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/common/worker-output.d.ts +7 -0
- package/dist/common/worker-output.d.ts.map +1 -1
- package/dist/common/worker-output.js +39 -0
- package/dist/common/worker-output.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@hono/node-server/README.md +2 -0
- package/node_modules/@hono/node-server/dist/index.cjs +1 -1
- package/node_modules/@hono/node-server/dist/index.mjs +1 -1
- package/node_modules/@hono/node-server/dist/serve-static.cjs +2 -1
- package/node_modules/@hono/node-server/dist/serve-static.mjs +2 -1
- package/node_modules/@hono/node-server/package.json +1 -1
- package/node_modules/@posthog/core/dist/metrics/index.d.ts +9 -0
- package/node_modules/@posthog/core/dist/metrics/index.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/metrics/index.js +38 -3
- package/node_modules/@posthog/core/dist/metrics/index.mjs +38 -3
- package/node_modules/@posthog/core/dist/metrics/types.d.ts +7 -2
- package/node_modules/@posthog/core/dist/metrics/types.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/traces/ids.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/traces/ids.js +2 -2
- package/node_modules/@posthog/core/dist/traces/ids.mjs +2 -2
- package/node_modules/@posthog/core/dist/types.d.ts +1 -1
- package/node_modules/@posthog/core/dist/types.d.ts.map +1 -1
- package/node_modules/@posthog/core/package.json +4 -3
- package/node_modules/@posthog/core/src/metrics/index.spec.ts +75 -0
- package/node_modules/@posthog/core/src/metrics/index.ts +60 -0
- package/node_modules/@posthog/core/src/metrics/types.ts +7 -1
- package/node_modules/@posthog/core/src/traces/ids.ts +4 -2
- package/node_modules/@posthog/core/src/types.ts +1 -1
- package/node_modules/@posthog/types/dist/capture-metric.d.ts +10 -0
- package/node_modules/@posthog/types/dist/capture-metric.d.ts.map +1 -1
- package/node_modules/@posthog/types/dist/capture.d.ts +1 -1
- package/node_modules/@posthog/types/dist/capture.d.ts.map +1 -1
- package/node_modules/@posthog/types/dist/index.d.ts +1 -1
- package/node_modules/@posthog/types/dist/index.d.ts.map +1 -1
- package/node_modules/@posthog/types/package.json +1 -1
- package/node_modules/@posthog/types/src/capture-metric.ts +11 -0
- package/node_modules/@posthog/types/src/capture.ts +1 -1
- package/node_modules/@posthog/types/src/index.ts +1 -0
- package/node_modules/@zuplo/core/customer.cli.minified.js +272 -261
- package/node_modules/@zuplo/core/index.minified.js +276 -265
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +5 -2
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-YJ2BHVUH.js → chunk-CDEAY3VY.js} +2 -2
- package/node_modules/@zuplo/runtime/out/esm/chunk-LVSZ3WTO.js +37 -0
- package/node_modules/@zuplo/runtime/out/esm/chunk-LVSZ3WTO.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/{chunk-VTO3F6DK.js → chunk-NUVXDVLJ.js} +2 -2
- package/node_modules/@zuplo/runtime/out/esm/{chunk-6YPRGG62.js → chunk-RHU3Z7DA.js} +108 -108
- package/node_modules/@zuplo/runtime/out/esm/chunk-RHU3Z7DA.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/internal/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/sdks/aws/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +15 -24
- package/node_modules/@zuplo/runtime/out/types/internal/index.d.ts +14 -0
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/package.json +15 -12
- package/dist/__tests__/archive-utils.test.d.ts +0 -2
- package/dist/__tests__/archive-utils.test.d.ts.map +0 -1
- package/dist/__tests__/archive-utils.test.js +0 -50
- package/dist/__tests__/archive-utils.test.js.map +0 -1
- package/dist/__tests__/import-openapi.test.d.ts +0 -2
- package/dist/__tests__/import-openapi.test.d.ts.map +0 -1
- package/dist/__tests__/import-openapi.test.js +0 -251
- package/dist/__tests__/import-openapi.test.js.map +0 -1
- package/dist/__tests__/integration/confirm-linked-config.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/confirm-linked-config.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/confirm-linked-config.integration.test.js +0 -202
- package/dist/__tests__/integration/confirm-linked-config.integration.test.js.map +0 -1
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js +0 -184
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js.map +0 -1
- package/dist/__tests__/integration/custom-domain.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/custom-domain.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/custom-domain.integration.test.js +0 -563
- package/dist/__tests__/integration/custom-domain.integration.test.js.map +0 -1
- package/dist/__tests__/integration/delete.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/delete.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/delete.integration.test.js +0 -262
- package/dist/__tests__/integration/delete.integration.test.js.map +0 -1
- package/dist/__tests__/integration/deploy.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/deploy.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/deploy.integration.test.js +0 -519
- package/dist/__tests__/integration/deploy.integration.test.js.map +0 -1
- package/dist/__tests__/integration/get-project-param.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/get-project-param.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/get-project-param.integration.test.js +0 -305
- package/dist/__tests__/integration/get-project-param.integration.test.js.map +0 -1
- package/dist/__tests__/integration/info.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/info.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/info.integration.test.js +0 -293
- package/dist/__tests__/integration/info.integration.test.js.map +0 -1
- package/dist/__tests__/integration/jest-mocks-setup.d.ts +0 -2
- package/dist/__tests__/integration/jest-mocks-setup.d.ts.map +0 -1
- package/dist/__tests__/integration/jest-mocks-setup.js +0 -104
- package/dist/__tests__/integration/jest-mocks-setup.js.map +0 -1
- package/dist/__tests__/integration/jest-setup.d.ts +0 -2
- package/dist/__tests__/integration/jest-setup.d.ts.map +0 -1
- package/dist/__tests__/integration/jest-setup.js +0 -12
- package/dist/__tests__/integration/jest-setup.js.map +0 -1
- package/dist/__tests__/integration/link.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/link.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/link.integration.test.js +0 -395
- package/dist/__tests__/integration/link.integration.test.js.map +0 -1
- package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js +0 -179
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js.map +0 -1
- package/dist/__tests__/integration/list.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/list.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/list.integration.test.js +0 -300
- package/dist/__tests__/integration/list.integration.test.js.map +0 -1
- package/dist/__tests__/integration/source-upgrade.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/source-upgrade.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/source-upgrade.integration.test.js +0 -100
- package/dist/__tests__/integration/source-upgrade.integration.test.js.map +0 -1
- package/dist/__tests__/integration/test-utils.d.ts +0 -30
- package/dist/__tests__/integration/test-utils.d.ts.map +0 -1
- package/dist/__tests__/integration/test-utils.js +0 -82
- package/dist/__tests__/integration/test-utils.js.map +0 -1
- package/dist/__tests__/integration/tunnel.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/tunnel.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/tunnel.integration.test.js +0 -486
- package/dist/__tests__/integration/tunnel.integration.test.js.map +0 -1
- package/dist/__tests__/integration/variable.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/variable.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/variable.integration.test.js +0 -258
- package/dist/__tests__/integration/variable.integration.test.js.map +0 -1
- package/dist/__tests__/integration/whoami.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/whoami.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/whoami.integration.test.js +0 -116
- package/dist/__tests__/integration/whoami.integration.test.js.map +0 -1
- package/dist/__tests__/outdated.test.d.ts +0 -2
- package/dist/__tests__/outdated.test.d.ts.map +0 -1
- package/dist/__tests__/outdated.test.js +0 -67
- package/dist/__tests__/outdated.test.js.map +0 -1
- package/dist/__tests__/populate.test.d.ts +0 -2
- package/dist/__tests__/populate.test.d.ts.map +0 -1
- package/dist/__tests__/populate.test.js +0 -445
- package/dist/__tests__/populate.test.js.map +0 -1
- package/dist/__tests__/tsconfig-upgrader.test.d.ts +0 -2
- package/dist/__tests__/tsconfig-upgrader.test.d.ts.map +0 -1
- package/dist/__tests__/tsconfig-upgrader.test.js +0 -31
- package/dist/__tests__/tsconfig-upgrader.test.js.map +0 -1
- package/dist/ca-certificate/validation.test.d.ts +0 -2
- package/dist/ca-certificate/validation.test.d.ts.map +0 -1
- package/dist/ca-certificate/validation.test.js +0 -131
- package/dist/ca-certificate/validation.test.js.map +0 -1
- package/dist/common/analytics/cli-invocation.test.d.ts +0 -2
- package/dist/common/analytics/cli-invocation.test.d.ts.map +0 -1
- package/dist/common/analytics/cli-invocation.test.js +0 -51
- package/dist/common/analytics/cli-invocation.test.js.map +0 -1
- package/dist/common/analytics/package-manager.test.d.ts +0 -2
- package/dist/common/analytics/package-manager.test.d.ts.map +0 -1
- package/dist/common/analytics/package-manager.test.js +0 -163
- package/dist/common/analytics/package-manager.test.js.map +0 -1
- package/dist/common/cli-dispatcher.test.d.ts +0 -2
- package/dist/common/cli-dispatcher.test.d.ts.map +0 -1
- package/dist/common/cli-dispatcher.test.js +0 -80
- package/dist/common/cli-dispatcher.test.js.map +0 -1
- package/dist/common/middleware/check-pnpm-lifecycle.test.d.ts +0 -2
- package/dist/common/middleware/check-pnpm-lifecycle.test.d.ts.map +0 -1
- package/dist/common/middleware/check-pnpm-lifecycle.test.js +0 -125
- package/dist/common/middleware/check-pnpm-lifecycle.test.js.map +0 -1
- package/dist/common/middleware/get-environment-param.test.d.ts +0 -2
- package/dist/common/middleware/get-environment-param.test.d.ts.map +0 -1
- package/dist/common/middleware/get-environment-param.test.js +0 -57
- package/dist/common/middleware/get-environment-param.test.js.map +0 -1
- package/dist/common/read-linked-config.test.d.ts +0 -2
- package/dist/common/read-linked-config.test.d.ts.map +0 -1
- package/dist/common/read-linked-config.test.js +0 -363
- package/dist/common/read-linked-config.test.js.map +0 -1
- package/dist/common/terminal.test.d.ts +0 -2
- package/dist/common/terminal.test.d.ts.map +0 -1
- package/dist/common/terminal.test.js +0 -101
- package/dist/common/terminal.test.js.map +0 -1
- package/dist/common/utils/build-environment-prompt-choices.test.d.ts +0 -2
- package/dist/common/utils/build-environment-prompt-choices.test.d.ts.map +0 -1
- package/dist/common/utils/build-environment-prompt-choices.test.js +0 -97
- package/dist/common/utils/build-environment-prompt-choices.test.js.map +0 -1
- package/dist/common/utils/format-environment-type.test.d.ts +0 -2
- package/dist/common/utils/format-environment-type.test.d.ts.map +0 -1
- package/dist/common/utils/format-environment-type.test.js +0 -32
- package/dist/common/utils/format-environment-type.test.js.map +0 -1
- package/dist/common/utils/pnpm-lifecycle.test.d.ts +0 -2
- package/dist/common/utils/pnpm-lifecycle.test.d.ts.map +0 -1
- package/dist/common/utils/pnpm-lifecycle.test.js +0 -196
- package/dist/common/utils/pnpm-lifecycle.test.js.map +0 -1
- package/dist/common/utils/pretty-print-environment-prompt.test.d.ts +0 -2
- package/dist/common/utils/pretty-print-environment-prompt.test.d.ts.map +0 -1
- package/dist/common/utils/pretty-print-environment-prompt.test.js +0 -42
- package/dist/common/utils/pretty-print-environment-prompt.test.js.map +0 -1
- package/dist/common/utils/sort-environments-for-prompt.test.d.ts +0 -2
- package/dist/common/utils/sort-environments-for-prompt.test.d.ts.map +0 -1
- package/dist/common/utils/sort-environments-for-prompt.test.js +0 -82
- package/dist/common/utils/sort-environments-for-prompt.test.js.map +0 -1
- package/dist/common/utils/stringify-config.test.d.ts +0 -2
- package/dist/common/utils/stringify-config.test.d.ts.map +0 -1
- package/dist/common/utils/stringify-config.test.js +0 -80
- package/dist/common/utils/stringify-config.test.js.map +0 -1
- package/dist/common/validators/argument-validators.spec.d.ts +0 -2
- package/dist/common/validators/argument-validators.spec.d.ts.map +0 -1
- package/dist/common/validators/argument-validators.spec.js +0 -181
- package/dist/common/validators/argument-validators.spec.js.map +0 -1
- package/dist/deploy/archive.local-registry.test.d.ts +0 -2
- package/dist/deploy/archive.local-registry.test.d.ts.map +0 -1
- package/dist/deploy/archive.local-registry.test.js +0 -100
- package/dist/deploy/archive.local-registry.test.js.map +0 -1
- package/dist/deploy/archive.test.d.ts +0 -2
- package/dist/deploy/archive.test.d.ts.map +0 -1
- package/dist/deploy/archive.test.js +0 -248
- package/dist/deploy/archive.test.js.map +0 -1
- package/dist/deploy/classify-build-probe.test.d.ts +0 -2
- package/dist/deploy/classify-build-probe.test.d.ts.map +0 -1
- package/dist/deploy/classify-build-probe.test.js +0 -51
- package/dist/deploy/classify-build-probe.test.js.map +0 -1
- package/dist/deploy/poll-deployment.test.d.ts +0 -2
- package/dist/deploy/poll-deployment.test.d.ts.map +0 -1
- package/dist/deploy/poll-deployment.test.js +0 -158
- package/dist/deploy/poll-deployment.test.js.map +0 -1
- package/dist/dev/zuplo-local-gitignore.test.d.ts +0 -2
- package/dist/dev/zuplo-local-gitignore.test.d.ts.map +0 -1
- package/dist/dev/zuplo-local-gitignore.test.js +0 -58
- package/dist/dev/zuplo-local-gitignore.test.js.map +0 -1
- package/dist/editor/e2e/editor.spec.d.ts +0 -2
- package/dist/editor/e2e/editor.spec.d.ts.map +0 -1
- package/dist/editor/e2e/editor.spec.js +0 -44
- package/dist/editor/e2e/editor.spec.js.map +0 -1
- package/dist/link/project-type.test.d.ts +0 -2
- package/dist/link/project-type.test.d.ts.map +0 -1
- package/dist/link/project-type.test.js +0 -225
- package/dist/link/project-type.test.js.map +0 -1
- package/dist/lint/resolve-binary.test.d.ts +0 -2
- package/dist/lint/resolve-binary.test.d.ts.map +0 -1
- package/dist/lint/resolve-binary.test.js +0 -155
- package/dist/lint/resolve-binary.test.js.map +0 -1
- package/dist/open-api/convert/handler.spec.d.ts +0 -2
- package/dist/open-api/convert/handler.spec.d.ts.map +0 -1
- package/dist/open-api/convert/handler.spec.js +0 -301
- package/dist/open-api/convert/handler.spec.js.map +0 -1
- package/dist/open-api/merge/handler.spec.d.ts +0 -2
- package/dist/open-api/merge/handler.spec.d.ts.map +0 -1
- package/dist/open-api/merge/handler.spec.js +0 -673
- package/dist/open-api/merge/handler.spec.js.map +0 -1
- package/dist/open-api/overlay/handler.spec.d.ts +0 -2
- package/dist/open-api/overlay/handler.spec.d.ts.map +0 -1
- package/dist/open-api/overlay/handler.spec.js +0 -346
- package/dist/open-api/overlay/handler.spec.js.map +0 -1
- package/dist/source/ai-gateway/files.test.d.ts +0 -2
- package/dist/source/ai-gateway/files.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/files.test.js +0 -135
- package/dist/source/ai-gateway/files.test.js.map +0 -1
- package/dist/source/ai-gateway/handler.test.d.ts +0 -2
- package/dist/source/ai-gateway/handler.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/handler.test.js +0 -113
- package/dist/source/ai-gateway/handler.test.js.map +0 -1
- package/dist/source/ai-gateway/package.test.d.ts +0 -2
- package/dist/source/ai-gateway/package.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/package.test.js +0 -30
- package/dist/source/ai-gateway/package.test.js.map +0 -1
- package/dist/source/ai-gateway/planner.test.d.ts +0 -2
- package/dist/source/ai-gateway/planner.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/planner.test.js +0 -330
- package/dist/source/ai-gateway/planner.test.js.map +0 -1
- package/dist/source/ai-gateway/release.test.d.ts +0 -2
- package/dist/source/ai-gateway/release.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/release.test.js +0 -62
- package/dist/source/ai-gateway/release.test.js.map +0 -1
- package/dist/test/invoke-test.test.d.ts +0 -2
- package/dist/test/invoke-test.test.d.ts.map +0 -1
- package/dist/test/invoke-test.test.js +0 -150
- package/dist/test/invoke-test.test.js.map +0 -1
- package/dist/test/test-files.test.d.ts +0 -2
- package/dist/test/test-files.test.d.ts.map +0 -1
- package/dist/test/test-files.test.js +0 -57
- package/dist/test/test-files.test.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.js +0 -289
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.js +0 -181
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.js +0 -399
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.js +0 -779
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.js +0 -269
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.js +0 -93
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.js.map +0 -1
- package/node_modules/@zuplo/runtime/out/esm/chunk-6YPRGG62.js.map +0 -1
- package/node_modules/@zuplo/runtime/out/esm/chunk-PBDT4FDO.js +0 -37
- package/node_modules/@zuplo/runtime/out/esm/chunk-PBDT4FDO.js.map +0 -1
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-YJ2BHVUH.js.map → chunk-CDEAY3VY.js.map} +0 -0
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-PBDT4FDO.js.LEGAL.txt → chunk-LVSZ3WTO.js.LEGAL.txt} +0 -0
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-VTO3F6DK.js.map → chunk-NUVXDVLJ.js.map} +0 -0
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-6YPRGG62.js.LEGAL.txt → chunk-RHU3Z7DA.js.LEGAL.txt} +0 -0
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
import nock from "nock";
|
|
2
|
-
import yargs from "yargs/yargs";
|
|
3
|
-
import linkCommand from "../../cmds/link.js";
|
|
4
|
-
import { confirmLinkedValue, readLinkedConfig, } from "../../common/read-linked-config.js";
|
|
5
|
-
import { isInteractiveTerminal } from "../../common/terminal.js";
|
|
6
|
-
import { syncProjectTypeForLink } from "../../link/project-type.js";
|
|
7
|
-
import { cleanupTest, RequestCapture, setupAuthenticatedNock, setupTestEnvironment, TEST_ACCOUNT_NAME, TEST_API_BASE, TEST_AUTH_TOKEN, TEST_PROJECT_NAME, } from "./test-utils.js";
|
|
8
|
-
jest.mock("../../common/terminal.js", () => ({
|
|
9
|
-
__esModule: true,
|
|
10
|
-
isInteractiveTerminal: jest.fn().mockReturnValue(true),
|
|
11
|
-
}));
|
|
12
|
-
jest.mock("../../common/read-linked-config.js", () => ({
|
|
13
|
-
__esModule: true,
|
|
14
|
-
confirmLinkedValue: jest.fn().mockResolvedValue(true),
|
|
15
|
-
readLinkedConfig: jest.fn().mockResolvedValue({}),
|
|
16
|
-
USE_LINKED_DETAILS: "useLinkedDetails",
|
|
17
|
-
ignoreLinkedDetails: jest
|
|
18
|
-
.fn()
|
|
19
|
-
.mockImplementation((argv) => {
|
|
20
|
-
argv["useLinkedDetails"] = false;
|
|
21
|
-
}),
|
|
22
|
-
}));
|
|
23
|
-
jest.mock("../../common/validators/file-system-validator.js", () => ({
|
|
24
|
-
ZuploProjectValidator: jest.fn().mockImplementation(() => ({
|
|
25
|
-
validate: jest.fn().mockResolvedValue(true),
|
|
26
|
-
})),
|
|
27
|
-
}));
|
|
28
|
-
jest.mock("../../common/populate.js", () => ({
|
|
29
|
-
pullSystemConfig: jest.fn().mockResolvedValue(undefined),
|
|
30
|
-
pullLocalConfig: jest.fn().mockResolvedValue(undefined),
|
|
31
|
-
safeMergeConfig: jest.fn().mockResolvedValue(undefined),
|
|
32
|
-
}));
|
|
33
|
-
jest.mock("../../link/project-type.js", () => ({
|
|
34
|
-
__esModule: true,
|
|
35
|
-
syncProjectTypeForLink: jest.fn().mockResolvedValue(undefined),
|
|
36
|
-
}));
|
|
37
|
-
async function executeLinkCommand(args) {
|
|
38
|
-
const yargsInstance = yargs([])
|
|
39
|
-
.command(linkCommand)
|
|
40
|
-
.help(false)
|
|
41
|
-
.version(false)
|
|
42
|
-
.exitProcess(false);
|
|
43
|
-
const commandArgs = ["link"];
|
|
44
|
-
if (args.account) {
|
|
45
|
-
commandArgs.push("--account", args.account);
|
|
46
|
-
}
|
|
47
|
-
if (args.project) {
|
|
48
|
-
commandArgs.push("--project", args.project);
|
|
49
|
-
}
|
|
50
|
-
if (args["api-key"]) {
|
|
51
|
-
commandArgs.push("--api-key", args["api-key"]);
|
|
52
|
-
}
|
|
53
|
-
if (args.environment) {
|
|
54
|
-
commandArgs.push("--environment", args.environment);
|
|
55
|
-
}
|
|
56
|
-
if (args.dir) {
|
|
57
|
-
commandArgs.push("--dir", args.dir);
|
|
58
|
-
}
|
|
59
|
-
return await yargsInstance.parse(commandArgs);
|
|
60
|
-
}
|
|
61
|
-
const mockPrintResult = jest.mocked(require("../../common/output.js").printResultToConsoleAndExitGracefully);
|
|
62
|
-
const mockPrintCriticalFailure = jest.mocked(require("../../common/output.js").printCriticalFailureToConsoleAndExit);
|
|
63
|
-
describe("Link Command Integration Tests", () => {
|
|
64
|
-
let requestCapture;
|
|
65
|
-
beforeEach(() => {
|
|
66
|
-
setupTestEnvironment();
|
|
67
|
-
requestCapture = new RequestCapture();
|
|
68
|
-
nock.disableNetConnect();
|
|
69
|
-
jest.clearAllMocks();
|
|
70
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(true);
|
|
71
|
-
});
|
|
72
|
-
afterEach(() => {
|
|
73
|
-
cleanupTest();
|
|
74
|
-
requestCapture.clear();
|
|
75
|
-
});
|
|
76
|
-
describe("Link with project and environment specified", () => {
|
|
77
|
-
it("should sync project type when project and environment are provided", async () => {
|
|
78
|
-
await executeLinkCommand({
|
|
79
|
-
account: TEST_ACCOUNT_NAME,
|
|
80
|
-
project: TEST_PROJECT_NAME,
|
|
81
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
82
|
-
environment: "development",
|
|
83
|
-
dir: ".",
|
|
84
|
-
});
|
|
85
|
-
expect(mockPrintResult).toHaveBeenCalledWith(expect.stringContaining(`Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`));
|
|
86
|
-
expect(syncProjectTypeForLink).toHaveBeenCalledWith({
|
|
87
|
-
sourceDirectory: ".",
|
|
88
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
89
|
-
projectName: TEST_PROJECT_NAME,
|
|
90
|
-
authToken: TEST_AUTH_TOKEN,
|
|
91
|
-
});
|
|
92
|
-
const capturedRequests = requestCapture.getRequests();
|
|
93
|
-
expect(capturedRequests).toEqual([]);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
describe("Link with automatic project selection", () => {
|
|
97
|
-
it("should intercept GET request to list projects", async () => {
|
|
98
|
-
const mockProjectsResponse = {
|
|
99
|
-
data: [
|
|
100
|
-
{
|
|
101
|
-
name: TEST_PROJECT_NAME,
|
|
102
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
103
|
-
description: "Test project",
|
|
104
|
-
createdAt: "2024-01-01T00:00:00Z",
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
};
|
|
108
|
-
const mockEnvironmentsResponse = {
|
|
109
|
-
data: [
|
|
110
|
-
{
|
|
111
|
-
name: "development",
|
|
112
|
-
environmentType: "development",
|
|
113
|
-
branchName: "main",
|
|
114
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
115
|
-
projectName: TEST_PROJECT_NAME,
|
|
116
|
-
},
|
|
117
|
-
],
|
|
118
|
-
};
|
|
119
|
-
const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
120
|
-
.get("/v1/projects")
|
|
121
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
122
|
-
.reply(200, mockProjectsResponse);
|
|
123
|
-
const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
124
|
-
.get("/v1/environments")
|
|
125
|
-
.query({
|
|
126
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
127
|
-
projectName: TEST_PROJECT_NAME,
|
|
128
|
-
})
|
|
129
|
-
.reply(200, mockEnvironmentsResponse);
|
|
130
|
-
const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
131
|
-
.get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`)
|
|
132
|
-
.reply(200, { data: [] });
|
|
133
|
-
[projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {
|
|
134
|
-
scope.on("request", (req, interceptor, body) => {
|
|
135
|
-
requestCapture.capture(req, interceptor, body);
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
await executeLinkCommand({
|
|
139
|
-
account: TEST_ACCOUNT_NAME,
|
|
140
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
141
|
-
dir: ".",
|
|
142
|
-
});
|
|
143
|
-
expect(projectsScope.isDone()).toBe(true);
|
|
144
|
-
expect(environmentsScope.isDone()).toBe(true);
|
|
145
|
-
expect(deploymentsScope.isDone()).toBe(true);
|
|
146
|
-
expect(mockPrintResult).toHaveBeenCalledWith(expect.stringContaining(`Successfully linked your local directory to the ${TEST_PROJECT_NAME} project`));
|
|
147
|
-
const capturedRequests = requestCapture.getRequests();
|
|
148
|
-
expect(capturedRequests).toMatchSnapshot("link-automatic-selection-requests");
|
|
149
|
-
});
|
|
150
|
-
it("should handle multiple projects and prompt selection", async () => {
|
|
151
|
-
const mockProjectsResponse = {
|
|
152
|
-
data: [
|
|
153
|
-
{ name: "project-1", accountName: TEST_ACCOUNT_NAME },
|
|
154
|
-
{ name: "project-2", accountName: TEST_ACCOUNT_NAME },
|
|
155
|
-
],
|
|
156
|
-
};
|
|
157
|
-
const mockEnvironmentsResponse = {
|
|
158
|
-
data: [
|
|
159
|
-
{
|
|
160
|
-
name: "development",
|
|
161
|
-
environmentType: "development",
|
|
162
|
-
branchName: "main",
|
|
163
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
164
|
-
projectName: "project-1",
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
|
-
};
|
|
168
|
-
const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
169
|
-
.get("/v1/projects")
|
|
170
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
171
|
-
.reply(200, mockProjectsResponse);
|
|
172
|
-
const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
173
|
-
.get("/v1/environments")
|
|
174
|
-
.query({
|
|
175
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
176
|
-
projectName: "project-1",
|
|
177
|
-
})
|
|
178
|
-
.reply(200, mockEnvironmentsResponse);
|
|
179
|
-
const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
180
|
-
.get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/project-1/deployments`)
|
|
181
|
-
.reply(200, { data: [] });
|
|
182
|
-
[projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {
|
|
183
|
-
scope.on("request", (req, interceptor, body) => {
|
|
184
|
-
requestCapture.capture(req, interceptor, body);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
await executeLinkCommand({
|
|
188
|
-
account: TEST_ACCOUNT_NAME,
|
|
189
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
190
|
-
dir: ".",
|
|
191
|
-
});
|
|
192
|
-
expect(projectsScope.isDone()).toBe(true);
|
|
193
|
-
expect(environmentsScope.isDone()).toBe(true);
|
|
194
|
-
expect(deploymentsScope.isDone()).toBe(true);
|
|
195
|
-
const capturedRequests = requestCapture.getRequests();
|
|
196
|
-
expect(capturedRequests).toMatchSnapshot("link-multiple-projects-requests");
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
describe("Link error handling", () => {
|
|
200
|
-
it("should fail when no environments exist", async () => {
|
|
201
|
-
const mockProjectsResponse = {
|
|
202
|
-
data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],
|
|
203
|
-
};
|
|
204
|
-
const mockEmptyEnvironmentsResponse = { data: [] };
|
|
205
|
-
const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
206
|
-
.get("/v1/projects")
|
|
207
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
208
|
-
.reply(200, mockProjectsResponse);
|
|
209
|
-
const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
210
|
-
.get("/v1/environments")
|
|
211
|
-
.query({
|
|
212
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
213
|
-
projectName: TEST_PROJECT_NAME,
|
|
214
|
-
})
|
|
215
|
-
.reply(200, mockEmptyEnvironmentsResponse);
|
|
216
|
-
const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
217
|
-
.get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`)
|
|
218
|
-
.reply(200, { data: [] });
|
|
219
|
-
[projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {
|
|
220
|
-
scope.on("request", (req, interceptor, body) => {
|
|
221
|
-
requestCapture.capture(req, interceptor, body);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
await expect(executeLinkCommand({
|
|
225
|
-
account: TEST_ACCOUNT_NAME,
|
|
226
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
227
|
-
dir: ".",
|
|
228
|
-
})).rejects.toThrow("Process would exit");
|
|
229
|
-
expect(projectsScope.isDone()).toBe(true);
|
|
230
|
-
expect(environmentsScope.isDone()).toBe(true);
|
|
231
|
-
expect(deploymentsScope.isDone()).toBe(true);
|
|
232
|
-
const capturedRequests = requestCapture.getRequests();
|
|
233
|
-
expect(capturedRequests.length).toBeGreaterThan(0);
|
|
234
|
-
expect(mockPrintCriticalFailure).toHaveBeenCalledWith(expect.stringContaining("any environments"));
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
describe("Error handling", () => {
|
|
238
|
-
it("should handle projects list failure", async () => {
|
|
239
|
-
const errorResponse = {
|
|
240
|
-
error: "Unauthorized",
|
|
241
|
-
message: "Invalid API key",
|
|
242
|
-
statusCode: 401,
|
|
243
|
-
};
|
|
244
|
-
const scope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
245
|
-
.get("/v1/projects")
|
|
246
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
247
|
-
.reply(401, errorResponse);
|
|
248
|
-
scope.on("request", (req, interceptor, body) => {
|
|
249
|
-
requestCapture.capture(req, interceptor, body);
|
|
250
|
-
});
|
|
251
|
-
await expect(executeLinkCommand({
|
|
252
|
-
account: TEST_ACCOUNT_NAME,
|
|
253
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
254
|
-
dir: ".",
|
|
255
|
-
})).rejects.toThrow("Process would exit");
|
|
256
|
-
expect(scope.isDone()).toBe(true);
|
|
257
|
-
expect(mockPrintCriticalFailure).toHaveBeenCalled();
|
|
258
|
-
const capturedRequests = requestCapture.getRequests();
|
|
259
|
-
expect(capturedRequests).toMatchSnapshot("link-projects-error-requests");
|
|
260
|
-
});
|
|
261
|
-
it("should handle environments list failure", async () => {
|
|
262
|
-
const mockProjectsResponse = {
|
|
263
|
-
data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],
|
|
264
|
-
};
|
|
265
|
-
const errorResponse = {
|
|
266
|
-
error: "Forbidden",
|
|
267
|
-
message: "Access denied to project",
|
|
268
|
-
statusCode: 403,
|
|
269
|
-
};
|
|
270
|
-
const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
271
|
-
.get("/v1/projects")
|
|
272
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
273
|
-
.reply(200, mockProjectsResponse);
|
|
274
|
-
const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
275
|
-
.get("/v1/environments")
|
|
276
|
-
.query({
|
|
277
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
278
|
-
projectName: TEST_PROJECT_NAME,
|
|
279
|
-
})
|
|
280
|
-
.reply(403, errorResponse);
|
|
281
|
-
[projectsScope, environmentsScope].forEach((scope) => {
|
|
282
|
-
scope.on("request", (req, interceptor, body) => {
|
|
283
|
-
requestCapture.capture(req, interceptor, body);
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
await expect(executeLinkCommand({
|
|
287
|
-
account: TEST_ACCOUNT_NAME,
|
|
288
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
289
|
-
dir: ".",
|
|
290
|
-
})).rejects.toThrow("Process would exit");
|
|
291
|
-
expect(projectsScope.isDone()).toBe(true);
|
|
292
|
-
expect(environmentsScope.isDone()).toBe(true);
|
|
293
|
-
expect(mockPrintCriticalFailure).toHaveBeenCalled();
|
|
294
|
-
const capturedRequests = requestCapture.getRequests();
|
|
295
|
-
expect(capturedRequests).toMatchSnapshot("link-environments-error-requests");
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
describe("Request validation", () => {
|
|
299
|
-
it("should include correct headers for API requests", async () => {
|
|
300
|
-
const mockProjectsResponse = {
|
|
301
|
-
data: [{ name: TEST_PROJECT_NAME, accountName: TEST_ACCOUNT_NAME }],
|
|
302
|
-
};
|
|
303
|
-
const mockEnvironmentsResponse = {
|
|
304
|
-
data: [
|
|
305
|
-
{
|
|
306
|
-
name: "development",
|
|
307
|
-
environmentType: "development",
|
|
308
|
-
branchName: "main",
|
|
309
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
310
|
-
projectName: TEST_PROJECT_NAME,
|
|
311
|
-
},
|
|
312
|
-
],
|
|
313
|
-
};
|
|
314
|
-
const projectsScope = nock(TEST_API_BASE)
|
|
315
|
-
.get("/v1/projects")
|
|
316
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
317
|
-
.matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
|
|
318
|
-
.reply(200, mockProjectsResponse);
|
|
319
|
-
const environmentsScope = nock(TEST_API_BASE)
|
|
320
|
-
.get("/v1/environments")
|
|
321
|
-
.query({
|
|
322
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
323
|
-
projectName: TEST_PROJECT_NAME,
|
|
324
|
-
})
|
|
325
|
-
.matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
|
|
326
|
-
.reply(200, mockEnvironmentsResponse);
|
|
327
|
-
const deploymentsScope = nock(TEST_API_BASE)
|
|
328
|
-
.get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`)
|
|
329
|
-
.matchHeader("authorization", `Bearer ${TEST_AUTH_TOKEN}`)
|
|
330
|
-
.reply(200, { data: [] });
|
|
331
|
-
[projectsScope, environmentsScope, deploymentsScope].forEach((scope) => {
|
|
332
|
-
scope.on("request", (req, interceptor, body) => {
|
|
333
|
-
requestCapture.capture(req, interceptor, body);
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
await executeLinkCommand({
|
|
337
|
-
account: TEST_ACCOUNT_NAME,
|
|
338
|
-
"api-key": TEST_AUTH_TOKEN,
|
|
339
|
-
dir: ".",
|
|
340
|
-
});
|
|
341
|
-
expect(projectsScope.isDone()).toBe(true);
|
|
342
|
-
expect(environmentsScope.isDone()).toBe(true);
|
|
343
|
-
expect(deploymentsScope.isDone()).toBe(true);
|
|
344
|
-
const capturedRequests = requestCapture.getRequests();
|
|
345
|
-
expect(capturedRequests).toMatchSnapshot("link-headers-validation");
|
|
346
|
-
});
|
|
347
|
-
});
|
|
348
|
-
describe("Link always re-prompts from scratch", () => {
|
|
349
|
-
it("should not offer linked account/project/environment even when .env.zuplo is present", async () => {
|
|
350
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
351
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
352
|
-
projectName: TEST_PROJECT_NAME,
|
|
353
|
-
});
|
|
354
|
-
jest
|
|
355
|
-
.mocked(confirmLinkedValue)
|
|
356
|
-
.mockRejectedValue(new Error("link should never call confirmLinkedValue"));
|
|
357
|
-
const accountsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
358
|
-
.get("/v1/accounts")
|
|
359
|
-
.reply(200, {
|
|
360
|
-
data: [{ name: TEST_ACCOUNT_NAME }],
|
|
361
|
-
});
|
|
362
|
-
const projectsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
363
|
-
.get("/v1/projects")
|
|
364
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
365
|
-
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
366
|
-
const environmentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
367
|
-
.get("/v1/environments")
|
|
368
|
-
.query({
|
|
369
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
370
|
-
projectName: TEST_PROJECT_NAME,
|
|
371
|
-
})
|
|
372
|
-
.reply(200, {
|
|
373
|
-
data: [
|
|
374
|
-
{
|
|
375
|
-
name: "development",
|
|
376
|
-
environmentType: "development",
|
|
377
|
-
branchName: "main",
|
|
378
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
379
|
-
projectName: TEST_PROJECT_NAME,
|
|
380
|
-
},
|
|
381
|
-
],
|
|
382
|
-
});
|
|
383
|
-
const deploymentsScope = setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
384
|
-
.get(`/v1/accounts/${TEST_ACCOUNT_NAME}/projects/${TEST_PROJECT_NAME}/deployments`)
|
|
385
|
-
.reply(200, { data: [] });
|
|
386
|
-
await executeLinkCommand({ dir: "." });
|
|
387
|
-
expect(accountsScope.isDone()).toBe(true);
|
|
388
|
-
expect(projectsScope.isDone()).toBe(true);
|
|
389
|
-
expect(environmentsScope.isDone()).toBe(true);
|
|
390
|
-
expect(deploymentsScope.isDone()).toBe(true);
|
|
391
|
-
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
//# sourceMappingURL=link.integration.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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 { isInteractiveTerminal } from \"../../common/terminal.js\";\nimport { syncProjectTypeForLink } from \"../../link/project-type.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// Tests exercise interactive selection flows — treat the terminal as interactive by default.\njest.mock(\"../../common/terminal.js\", () => ({\n __esModule: true,\n isInteractiveTerminal: jest.fn().mockReturnValue(true),\n}));\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\njest.mock(\"../../link/project-type.js\", () => ({\n __esModule: true,\n syncProjectTypeForLink: 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 jest.mocked(isInteractiveTerminal).mockReturnValue(true);\n });\n\n afterEach(() => {\n cleanupTest();\n requestCapture.clear();\n });\n\n describe(\"Link with project and environment specified\", () => {\n it(\"should sync project type 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 expect(syncProjectTypeForLink).toHaveBeenCalledWith({\n sourceDirectory: \".\",\n accountName: TEST_ACCOUNT_NAME,\n projectName: TEST_PROJECT_NAME,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // No selection API requests are needed 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"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"linked-config-cascade.integration.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/linked-config-cascade.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import nock from "nock";
|
|
2
|
-
import { confirmLinkedConfig } from "../../common/middleware/confirm-linked-config.js";
|
|
3
|
-
import { fetchAccount } from "../../common/middleware/get-account-param.js";
|
|
4
|
-
import { fetchEnvironment } from "../../common/middleware/get-environment-param.js";
|
|
5
|
-
import { fetchProject } from "../../common/middleware/get-project-param.js";
|
|
6
|
-
import { printCriticalFailureToConsoleAndExit } from "../../common/output.js";
|
|
7
|
-
import { confirmLinkedValue, readLinkedConfig, USE_LINKED_DETAILS, } from "../../common/read-linked-config.js";
|
|
8
|
-
import { isInteractiveTerminal } from "../../common/terminal.js";
|
|
9
|
-
import { cleanupTest, setupAuthenticatedNock, setupTestEnvironment, TEST_ACCOUNT_NAME, TEST_API_BASE, TEST_AUTH_TOKEN, TEST_PROJECT_NAME, } from "./test-utils.js";
|
|
10
|
-
jest.mock("../../common/read-linked-config.js", () => ({
|
|
11
|
-
__esModule: true,
|
|
12
|
-
confirmLinkedValue: jest.fn().mockResolvedValue(true),
|
|
13
|
-
readLinkedConfig: jest.fn().mockResolvedValue({}),
|
|
14
|
-
USE_LINKED_DETAILS: "useLinkedDetails",
|
|
15
|
-
ignoreLinkedDetails: jest
|
|
16
|
-
.fn()
|
|
17
|
-
.mockImplementation((argv) => {
|
|
18
|
-
argv["useLinkedDetails"] = false;
|
|
19
|
-
}),
|
|
20
|
-
}));
|
|
21
|
-
jest.mock("../../common/terminal.js", () => ({
|
|
22
|
-
__esModule: true,
|
|
23
|
-
isInteractiveTerminal: jest.fn().mockReturnValue(true),
|
|
24
|
-
}));
|
|
25
|
-
describe("Linked-config cascade decline", () => {
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
setupTestEnvironment();
|
|
28
|
-
nock.disableNetConnect();
|
|
29
|
-
jest.clearAllMocks();
|
|
30
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(true);
|
|
31
|
-
});
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
cleanupTest();
|
|
34
|
-
});
|
|
35
|
-
it("sets useLinkedDetails to false when user declines linked account", async () => {
|
|
36
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
37
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
38
|
-
});
|
|
39
|
-
jest.mocked(confirmLinkedValue).mockResolvedValue(false);
|
|
40
|
-
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
41
|
-
.get("/v1/accounts")
|
|
42
|
-
.reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });
|
|
43
|
-
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
44
|
-
await fetchAccount(argv);
|
|
45
|
-
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
46
|
-
expect(argv[USE_LINKED_DETAILS]).toBe(false);
|
|
47
|
-
expect(argv.account).toBe(TEST_ACCOUNT_NAME);
|
|
48
|
-
});
|
|
49
|
-
it("skips linked project prompt when useLinkedDetails is false", async () => {
|
|
50
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
51
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
52
|
-
projectName: TEST_PROJECT_NAME,
|
|
53
|
-
});
|
|
54
|
-
jest
|
|
55
|
-
.mocked(confirmLinkedValue)
|
|
56
|
-
.mockRejectedValue(new Error("fetchProject must not call confirmLinkedValue after decline"));
|
|
57
|
-
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
58
|
-
.get("/v1/projects")
|
|
59
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
60
|
-
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
61
|
-
const argv = {
|
|
62
|
-
authToken: TEST_AUTH_TOKEN,
|
|
63
|
-
account: TEST_ACCOUNT_NAME,
|
|
64
|
-
[USE_LINKED_DETAILS]: false,
|
|
65
|
-
};
|
|
66
|
-
await fetchProject(argv);
|
|
67
|
-
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
68
|
-
expect(argv.project).toBe(TEST_PROJECT_NAME);
|
|
69
|
-
});
|
|
70
|
-
it("full cascade: declining account prevents linked project prompt", async () => {
|
|
71
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
72
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
73
|
-
projectName: TEST_PROJECT_NAME,
|
|
74
|
-
});
|
|
75
|
-
jest.mocked(confirmLinkedValue).mockResolvedValueOnce(false);
|
|
76
|
-
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
77
|
-
.get("/v1/accounts")
|
|
78
|
-
.reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });
|
|
79
|
-
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
80
|
-
.get("/v1/projects")
|
|
81
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
82
|
-
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
83
|
-
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
84
|
-
await fetchAccount(argv);
|
|
85
|
-
await fetchProject(argv);
|
|
86
|
-
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
87
|
-
expect(argv[USE_LINKED_DETAILS]).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
it("uses linked account silently when terminal is non-interactive", async () => {
|
|
90
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
91
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
92
|
-
});
|
|
93
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(false);
|
|
94
|
-
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
95
|
-
await fetchAccount(argv);
|
|
96
|
-
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
97
|
-
expect(argv.account).toBe(TEST_ACCOUNT_NAME);
|
|
98
|
-
});
|
|
99
|
-
it("uses linked project silently when terminal is non-interactive", async () => {
|
|
100
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
101
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
102
|
-
projectName: TEST_PROJECT_NAME,
|
|
103
|
-
});
|
|
104
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(false);
|
|
105
|
-
const argv = {
|
|
106
|
-
authToken: TEST_AUTH_TOKEN,
|
|
107
|
-
account: TEST_ACCOUNT_NAME,
|
|
108
|
-
};
|
|
109
|
-
await fetchProject(argv);
|
|
110
|
-
expect(confirmLinkedValue).not.toHaveBeenCalled();
|
|
111
|
-
expect(argv.project).toBe(TEST_PROJECT_NAME);
|
|
112
|
-
});
|
|
113
|
-
it("combined prompt accepted: full chain calls confirmLinkedValue exactly once", async () => {
|
|
114
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
115
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
116
|
-
projectName: TEST_PROJECT_NAME,
|
|
117
|
-
});
|
|
118
|
-
jest.mocked(confirmLinkedValue).mockResolvedValue(true);
|
|
119
|
-
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
120
|
-
await confirmLinkedConfig(argv);
|
|
121
|
-
await fetchAccount(argv);
|
|
122
|
-
await fetchProject(argv);
|
|
123
|
-
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
124
|
-
expect(confirmLinkedValue).toHaveBeenCalledWith(`Use linked project '${TEST_PROJECT_NAME}' in account '${TEST_ACCOUNT_NAME}'?`);
|
|
125
|
-
expect(argv.account).toBe(TEST_ACCOUNT_NAME);
|
|
126
|
-
expect(argv.project).toBe(TEST_PROJECT_NAME);
|
|
127
|
-
});
|
|
128
|
-
it("combined prompt declined: full chain falls through to API pickers without further linked prompts", async () => {
|
|
129
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({
|
|
130
|
-
accountName: TEST_ACCOUNT_NAME,
|
|
131
|
-
projectName: TEST_PROJECT_NAME,
|
|
132
|
-
});
|
|
133
|
-
jest.mocked(confirmLinkedValue).mockResolvedValue(false);
|
|
134
|
-
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
135
|
-
.get("/v1/accounts")
|
|
136
|
-
.reply(200, { data: [{ name: TEST_ACCOUNT_NAME }] });
|
|
137
|
-
setupAuthenticatedNock(nock(TEST_API_BASE))
|
|
138
|
-
.get("/v1/projects")
|
|
139
|
-
.query({ accountName: TEST_ACCOUNT_NAME })
|
|
140
|
-
.reply(200, { data: [{ name: TEST_PROJECT_NAME }] });
|
|
141
|
-
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
142
|
-
await confirmLinkedConfig(argv);
|
|
143
|
-
await fetchAccount(argv);
|
|
144
|
-
await fetchProject(argv);
|
|
145
|
-
expect(confirmLinkedValue).toHaveBeenCalledTimes(1);
|
|
146
|
-
expect(argv[USE_LINKED_DETAILS]).toBe(false);
|
|
147
|
-
});
|
|
148
|
-
it("fails loudly when --project is omitted in non-interactive environments without linked config", async () => {
|
|
149
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({});
|
|
150
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(false);
|
|
151
|
-
const argv = {
|
|
152
|
-
authToken: TEST_AUTH_TOKEN,
|
|
153
|
-
account: TEST_ACCOUNT_NAME,
|
|
154
|
-
};
|
|
155
|
-
await expect(fetchProject(argv)).rejects.toThrow("Process would exit");
|
|
156
|
-
expect(printCriticalFailureToConsoleAndExit).toHaveBeenCalledWith(expect.stringContaining("--project is required"));
|
|
157
|
-
expect(argv.project).toBeUndefined();
|
|
158
|
-
});
|
|
159
|
-
it("fails loudly when --account is omitted in non-interactive environments without linked config", async () => {
|
|
160
|
-
jest.mocked(readLinkedConfig).mockResolvedValue({});
|
|
161
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(false);
|
|
162
|
-
const argv = { authToken: TEST_AUTH_TOKEN };
|
|
163
|
-
await expect(fetchAccount(argv)).rejects.toThrow("Process would exit");
|
|
164
|
-
expect(printCriticalFailureToConsoleAndExit).toHaveBeenCalledWith(expect.stringContaining("--account is required"));
|
|
165
|
-
expect(argv.account).toBeUndefined();
|
|
166
|
-
});
|
|
167
|
-
it("fails loudly when --environment is omitted in non-interactive environments", async () => {
|
|
168
|
-
jest.mocked(isInteractiveTerminal).mockReturnValue(false);
|
|
169
|
-
const argv = {
|
|
170
|
-
authToken: TEST_AUTH_TOKEN,
|
|
171
|
-
account: TEST_ACCOUNT_NAME,
|
|
172
|
-
project: TEST_PROJECT_NAME,
|
|
173
|
-
};
|
|
174
|
-
await expect(fetchEnvironment(argv)).rejects.toThrow("Process would exit");
|
|
175
|
-
expect(printCriticalFailureToConsoleAndExit).toHaveBeenCalledWith(expect.stringContaining("--environment is required"));
|
|
176
|
-
expect(argv.environment).toBeUndefined();
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
//# sourceMappingURL=linked-config-cascade.integration.test.js.map
|