browser_endtoend
Run end-to-end browser tests using LLMs with Playwright's accessibility tree to validate test cases efficiently.
Instructions
Run an end to end test suit in the browser
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| testDefinition | Yes | The test case definition |
Implementation Reference
- packages/limetest/src/limetest.ts:52-232 (handler)Primary handler for 'browser_endtoend' tool. Orchestrates E2E testing using GPT-4o AI agent with browser sub-tools like navigate, click, screenshot, etc., based on testDefinition input.export const limetest: Tool = { schema: { name: 'browser_endtoend', description: 'Run an end to end test suit in the browser', inputSchema: zodToJsonSchema(limetestSchema) }, handle: async (context, params) => { const validatedParams = limetestSchema.parse(params); const content = `${systemMessage} - List of Urls in target for end to end testing : ${JSON.stringify(validatedParams)}`; const apiKey = context.apiKey; process.env.OPENAI_API_KEY = apiKey; while (true) { const result = generateText({ model: openai('gpt-4o'), messages: [{ role: 'system', content: content }], tools: { // snapshot tools snapshot: tool({ description: 'Capture accessibility snapshot of the current page, this is better than screenshot', parameters: z.object({}), execute: async () => { return await snapshot.snapshot.handle(context); } }), clickSnapshot: tool({ description: 'Perform click on a web page', parameters: snapshot.elementSchema, execute: async (params: z.infer<typeof snapshot.elementSchema>) => { const validatedParams = snapshot.elementSchema.parse(params); return await snapshot.click.handle(context, validatedParams, true); } }), dragSnapshot: tool({ description: 'Perform drag and drop between two elements', parameters: snapshot.dragSchema, execute: async (params: z.infer<typeof snapshot.dragSchema>) => { const validatedParams = snapshot.dragSchema.parse(params); return await snapshot.drag.handle(context, validatedParams, true); } }), hoverSnapshot: tool({ description: 'Hover over element on page', parameters: snapshot.elementSchema, execute: async (params: z.infer<typeof snapshot.elementSchema>) => { const validatedParams = snapshot.elementSchema.parse(params); return await snapshot.hover.handle(context, validatedParams, true); } }), typeSnapshot: tool({ description: 'Type text into editable element', parameters: snapshot.typeSchema, execute: async (params: z.infer<typeof snapshot.typeSchema>) => { const validatedParams = snapshot.typeSchema.parse(params); return await snapshot.type.handle(context, validatedParams, true); } }), selectOptionSnapshot: tool({ description: 'Select an option in a dropdown', parameters: snapshot.selectOptionSchema, execute: async (params: z.infer<typeof snapshot.selectOptionSchema>) => { const validatedParams = snapshot.selectOptionSchema.parse(params); return await snapshot.selectOption.handle(context, validatedParams, true); } }), // screenshot tools screenshot: tool({ description: 'Take a screenshot of the current page', parameters: z.object({}), execute: async () => { return await screenshot.screenshot.handle(context); } }), moveMouseVision: tool({ description: 'Move mouse to a given position', parameters: screenshot.moveMouseSchema, execute: async (params: z.infer<typeof screenshot.moveMouseSchema>) => { const validatedParams = screenshot.moveMouseSchema.parse(params); return await screenshot.moveMouse.handle(context, validatedParams); } }), clickVision: tool({ description: 'Click on a web page', parameters: screenshot.clickVisionkSchema, execute: async (params: z.infer<typeof screenshot.clickVisionkSchema>) => { const validatedParams = screenshot.clickVisionkSchema.parse(params); return await screenshot.clickVision.handle(context, validatedParams); } }), dragVision: tool({ description: 'Drag and drop between two elements', parameters: screenshot.dragVisionkSchema, execute: async (params: z.infer<typeof screenshot.dragVisionkSchema>) => { const validatedParams = screenshot.dragVisionkSchema.parse(params); return await screenshot.dragVision.handle(context, validatedParams); } }), typeVision: tool({ description: 'Type text into editable element', parameters: screenshot.typeVisionkSchema, execute: async (params: z.infer<typeof screenshot.typeVisionkSchema>) => { const validatedParams = screenshot.typeVisionkSchema.parse(params); return await screenshot.typeVision.handle(context, validatedParams); } }), // common tools navigate: tool({ description: 'Navigate to a URL', parameters: common.navigateSchema, execute: async (params: z.infer<typeof common.navigateSchema>) => { const validatedParams = common.navigateSchema.parse(params); return await common.navigate(true).handle(context, validatedParams); } }), goBack: tool({ description: 'Go back to the previous page', parameters: common.goBackSchema, execute: async (params: z.infer<typeof common.goBackSchema>) => { return await common.goBack(true).handle(context); } }), goForward: tool({ description: 'Go back to the previous page', parameters: common.goForwardSchema, execute: async (params: z.infer<typeof common.goBackSchema>) => { return await common.goForward(true).handle(context); } }), wait: tool({ description: 'Wait for a specified time in seconds', parameters: common.waitSchema, execute: async (params: z.infer<typeof common.waitSchema>) => { const validatedParams = common.waitSchema.parse(params); return await common.wait.handle(context, validatedParams, true); } }), pressKey: tool({ description: 'Press a key on the keyboard', parameters: common.pressKeySchema, execute: async (params: z.infer<typeof common.pressKeySchema>) => { const validatedParams = common.pressKeySchema.parse(params); return await common.pressKey.handle(context, validatedParams, true); } }), pdf: tool({ description: 'Save page as PDF', parameters: common.pdfSchema, execute: async (params: z.infer<typeof common.pdfSchema>) => { const validatedParams = common.pdfSchema.parse(params); return await common.pdf.handle(context, validatedParams, true); } }), close: tool({ description: 'Close the page', parameters: common.closeSchema, execute: async (params: z.infer<typeof common.closeSchema>) => { const validatedParams = common.closeSchema.parse(params); return await common.close.handle(context, validatedParams, true); } }), chooseFile: tool({ description: 'Choose one or multiple files to upload', parameters: common.chooseFileSchema, execute: async (params: z.infer<typeof common.chooseFileSchema>) => { const validatedParams = common.chooseFileSchema.parse(params); return await common.chooseFile(true).handle(context, validatedParams); } }) }, maxSteps: 5 }); let fullResponse = ''; for await (const delta of (await result).text) fullResponse += delta; return { content: [{ type: 'text', text: fullResponse }] }; } } };
- Zod schema defining input for browser_endtoend tool: a string testDefinition.const limetestSchema = z.object({ testDefinition: z.string().describe('The test case definition'), // expect: z.string().optional().describe('The expected result of running the test case') });
- packages/mcp/src/index.ts:22-98 (registration)Registers the browser_endtoend tool by importing limetest.limetest and including it in the tools array for the MCP server.import { createServerWithTools } from './server'; import * as limetest from '@limetest/limetest'; import { console } from '@limetest/core'; import type { Tool } from '@limetest/core'; import type { Resource } from '@limetest/core'; import type { Server } from '@modelcontextprotocol/sdk/server/index.js'; import type { LaunchOptions } from 'playwright'; const limetestTools: Tool[] = [ limetest.limetest ]; // const commonTools: Tool[] = [ // common.pressKey, // common.wait, // common.pdf, // common.close, // ]; // const snapshotTools: Tool[] = [ // common.navigate(true), // common.goBack(true), // common.goForward(true), // common.chooseFile(true), // snapshot.snapshot, // snapshot.click, // snapshot.drag, // snapshot.hover, // snapshot.type, // snapshot.selectOption, // snapshot.screenshot, // ...commonTools, // ]; // const screenshotTools: Tool[] = [ // common.navigate(false), // common.goBack(false), // common.goForward(false), // common.chooseFile(false), // screenshot.screenshot, // screenshot.moveMouse, // screenshot.click, // screenshot.drag, // screenshot.type, // ...commonTools, // ]; const resources: Resource[] = [ console, ]; type Options = { userDataDir?: string; launchOptions?: LaunchOptions; cdpEndpoint?: string; // vision?: boolean; // endtoend?: boolean; apiKey?: string; }; const packageJSON = require('../package.json'); export function createServer(options?: Options): Server { // const tools = options?.endtoend ? qaTools : (options?.vision ? screenshotTools : snapshotTools); const tools = limetestTools; return createServerWithTools({ name: 'Playwright', version: packageJSON.version, tools, resources, userDataDir: options?.userDataDir ?? '', launchOptions: options?.launchOptions, cdpEndpoint: options?.cdpEndpoint, apiKey: options?.apiKey, }); }