Skip to content

Commit 0bb9117

Browse files
authored
Add public API contract tests (browserbase#1290)
# why We need to create stubs for the client sdk, and this allows us to write tests so that we can confirm that our stub signatures have full parity. # what changed Added full contract tests which check just the public facing API *types* https://vitest.dev/guide/testing-types Also made it so that all types from `/public/types` are explicitly re-exported through index.ts, so that we can have a single place to review all public exports. These tests might be a bit more in-depth then we ultimately want - we are checking function signatures for stuff like the vercel AI client, which might be more brittle than we want currently, but we will likely be removing some of these public exports anyways with the canonical work. # test plan You can run `pnpm --filter @browserbasehq/stagehand test:vitest`
1 parent 8ff7d27 commit 0bb9117

11 files changed

Lines changed: 1065 additions & 142 deletions

.changeset/dark-pans-carry.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@browserbasehq/stagehand": patch
33
---
44

5-
Add support for zod 4, while maintaining backwards compatibility for zod 3
5+
Add support for zod 4, while maintaining backwards compatibility for zod 3

packages/core/lib/v3/index.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
11
export { V3 } from "./v3";
22
export { V3 as Stagehand } from "./v3";
33

4-
// Re-export common V3 types for consumers
5-
export * from "./llm/LLMClient";
64
export * from "./types/public";
7-
export * from "./agent/AgentProvider";
8-
export * from "../utils";
9-
export * from "./zodCompat";
5+
export { AnnotatedScreenshotText, LLMClient } from "./llm/LLMClient";
6+
7+
export { AgentProvider, modelToAgentProviderMap } from "./agent/AgentProvider";
8+
9+
export {
10+
validateZodSchema,
11+
isRunningInBun,
12+
toGeminiSchema,
13+
getZodType,
14+
transformSchema,
15+
injectUrls,
16+
providerEnvVarMap,
17+
loadApiKeyFromEnv,
18+
trimTrailingTextNode,
19+
jsonSchemaToZod,
20+
} from "../utils";
21+
export { isZod4Schema, isZod3Schema, toJsonSchema } from "./zodCompat";
22+
1023
export { connectToMCPServer } from "./mcp/connection";
1124
export { V3Evaluator } from "../v3Evaluator";
25+
26+
export type {
27+
ChatMessage,
28+
ChatMessageContent,
29+
ChatMessageImageContent,
30+
ChatMessageTextContent,
31+
ChatCompletionOptions,
32+
LLMResponse,
33+
CreateChatCompletionOptions,
34+
LLMUsage,
35+
LLMParsedResponse,
36+
} from "./llm/LLMClient";
37+
38+
export type {
39+
StagehandZodSchema,
40+
StagehandZodObject,
41+
InferStagehandSchema,
42+
JsonSchemaDocument,
43+
} from "./zodCompat";
44+
45+
export type { JsonSchema, JsonSchemaProperty } from "../utils";

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"e2e:bb": "playwright test --config=lib/v3/tests/v3.bb.playwright.config.ts",
2020
"lint": "cd ../.. && prettier --check packages/core && cd packages/core && eslint .",
2121
"format": "prettier --write .",
22-
"test:vitest": "pnpm run build-js && vitest run --config vitest.config.ts"
22+
"test:vitest": "pnpm run build-js && pnpm run typecheck && vitest run --config vitest.config.ts"
2323
},
2424
"files": [
2525
"dist/index.js",
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { describe, expect, it } from "vitest";
2+
import StagehandDefaultExport, * as Stagehand from "../../dist/index.js";
3+
import { publicErrorTypes } from "./public-error-types.test";
4+
5+
// Type matcher guidelines:
6+
//
7+
// toEqualTypeOf – Default. Assert full, deep type equality; any type change should fail.
8+
// e.g. expectTypeOf<ReturnType<typeof foo>>().toEqualTypeOf<FooResult>()
9+
//
10+
// toMatchObjectType – Assert (part of) an object's shape while allowing extra fields.
11+
// e.g. expectTypeOf(user).toMatchObjectType<{ id: string; email: string }>()
12+
//
13+
// toExtend – Assert that a type is compatible with a broader contract (assignable/extends).
14+
// e.g. expectTypeOf<User>().toExtend<BaseUser>()
15+
16+
const publicApiShape = {
17+
AISdkClient: Stagehand.AISdkClient,
18+
AVAILABLE_CUA_MODELS: Stagehand.AVAILABLE_CUA_MODELS,
19+
AgentProvider: Stagehand.AgentProvider,
20+
AnnotatedScreenshotText: Stagehand.AnnotatedScreenshotText,
21+
ConsoleMessage: Stagehand.ConsoleMessage,
22+
LLMClient: Stagehand.LLMClient,
23+
LOG_LEVEL_NAMES: Stagehand.LOG_LEVEL_NAMES,
24+
Response: Stagehand.Response,
25+
Stagehand: Stagehand.Stagehand,
26+
V3: Stagehand.V3,
27+
V3Evaluator: Stagehand.V3Evaluator,
28+
V3FunctionName: Stagehand.V3FunctionName,
29+
connectToMCPServer: Stagehand.connectToMCPServer,
30+
default: StagehandDefaultExport,
31+
defaultExtractSchema: Stagehand.defaultExtractSchema,
32+
getZodType: Stagehand.getZodType,
33+
injectUrls: Stagehand.injectUrls,
34+
isRunningInBun: Stagehand.isRunningInBun,
35+
isZod3Schema: Stagehand.isZod3Schema,
36+
isZod4Schema: Stagehand.isZod4Schema,
37+
jsonSchemaToZod: Stagehand.jsonSchemaToZod,
38+
loadApiKeyFromEnv: Stagehand.loadApiKeyFromEnv,
39+
modelToAgentProviderMap: Stagehand.modelToAgentProviderMap,
40+
pageTextSchema: Stagehand.pageTextSchema,
41+
providerEnvVarMap: Stagehand.providerEnvVarMap,
42+
toGeminiSchema: Stagehand.toGeminiSchema,
43+
toJsonSchema: Stagehand.toJsonSchema,
44+
transformSchema: Stagehand.transformSchema,
45+
trimTrailingTextNode: Stagehand.trimTrailingTextNode,
46+
validateZodSchema: Stagehand.validateZodSchema,
47+
...publicErrorTypes,
48+
} as const;
49+
50+
type StagehandExports = typeof Stagehand & {
51+
default: typeof StagehandDefaultExport;
52+
};
53+
54+
type PublicAPI = {
55+
[K in keyof typeof publicApiShape]: StagehandExports[K];
56+
};
57+
58+
describe("Stagehand public API export surface", () => {
59+
it("public API shape matches module exports", () => {
60+
const _check: PublicAPI = publicApiShape;
61+
void _check;
62+
});
63+
64+
it("does not expose unexpected top-level exports", () => {
65+
const expected = Object.keys(publicApiShape).sort();
66+
const actual = Object.keys(Stagehand).sort();
67+
expect(actual).toStrictEqual(expected);
68+
});
69+
});

0 commit comments

Comments
 (0)