Skip to content

Commit a5b626b

Browse files
committed
fix(docs): expose root response schemas and generate clean-checkout types
1 parent fb45fae commit a5b626b

5 files changed

Lines changed: 145 additions & 49 deletions

File tree

‎apps/docs/components/docs/api-schema.tsx‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,12 @@ export function ApiSchema({ schema: raw, document, name, required, ancestors = [
8888
: (reference?.split('/').at(-1) ?? 'value')
8989
return (
9090
<div className='min-w-0 py-4'>
91-
{name && (
92-
<div className='mb-2 flex flex-wrap items-baseline gap-2.5 font-mono text-docs-control leading-5'>
93-
<span className='break-all text-[var(--docs-heading)]'>{name}</span>
94-
<span className='text-[var(--docs-muted)]'>{type}</span>
95-
{required && <span className='ml-auto text-[var(--docs-muted)]'>Required</span>}
96-
{schema.deprecated === true && <NeutralBadge>Deprecated</NeutralBadge>}
97-
</div>
98-
)}
91+
<div className='mb-2 flex flex-wrap items-baseline gap-2.5 font-mono text-docs-control leading-5'>
92+
{name && <span className='break-all text-[var(--docs-heading)]'>{name}</span>}
93+
<span className='text-[var(--docs-muted)]'>{type}</span>
94+
{required && <span className='ml-auto text-[var(--docs-muted)]'>Required</span>}
95+
{schema.deprecated === true && <NeutralBadge>Deprecated</NeutralBadge>}
96+
</div>
9997
{typeof schema.description === 'string' && (
10098
<div className='text-[var(--docs-muted)] text-docs-table [&_p]:my-0 [&_p]:text-docs-table [&_p]:text-inherit'>
10199
<Markdown>{schema.description}</Markdown>

‎apps/docs/components/ui/tabs.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export function Tabs({
170170
>
171171
<noscript>
172172
<style>{`
173-
.docs-root [data-docs-tab-panel][hidden] { display: block; }
173+
.docs-root [data-docs-tab-panel][hidden] { display: block !important; }
174174
.docs-root [data-docs-tabs-root] [role="tablist"],
175175
.docs-root [data-docs-tabs-root] select,
176176
.docs-root [data-docs-tabs-root] button { display: none; }

‎apps/docs/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"test": "vitest run",
1313
"test:negotiation:e2e": "bun scripts/test-negotiation-e2e.ts",
1414
"test:headers:e2e": "bun scripts/test-header-merge-e2e.ts",
15-
"type-check": "bun run content:generate && tsc --noEmit",
15+
"type-check": "bun run content:generate && next typegen && tsc --noEmit",
1616
"lint": "biome check --write --unsafe .",
1717
"lint:check": "biome check .",
1818
"format": "biome format --write .",

‎apps/docs/scripts/benchmark-readiness.ts‎

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -609,8 +609,8 @@ async function existingLink(page: Page, route: string): Promise<Locator | null>
609609

610610
function searchInput(page: Page) {
611611
return page
612-
.getByRole('combobox')
613-
.or(page.getByRole('searchbox'))
612+
.getByRole('combobox', { name: /Search/i })
613+
.or(page.getByRole('searchbox', { name: /Search/i }))
614614
.or(page.getByPlaceholder(/Search/))
615615
.filter({ visible: true })
616616
.first()
@@ -629,7 +629,7 @@ async function readyForControls(page: Page) {
629629
.click()
630630
}
631631
await input.waitFor()
632-
await page.waitForFunction(() => document.activeElement instanceof HTMLInputElement)
632+
await expect(input).toBeFocused()
633633
await page.keyboard.press('Escape')
634634
await input.waitFor({ state: 'hidden' })
635635
}
@@ -940,11 +940,7 @@ async function interactions(browser: Browser, profile: Profile, repetition: numb
940940
const trigger = run.page
941941
.getByRole('button', { name: /^(Expand .*workflow preview|Inspect workflow: .*)$/i })
942942
.first()
943-
if (!(await trigger.count()))
944-
return {
945-
status: 'unavailable',
946-
error: 'No named workflow inspection trigger on this baseline.',
947-
}
943+
await trigger.waitFor({ state: 'visible', timeout: 15_000 })
948944
await trigger.scrollIntoViewIfNeeded()
949945
const start = performance.now()
950946
await trigger.click()
@@ -1007,6 +1003,44 @@ async function interactions(browser: Browser, profile: Profile, repetition: numb
10071003
}
10081004
}
10091005

1006+
async function tabControl(
1007+
run: Awaited<ReturnType<typeof contextFor>>,
1008+
profile: Profile,
1009+
repetition: number,
1010+
route: string,
1011+
control: { scenario: string; label: string; choice: RegExp }
1012+
) {
1013+
await measure(profile, route, repetition, control.scenario, async () => {
1014+
const list = run.page.getByRole('tablist', { name: control.label, exact: true })
1015+
const tab = list.getByRole('tab', { name: control.choice }).filter({ visible: true }).first()
1016+
if (!(await tab.count()))
1017+
return {
1018+
status: 'unavailable',
1019+
error: `No matching ${control.label} tab on this baseline.`,
1020+
}
1021+
const choices = await list.getByRole('tab').count()
1022+
await tab.scrollIntoViewIfNeeded()
1023+
const start = performance.now()
1024+
await tab.click()
1025+
await expect(tab).toHaveAttribute('aria-selected', 'true')
1026+
const id = await tab.getAttribute('aria-controls')
1027+
if (!id) throw new Error('Tab has no linked content')
1028+
const panel = run.page.locator(`[id="${id}"]`)
1029+
await panel.waitFor({ state: 'visible' })
1030+
await painted(run.page)
1031+
return {
1032+
status: 'completed',
1033+
feedbackMs: choices > 1 ? performance.now() - start : undefined,
1034+
data: {
1035+
choices,
1036+
selected: await tab.textContent(),
1037+
contentLength: (await panel.textContent())?.length,
1038+
applicableTransition: choices > 1,
1039+
},
1040+
}
1041+
})
1042+
}
1043+
10101044
async function apiControls(
10111045
run: Awaited<ReturnType<typeof contextFor>>,
10121046
profile: Profile,
@@ -1037,39 +1071,11 @@ async function apiControls(
10371071
{ scenario: 'response-status-control', label: 'Response status', choice: /^400$/ },
10381072
{
10391073
scenario: 'response-media-control',
1040-
label: 'Response 400 content type',
1074+
label: '400 response content type',
10411075
choice: /^application\/json$/,
10421076
},
10431077
]) {
1044-
await measure(profile, route, repetition, control.scenario, async () => {
1045-
const list = run.page.getByRole('tablist', { name: control.label, exact: true })
1046-
const tab = list.getByRole('tab', { name: control.choice }).filter({ visible: true }).first()
1047-
if (!(await tab.count()))
1048-
return {
1049-
status: 'unavailable',
1050-
error: `No matching ${control.label} tab on this baseline.`,
1051-
}
1052-
const choices = await list.getByRole('tab').count()
1053-
await tab.scrollIntoViewIfNeeded()
1054-
const start = performance.now()
1055-
await tab.click()
1056-
await expect(tab).toHaveAttribute('aria-selected', 'true')
1057-
const id = await tab.getAttribute('aria-controls')
1058-
if (!id) throw new Error('Tab has no linked content')
1059-
const panel = run.page.locator(`[id="${id}"]`)
1060-
await panel.waitFor({ state: 'visible' })
1061-
await painted(run.page)
1062-
return {
1063-
status: 'completed',
1064-
feedbackMs: choices > 1 ? performance.now() - start : undefined,
1065-
data: {
1066-
choices,
1067-
selected: await tab.textContent(),
1068-
contentLength: (await panel.textContent())?.length,
1069-
applicableTransition: choices > 1,
1070-
},
1071-
}
1072-
})
1078+
await tabControl(run, profile, repetition, route, control)
10731079
}
10741080
await measure(profile, route, repetition, 'schema-disclosure-control', async () => {
10751081
const details = run.page.locator('main details:not([open])').filter({ visible: true }).first()
@@ -1127,6 +1133,21 @@ async function apiControls(
11271133
data: { exactSelectedSampleCopied: true, characters: expected?.length },
11281134
}
11291135
})
1136+
const streamingRoute = '/api-reference/workflows/executeWorkflowV2'
1137+
await measure(profile, streamingRoute, repetition, 'response-format-readiness', async () => {
1138+
const response = await run.page.goto(new URL(streamingRoute, base).href, {
1139+
waitUntil: 'domcontentloaded',
1140+
})
1141+
if (!response?.ok()) throw new Error(`Document returned ${response?.status()}`)
1142+
await meaningful(run.page, streamingRoute)
1143+
await readyForControls(run.page)
1144+
return { status: 'completed' }
1145+
})
1146+
await tabControl(run, profile, repetition, streamingRoute, {
1147+
scenario: 'response-format-control',
1148+
label: '200 response content type',
1149+
choice: /^text\/event-stream$/,
1150+
})
11301151
}
11311152

11321153
async function lighthouse(profile: Profile, route: string, repetition: number) {
@@ -1282,6 +1303,14 @@ if (mode === 'lighthouse') {
12821303
}
12831304
}
12841305
if (scenarios.has('interactions')) await interactions(browser, profile, repetition)
1306+
else if (scenarios.has('api-controls')) {
1307+
const run = await contextFor(browser, profile)
1308+
try {
1309+
await apiControls(run, profile, repetition)
1310+
} finally {
1311+
await run.context.close()
1312+
}
1313+
}
12851314
}
12861315
} finally {
12871316
await browser.close()

‎apps/docs/scripts/test-navigation-e2e.ts‎

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ async function check(name: string, action: () => Promise<void>, unavailable?: st
6666

6767
async function open(page: Page, path: string) {
6868
const response = await page.goto(new URL(path, target).href, { waitUntil: 'domcontentloaded' })
69-
expect(response?.ok()).toBe(true)
69+
expect(response?.ok() || response?.status() === 304).toBe(true)
7070
await expect(page.getByRole('heading', { level: 1 }).first()).toBeVisible()
7171
await page.evaluate(() => document.fonts.ready)
7272
await expect(
@@ -686,6 +686,75 @@ try {
686686
await expect(page.locator(`[id="${panelId}"]`)).toBeVisible()
687687
await page.screenshot({ path: join(directory, 'api-language-after-reload.png') })
688688
})
689+
await check(
690+
'Streaming response formats expose their type without changing request language',
691+
async () => {
692+
const page = await languageContext.newPage()
693+
try {
694+
await open(page, '/api-reference/workflows/executeWorkflowV2')
695+
const language = page.getByRole('combobox', { name: 'Request status', exact: true })
696+
const python = await language
697+
.getByRole('option', { name: /^Python/ })
698+
.first()
699+
.getAttribute('value')
700+
if (!python) throw new Error('Execute workflow has no Python request example')
701+
await language.selectOption(python)
702+
await expect(language).toHaveValue(python)
703+
const requestId = await language.getAttribute('aria-controls')
704+
if (!requestId) throw new Error('Selected request has no sample panel')
705+
const request = page.locator(`[id="${requestId}"] code`)
706+
const originalSample = await request.textContent()
707+
const formats = page.getByRole('tablist', {
708+
name: '200 response content type',
709+
exact: true,
710+
})
711+
const observations = []
712+
const missingTypes: string[] = []
713+
for (const [index, format] of [
714+
'application/json',
715+
'application/x-ndjson',
716+
'text/event-stream',
717+
].entries()) {
718+
const tab = formats.getByRole('tab', { name: format, exact: true })
719+
await tab.click()
720+
await expect(tab).toHaveAttribute('aria-selected', 'true')
721+
const panelId = await tab.getAttribute('aria-controls')
722+
if (!panelId) throw new Error(`Response format ${format} has no panel`)
723+
const panel = page.locator(`[id="${panelId}"]`)
724+
await expect(panel).toBeVisible()
725+
await expect(language).toHaveValue(python)
726+
await expect(request).toHaveText(originalSample ?? '')
727+
const stringTypeVisible = await panel
728+
.getByText('string', { exact: true })
729+
.first()
730+
.isVisible()
731+
if (format !== 'application/json' && !stringTypeVisible) missingTypes.push(format)
732+
if (format === 'application/json')
733+
expect((await panel.innerText()).trim().length).toBeGreaterThan(0)
734+
observations.push({
735+
format,
736+
stringTypeVisible,
737+
requestLanguage: 'Python',
738+
requestSampleUnchanged: true,
739+
contentLength: (await panel.innerText()).trim().length,
740+
})
741+
await panel.scrollIntoViewIfNeeded()
742+
await page.screenshot({
743+
path: join(directory, `streaming-response-format-${index}.png`),
744+
})
745+
}
746+
await writeFile(
747+
join(directory, 'streaming-response-formats.json'),
748+
`${JSON.stringify(observations, null, 2)}\n`
749+
)
750+
expect(missingTypes, 'Streaming response schemas must display their string type').toEqual(
751+
[]
752+
)
753+
} finally {
754+
await page.close()
755+
}
756+
}
757+
)
689758
await check('API language preference tolerates an unavailable stored language', async () => {
690759
const page = await languageContext.newPage()
691760
await open(page, '/api-reference/logs/getLog')

0 commit comments

Comments
 (0)