Files
rs-sdk/sdk/test/api-docs.test.ts
Max BittkerandClaude Opus 5 e5fb1e9d07 Make the agent API self-describing and add regression CI (#43)
* Improve agent API docs and validation

* Drop the wiki search tool

Removes wiki/search.ts and its test. The index only covered names, aliases,
summaries and Sources lines, so it had worse recall than grep on body text
(e.g. "cow hide" missed skills/crafting.md), and normalize() stripped
underscores so map-square queries matched every neighbouring square
(m50_50 returned m50_53 NPCs). The computed mapSquareBounds were only
indexed as text, so coordinate lookups — the one thing grep can't do —
never worked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Regenerate the wiki from server/content

Adds the coordinate-samples column to NPC location tables and picks up
content drift the checked-in pages had missed (807 NPC, 117 shop, 1573 item
pages; 335 of them new). Examples: Aubury now stocks 1000 chaos/death runes
rather than 500, and shop rows point at "Vial of water"/"Bolts" instead of
the stale "Vial"/"Bolt" names.

Also stops all three generators from crashing on their final step. Each one
read wiki/README.md unconditionally, but that file has never existed, so the
index update threw ENOENT on every run. Skip it when absent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-24 17:52:51 -04:00

55 lines
2.0 KiB
TypeScript

#!/usr/bin/env bun
import { describe, expect, test } from 'bun:test';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import {
buildApiModel,
generateApiMarkdown,
} from '../generate-api-docs';
const sdkDir = join(import.meta.dir, '..');
describe('generated API reference', () => {
test('matches the checked-in document', async () => {
const [generated, checkedIn] = await Promise.all([
generateApiMarkdown(sdkDir),
readFile(join(sdkDir, 'API.md'), 'utf8'),
]);
expect(checkedIn).toBe(generated);
});
test('contains every public class method and complete signatures', async () => {
const model = await buildApiModel(sdkDir);
const generated = await generateApiMarkdown(sdkDir);
const methods = [...model.botActionsMethods, ...model.sdkMethods];
expect(methods.length).toBeGreaterThan(100);
for (const method of methods) {
expect(generated).toContain(method.name);
expect(method.signature).toContain(':');
}
for (const historicallyOmittedMethod of [
'navigateDialog',
'onConnectionStateChange',
'onStateUpdate',
'waitForCondition',
]) {
expect(methods.some(method => method.name === historicallyOmittedMethod)).toBeTrue();
}
});
test('preserves async markers, return types, defaults, and dotted descriptions', async () => {
const model = await buildApiModel(sdkDir);
const methods = [...model.botActionsMethods, ...model.sdkMethods];
expect(methods.find(method => method.name === 'scanNearbyLocs')?.signature)
.toBe('async scanNearbyLocs(radius?: number): Promise<NearbyLoc[]>');
expect(methods.find(method => method.name === 'sendWalk')?.signature)
.toContain('running: boolean = true');
expect(methods.find(method => method.name === 'useItemOnLoc')?.description)
.toContain('e.g.');
});
});