camunda / camunda/api-test-generator

feat: JavaScript SDK emitter (`js-sdk`) — lower path-analyser scenarios onto @camunda8/orchestration-cluster-api

Open
#131 3 comments 0 reactions 1 assignee View on GitHub

@johnOC03 is already working on this.

Since May 5, 2026.

enhancement OCA
Dominant language
TypeScript
Stars
0
Forks
3
Avg merge
13h 41m
Merged PRs (30d)
23

Description

Sub-issue of #8. Implement the js-sdk emitter strategy that lowers path-analyser EndpointScenarioCollection objects onto the @camunda8/orchestration-cluster-api TypeScript SDK, instead of emitting raw Playwright HTTP calls.

Prerequisites

  • Emitter interface — landed (path-analyser/src/codegen/emitter.ts, registry.ts, orchestrator.ts, cli-args.ts) — see #5 / #8
  • Reference implementation — PlaywrightEmitter at path-analyser/src/codegen/playwright/emitter.ts (488 lines). Treat this as the canonical lowering reference.
  • Per-step success-status correctness — successStatusByOp flows through RequestStep.expect.status (PR #52 / Bug A). SDK emitter gets this for free.

What to build

A new emitter registered under --target=js-sdk at:

path-analyser/src/codegen/js-sdk/
  emitter.ts          # JsSdkEmitter implements Emitter
  sdk-mapping.ts      # SdkMappingSource interface + OperationMapJsonSource impl
  materialize-support.ts  # vendors a self-contained JS project skeleton into <outDir>/
  README.md           # emitter id, env vars, supported scenario shapes
SDK surface
  • Package: @camunda8/orchestration-cluster-api
  • Client construction: createCamundaClient() (or new CamundaClient(config) — confirm against SDK README)
  • Method naming: camelCaseoperationId already matches directly
  • Ergonomic helpers: deployResourcesFromFiles and others in src/facade/operations.gen.ts
  • Hooks that produce them: hooks/post/300-generate-class-methods.ts, hooks/post/400-generate-facade.ts
  • Existing helper map: examples/operation-map.json
Mapping strategy (Option C from #8)

Use the SDK's existing examples/operation-map.json combined with spec/bundled/spec-metadata.json:

  1. Load operation-map.json from the SDK repo (see Open Question 1 on checkout layout).
  2. For each operationId, look up operation-map.json[operationId][0].region — this is the preferred method symbol (helper or raw).
  3. If no entry exists, derive raw method from operationId directly (already camelCase — no transform needed for JS).
  4. Emit client.<method>(args) instead of request.post(url, body).

Implement SdkMappingSource as a shared interface in path-analyser/src/codegen/strategy/sdk-mapping.ts so Python and C# emitters can reuse it.

Test runner decision (to be pinned in first PR)

Decide between:

  • Playwright Test — reuses @playwright/test infra already in use; request fixture available for any raw-HTTP fallback steps
  • Vitest — better TypeScript DX, no browser overhead, fits a pure-SDK suite better

Recommendation: Vitest for the SDK suite (SDK calls are plain async functions, no HTTP fixture needed). Keep Playwright for the raw REST suite.

Emitter behaviour

For each scenario step, the emitter should:

  1. Map RequestStep.operationId → SDK method symbol via SdkMappingSource.
  2. Build typed call arguments from RequestStep.body / RequestStep.pathParams / RequestStep.queryParams.
  3. Emit const result = await client.<method>(args).
  4. Extract response fields into ctx using the same extractInto pattern as PlaywrightEmitter, but from the typed SDK response rather than response.json().
  5. Assert result shape with assert-json-body (reuse existing).
Auth / env vars

The generated suite must support both:

  • Local unauthenticated (no env vars) — createCamundaClient() with no credentials
  • OAuth2 / SaaSCAMUNDA_CLIENT_ID, CAMUNDA_CLIENT_SECRET, CAMUNDA_OAUTH_URL, CAMUNDA_CLUSTER_ID per SDK conventions

Investigate whether the SDK's built-in credential resolution already handles the env-var pattern used in support/env.ts today (API_BASE_URL, etc.) and document the mapping.

Open questions to resolve (from #8)

  1. SDK-repo checkout layout — how does the generator read examples/operation-map.json at generation time? Options: sparse clone (like camunda-schema-bundler), published npm sidecar, local path env var, or bundled into spec-metadata.json upstream. Pick and document.
  2. Helper-signature mismatch policy — if a scenario's request shape doesn't match the helper's signature (e.g. multipart body that the helper doesn't accept), does the emitter silently fall back to the raw SDK method, or hard-fail to surface the gap?
  3. request-validation parity — should request-validation/src/emit/qaEmitter.ts also get a JS SDK variant, or is this emitter path-analyser-only for now?
  4. endpoint-map.json enrichment — should camunda-schema-bundler 2.x add operationId to endpoint-map.json to drop one of the two current metadata reads? Coordinate with camunda-schema-bundler#21.

Layered test requirements (mirrors Bug A pattern from #8)

Per the AGENTS.md red/green/class-scoped rule and the regression-guard pattern in #8:

  1. Layer-1 fixture — one hand-built EndpointScenarioCollection → emitted JS SDK call assertion (in tests/fixtures/planner/).
  2. Layer-2 contractJsSdkEmitter.emit() purity test: same input produces byte-identical output (in tests/codegen/js-sdk-emitter.test.ts).
  3. Layer-3 invariant — class-scoped assertion in tests/regression/bundled-spec-invariants.test.ts:
    • Every URL placeholder in the JS SDK suite is either seeded or extracted by an upstream step (mirrors Bug A invariant).
    • The operationId keyset of the emitter's call-shape table matches examples/operation-map.json under a CI cross-check.

Definition of Done

  • JsSdkEmitter registered under --target=js-sdk via registerEmitter().
  • npm run testsuite:generate -- --target=js-sdk produces a runnable suite for every endpoint in the pinned bundled spec.
  • materialize-support analogue produces a self-contained project (package.json, tsconfig.json, vitest.config.ts or playwright.config.ts) that runs npm install && npm test without referencing this generator.
  • Layer-3 invariant in tests/regression/bundled-spec-invariants.test.ts covers placeholder binding and per-step success-status correctness for the JS SDK suite.
  • operationId keyset of emitter's mapping matches SDK's examples/operation-map.json under CI.
  • path-analyser/src/codegen/js-sdk/README.md documents: emitter id, expected env vars, supported scenario shapes, how to point the strategy at a checked-out SDK repo.
  • npm run lint, tsc --noEmit, and npm test all pass.

Out of scope

  • Live-cluster CI matrix (separate follow-up once emitter ships end-to-end).
  • Resolving Bug B (#53) and Bug C (#54) — apply the same scope filters as the Bug A invariant.
  • Python and C# emitters (tracked in their own sub-issues).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.