(deps: TestDeps)
| 8386 | } |
| 8387 | |
| 8388 | function createTestPlanCommand(deps: TestDeps): Command { |
| 8389 | const plan = new Command('plan').description('Manage FE test plan-steps (FE-only)'); |
| 8390 | plan |
| 8391 | .command('put <test-id>') |
| 8392 | .description("Replace an FE test's planSteps[] (BE tests return 400 → use 'test code put')") |
| 8393 | .option( |
| 8394 | '--steps <path>', |
| 8395 | 'JSON file with { planSteps: [...] } (FE-only, ≤ 200 steps, ≤ 256 KB)', |
| 8396 | ) |
| 8397 | .option( |
| 8398 | '--expected-step-count <n>', |
| 8399 | 'optional defensive concurrency check; server rejects with 412 when the current length differs', |
| 8400 | ) |
| 8401 | .option( |
| 8402 | '--idempotency-key <token>', |
| 8403 | 'opaque idempotency token (1-256 ASCII chars). Defaults to a UUIDv4 minted per invocation; pin one yourself for safe retries.', |
| 8404 | ) |
| 8405 | .option( |
| 8406 | '--dry-run-simulate-error <code>', |
| 8407 | 'With --dry-run: synthesise an error envelope to preview the error path. Supported: PRECONDITION_FAILED (412).', |
| 8408 | ) |
| 8409 | .addHelpText( |
| 8410 | 'after', |
| 8411 | '\nDry-run note: --dry-run always returns the happy response shape.\n' + |
| 8412 | 'To preview the 412 retry-hint path, combine with --dry-run-simulate-error PRECONDITION_FAILED.\n' + |
| 8413 | '\n' + |
| 8414 | GLOBAL_OPTS_HINT, |
| 8415 | ) |
| 8416 | .action(async (testId: string, cmdOpts: PlanPutFlagOpts, command: Command) => { |
| 8417 | const simulateError = cmdOpts.dryRunSimulateError; |
| 8418 | if (simulateError !== undefined && simulateError !== 'PRECONDITION_FAILED') { |
| 8419 | throw localValidationError( |
| 8420 | 'dry-run-simulate-error', |
| 8421 | `unsupported value "${simulateError}"; only PRECONDITION_FAILED is supported`, |
| 8422 | ['PRECONDITION_FAILED'], |
| 8423 | ); |
| 8424 | } |
| 8425 | await runPlanPut( |
| 8426 | { |
| 8427 | ...resolveCommonOptions(command), |
| 8428 | testId, |
| 8429 | stepsFile: cmdOpts.steps, |
| 8430 | expectedStepCount: parseNumericFlag(cmdOpts.expectedStepCount, 'expected-step-count'), |
| 8431 | idempotencyKey: cmdOpts.idempotencyKey, |
| 8432 | dryRunSimulateError: |
| 8433 | simulateError === 'PRECONDITION_FAILED' ? 'PRECONDITION_FAILED' : undefined, |
| 8434 | }, |
| 8435 | deps, |
| 8436 | ); |
| 8437 | }); |
| 8438 | return plan; |
| 8439 | } |
| 8440 | |
| 8441 | interface PlanPutFlagOpts { |
| 8442 | steps: string; |
no test coverage detected