Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 0 additions & 79 deletions javascript/src/voice/__tests__/voice-contract-surface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
* the suite if any bound scenario is missing a step binding.
*/

import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

Expand All @@ -30,35 +29,6 @@ import {

const HERE = dirname(fileURLToPath(import.meta.url));
const FEATURE_PATH = resolve(HERE, "..", "..", "..", "..", "specs", "voice-agents.feature");
// Capability matrix is now sourced from the published docs page (single
// source-of-truth across Python + TS). The wrapper page documents the
// adapters; the per-capability table itself is auto-generated from the
// Python declarations into _generated/ and imported by the wrapper.
const MATRIX_DOC_PATH = resolve(
HERE,
"..",
"..",
"..",
"..",
"docs",
"docs",
"pages",
"voice",
"capability-matrix.mdx",
);
const GENERATED_MATRIX_PATH = resolve(
HERE,
"..",
"..",
"..",
"..",
"docs",
"docs",
"pages",
"_generated",
"voice",
"capability-matrix.mdx",
);

/**
* Stub adapter used by several scenarios. Keeps the same shape as the
Expand Down Expand Up @@ -266,55 +236,6 @@ describeFeature(
);
},
);

// -----------------------------------------------------------------------
// Scenario: Capability matrix is rendered into adapter docs (lines 763-771)
// -----------------------------------------------------------------------
Scenario(
"Capability matrix is rendered into adapter docs",
({ Given, Then, And }) => {
let doc: string;

Given("the voice-agents documentation", () => {
// Wrapper page (adapter docs) + the auto-generated capability table
// it imports — together they are "the documentation" for the matrix.
doc =
readFileSync(MATRIX_DOC_PATH, "utf8") +
"\n" +
readFileSync(GENERATED_MATRIX_PATH, "utf8");
});

Then("a capability matrix table lists every built-in adapter", () => {
const adapters = [
"PipecatAgentAdapter",
"TwilioAgentAdapter",
"OpenAIRealtimeAgentAdapter",
"ElevenLabsAgentAdapter",
"GeminiLiveAgentAdapter",
"LiveKitAgentAdapter",
"VapiAgentAdapter",
"WebRTCAgentAdapter",
"WebSocketAgentAdapter",
];
for (const adapter of adapters) {
expect(doc).toContain(adapter);
}
});

And(
"each row shows streaming_transcripts, native_vad, dtmf, input/output formats",
() => {
// The generated table's column headers — the literal capability
// keys, exactly as the feature step names them.
expect(doc.toLowerCase()).toContain("streaming_transcripts");
expect(doc.toLowerCase()).toContain("native_vad");
expect(doc.toLowerCase()).toContain("dtmf");
expect(doc.toLowerCase()).toContain("input_formats");
expect(doc.toLowerCase()).toContain("output_formats");
},
);
},
);
},
// AND-match: this file owns exactly the scenarios tagged both @ts-bound and
// @ts-contract-surface. Other PR-N test files bind their own @ts-<scope>
Expand Down
107 changes: 107 additions & 0 deletions javascript/src/voice/__tests__/voice-docs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Documentation lint suite for voice-agent docs.
*
* Binds scenarios tagged `@docs` from `specs/voice-agents.feature`.
* These scenarios assert that rendered documentation files stay in sync
* with the adapter surface — they exercise filesystem I/O against markdown,
* not runtime adapter behaviour, so they live here rather than in the voice
* contract-surface suite.
*
* See issue #518 for the rationale behind the separation.
*/

import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

import { loadFeature, describeFeature } from "@amiceli/vitest-cucumber";
import { expect } from "vitest";

const HERE = dirname(fileURLToPath(import.meta.url));
const FEATURE_PATH = resolve(HERE, "..", "..", "..", "..", "specs", "voice-agents.feature");
// Capability matrix is sourced from the published docs page (single
// source-of-truth across Python + TS). The wrapper page documents the
// adapters; the per-capability table itself is auto-generated from the
// Python declarations into _generated/ and imported by the wrapper.
const MATRIX_DOC_PATH = resolve(
HERE,
"..",
"..",
"..",
"..",
"docs",
"docs",
"pages",
"voice",
"capability-matrix.mdx",
);
const GENERATED_MATRIX_PATH = resolve(
HERE,
"..",
"..",
"..",
"..",
"docs",
"docs",
"pages",
"_generated",
"voice",
"capability-matrix.mdx",
);

const feature = await loadFeature(FEATURE_PATH);

describeFeature(
feature,
({ Scenario }) => {
// -----------------------------------------------------------------------
// Scenario: Capability matrix is rendered into adapter docs
// -----------------------------------------------------------------------
Scenario(
"Capability matrix is rendered into adapter docs",
({ Given, Then, And }) => {
let doc: string;

Given("the voice-agents documentation", () => {
// Wrapper page (adapter docs) + the auto-generated capability table
// it imports — together they are "the documentation" for the matrix.
doc =
readFileSync(MATRIX_DOC_PATH, "utf8") +
"\n" +
readFileSync(GENERATED_MATRIX_PATH, "utf8");
});

Then("a capability matrix table lists every built-in adapter", () => {
const adapters = [
"PipecatAgentAdapter",
"TwilioAgentAdapter",
"OpenAIRealtimeAgentAdapter",
"ElevenLabsAgentAdapter",
"GeminiLiveAgentAdapter",
"LiveKitAgentAdapter",
"VapiAgentAdapter",
"WebRTCAgentAdapter",
"WebSocketAgentAdapter",
];
for (const adapter of adapters) {
expect(doc).toContain(adapter);
}
});

And(
"each row shows streaming_transcripts, native_vad, dtmf, input/output formats",
() => {
// The generated table's column headers — the literal capability
// keys, exactly as the feature step names them.
expect(doc.toLowerCase()).toContain("streaming_transcripts");
expect(doc.toLowerCase()).toContain("native_vad");
expect(doc.toLowerCase()).toContain("dtmf");
expect(doc.toLowerCase()).toContain("input_formats");
expect(doc.toLowerCase()).toContain("output_formats");
},
);
},
);
},
{ includeTags: ["docs"] },
);
2 changes: 1 addition & 1 deletion specs/voice-agents.feature
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ Feature: Voice agent testing in Scenario SDK
When scenario.dtmf("1") runs
Then UnsupportedCapabilityError is raised naming the adapter and the "dtmf" capability

@unit @ts-bound @ts-contract-surface
@docs
Scenario: Capability matrix is rendered into adapter docs
Given the voice-agents documentation
Then a capability matrix table lists every built-in adapter
Expand Down
Loading