7.1 Story 7.1: Create Structured Test Output and Trace Context Helpers
Sprint Key: 7-1-create-structured-test-output-and-trace-context-helpers
Epic: 7
PRD: testing-framework
Story 7.1: Create Structured Test Output and Trace Context Helpers
Status: ready-for-dev
Story
As a developer, I want test framework helpers that produce structured output and mock trace IDs, So that Sprint 23's MELT platform can consume test telemetry without code changes.
Acceptance Criteria
-
AC1:
tests/melt-helpers/trace-context.jsexports functions to generate deterministic mock trace IDs for JS test correlation, usable in JestbeforeEach()to set trace context per test -
AC2:
tests/melt-helpers/trace-context.pyexports pytest fixtures that generate mock trace context (trace_id,span_id) via@pytest.fixturedecorator - AC3: Trace IDs are deterministic and reproducible across repeated test runs (NFR10) — same test name always produces the same trace ID
- AC4: No Sprint 22 code imports or depends on MELT libraries (OTel, VictoriaMetrics, Grafana) — zero external dependencies beyond Jest/pytest
-
AC5:
tests/melt-helpers/trace-context.test.jsprovides test coverage for the JS helper itself -
AC6:
tests/test_trace_context.py(ingenie-ai-overlay/tests/) provides test coverage for the Python fixture - AC7: Both helpers produce structured JSON output compatible with OTel ingestion format (Sprint 23 bridge pattern)
- AC8: All new files pass their respective linters (ESLint for JS, Ruff for Python) with zero errors
Tasks / Subtasks
-
Task 1: Create tests/melt-helpers/directory (AC1, AC2)-
1.1 Create tests/melt-helpers/README.mddocumenting purpose and Sprint 23 integration path
-
-
Task 2: Implement tests/melt-helpers/trace-context.js(AC1, AC3, AC7)-
2.1 Export generateTraceId(testName)— deterministic hash from test name -
2.2 Export generateSpanId(testName, spanName)— deterministic hash for sub-spans -
2.3 Export createTraceContext(testName)— returns{ traceId, spanId, startTime, metadata }object -
2.4 Export setTraceContext(testName)— JestbeforeEach-compatible setup function -
2.5 Export getTestTraceId()— retrieves current test trace ID -
2.6 All IDs use hex format matching OTel trace ID format (32 hex chars for trace_id, 16 for span_id)
-
-
Task 3: Implement tests/melt-helpers/trace-context.py(AC2, AC3, AC7)-
3.1 Create @pytest.fixturenamedtrace_contextreturning dict withtrace_idandspan_id -
3.2 Use deterministic generation (hash of test name, not random UUID) -
3.3 Include ITU copyright header -
3.4 IDs use same hex format as JS version for cross-language correlation
-
-
Task 4: Create tests/melt-helpers/trace-context.test.js(AC5)-
4.1 Test generateTraceId()determinism — same input → same output -
4.2 Test generateTraceId()uniqueness — different inputs → different outputs -
4.3 Test ID format compliance (32 hex chars for trace_id, 16 for span_id) -
4.4 Test createTraceContext()returns full structured object -
4.5 Test setTraceContext()works in Jest beforeEach
-
-
Task 5: Create genie-ai-overlay/tests/test_trace_context.py(AC6)-
5.1 Test fixture returns dict with trace_id and span_id -
5.2 Test fixture determinism — same test name → same IDs -
5.3 Test ID format compliance -
5.4 Include ITU copyright header
-
-
Task 6: Run linters and fix any errors (AC8)
Dev Notes
Architecture Context
This story implements the Sprint 22/23 Bridge Pattern defined in _bmad-output/planning-artifacts/architecture.md:
| Hook | Sprint 22 (This Story) | Sprint 23 (Future) |
|---|---|---|
| Trace context | Mock trace IDs in test fixtures | Real OTel trace context from Collector |
| Test results | JUnit XML + structured JSON | OTel exporter ingests into VictoriaMetrics |
Key principle: Emit data in formats Sprint 23 can ingest without code changes. No Sprint 22 code imports or depends on MELT libraries.
Implementation Guidance
JavaScript (trace-context.js):
- Use CommonJS (
module.exports) — this is in the roottests/directory which follows Node.js conventions - Deterministic ID generation: hash the test name using a simple algorithm (e.g., DJB2 or FNV-1a) and truncate to OTel format lengths. Do NOT use
Date.now()orMath.random()— NFR10 requires reproducibility. - OTel trace ID format: 32 lowercase hex characters (e.g.,
a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4) - OTel span ID format: 16 lowercase hex characters
- The
setTraceContext()function should store trace context in a module-level variable thatgetTestTraceId()reads — this is the Jest-compatible pattern since Jest has no built-in context propagation. - The structured JSON output should match this shape for Sprint 23 compatibility:
{ "trace_id": "a1b2c3d4...", "span_id": "e5f6a1b2...", "start_time": "2026-05-27T10:00:00.000Z", "metadata": { "test_name": "should do X", "framework": "jest" } }
Python (trace-context.py):
- Place in
tests/melt-helpers/(shared test utilities, not insidegenie-ai-overlay/) - The pytest fixture should be importable via
conftest.pyor directly:from tests.melt_helpers.trace_context import trace_context - Use the same hash algorithm as JS for cross-language correlation
- Include ITU copyright header (required by NFR23)
- Must pass Ruff linting (NFR24)
File Locations
| File | Action | Notes |
|---|---|---|
tests/melt-helpers/trace-context.js |
NEW | JS trace context helper |
tests/melt-helpers/trace-context.py |
NEW | Python trace context fixture |
tests/melt-helpers/README.md |
NEW | Documentation for Sprint 23 integration |
tests/melt-helpers/trace-context.test.js |
NEW | JS helper tests |
genie-ai-overlay/tests/test_trace_context.py |
NEW | Python fixture tests |
Dependencies
-
Epic 7 is a Wave 0 prerequisite per
_bmad-output/planning-artifacts/epics.md: "Epic 7 Stories 7.1–7.2 — test utilities imported by Epics 3–6" - This story has no upstream dependency — it creates new files with no existing code to modify
- Downstream: Stories 7.2 (log assertions), and test suites in Epics 2-5 can optionally import these helpers
Existing Patterns to Follow
- Backend tests use
jest.mock()hoisting with closure-based references - OPEA tests use
conftest.pyfixtures with@pytest.fixture - Logger mocking pattern from
components/gov-chat-backend/__tests__/services/user-provisioning-service.test.js:expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('...')) - Project root
tests/directory already hasconfig-validator/ande2e/as sibling directories
Critical Constraints
-
NEVER import
@opentelemetry/*or any OTel library — these don't exist in Sprint 22 -
NEVER use
uuidorMath.random()for trace IDs — NFR10 requires deterministic reproducibility -
NEVER use ES imports in JS files — CommonJS only (
require()/module.exports) - ALWAYS include ITU copyright header in Python files
References
- Architecture:
_bmad-output/planning-artifacts/architecture.md(MELT Instrumentation section, lines 269-280, 478-505) - Epics:
_bmad-output/planning-artifacts/epics.md(Story 7.1, lines 909-925) - PRD:
_bmad-output/planning-artifacts/prd.md(FR40-FR41, MELT requirements) - Project context:
_bmad-output/project-context.md(Python copyright headers rule)