Skip to main content
Glama

Playwright MCP Server

by BhanuTJ93
generator.ts6.06 kB
import * as path from 'path'; import { CodegenAction, CodegenOptions, CodegenResult, CodegenSession, PlaywrightTestCase } from './types.js'; export class PlaywrightGenerator { private static readonly DEFAULT_OPTIONS: Required<CodegenOptions> = { outputPath: 'tests', testNamePrefix: 'MCP', includeComments: true, }; private options: Required<CodegenOptions>; constructor(options: CodegenOptions = {}) { this.validateOptions(options); this.options = { ...PlaywrightGenerator.DEFAULT_OPTIONS, ...options }; } private validateOptions(options: CodegenOptions): void { if (options.outputPath && typeof options.outputPath !== 'string') { throw new Error('outputPath must be a string'); } if (options.testNamePrefix && typeof options.testNamePrefix !== 'string') { throw new Error('testNamePrefix must be a string'); } if (options.includeComments !== undefined && typeof options.includeComments !== 'boolean') { throw new Error('includeComments must be a boolean'); } } async generateTest(session: CodegenSession): Promise<CodegenResult> { if (!session || !Array.isArray(session.actions)) { throw new Error('Invalid session data'); } const testCase = this.createTestCase(session); const testCode = this.generateTestCode(testCase); const filePath = this.getOutputFilePath(session); return { testCode, filePath, sessionId: session.id, }; } private createTestCase(session: CodegenSession): PlaywrightTestCase { const testCase: PlaywrightTestCase = { name: `${this.options.testNamePrefix}_${new Date(session.startTime).toISOString().split('T')[0]}`, steps: [], imports: new Set(['test', 'expect']), }; for (const action of session.actions) { const step = this.convertActionToStep(action); if (step) { testCase.steps.push(step); } } return testCase; } private convertActionToStep(action: CodegenAction): string | null { const { toolName, parameters } = action; switch (toolName) { case 'playwright_navigate': return this.generateNavigateStep(parameters); case 'playwright_fill': return this.generateFillStep(parameters); case 'playwright_click': return this.generateClickStep(parameters); case 'playwright_screenshot': return this.generateScreenshotStep(parameters); case 'playwright_expect_response': return this.generateExpectResponseStep(parameters); case 'playwright_assert_response': return this.generateAssertResponseStep(parameters); case 'playwright_hover': return this.generateHoverStep(parameters); case 'playwright_select': return this.generateSelectStep(parameters); case 'playwright_custom_user_agent': return this.generateCustomUserAgentStep(parameters); default: console.warn(`Unsupported tool: ${toolName}`); return null; } } private generateNavigateStep(parameters: Record<string, unknown>): string { const { url, waitUntil } = parameters; const options = waitUntil ? `, { waitUntil: '${waitUntil}' }` : ''; return ` // Navigate to URL await page.goto('${url}'${options});`; } private generateFillStep(parameters: Record<string, unknown>): string { const { selector, value } = parameters; return ` // Fill input field await page.fill('${selector}', '${value}');`; } private generateClickStep(parameters: Record<string, unknown>): string { const { selector } = parameters; return ` // Click element await page.click('${selector}');`; } private generateScreenshotStep(parameters: Record<string, unknown>): string { const { name, fullPage = false, path } = parameters; const options = []; if (fullPage) options.push('fullPage: true'); if (path) options.push(`path: '${path}'`); const optionsStr = options.length > 0 ? `, { ${options.join(', ')} }` : ''; return ` // Take screenshot await page.screenshot({ path: '${name}.png'${optionsStr} });`; } private generateExpectResponseStep(parameters: Record<string, unknown>): string { const { url, id } = parameters; return ` // Wait for response const ${id}Response = page.waitForResponse('${url}');`; } private generateAssertResponseStep(parameters: Record<string, unknown>): string { const { id, value } = parameters; const assertion = value ? `\n const responseText = await ${id}Response.text();\n expect(responseText).toContain('${value}');` : `\n expect(${id}Response.ok()).toBeTruthy();`; return ` // Assert response${assertion}`; } private generateHoverStep(parameters: Record<string, unknown>): string { const { selector } = parameters; return ` // Hover over element await page.hover('${selector}');`; } private generateSelectStep(parameters: Record<string, unknown>): string { const { selector, value } = parameters; return ` // Select option await page.selectOption('${selector}', '${value}');`; } private generateCustomUserAgentStep(parameters: Record<string, unknown>): string { const { userAgent } = parameters; return ` // Set custom user agent await context.setUserAgent('${userAgent}');`; } private generateTestCode(testCase: PlaywrightTestCase): string { const imports = Array.from(testCase.imports) .map(imp => `import { ${imp} } from '@playwright/test';`) .join('\n'); return ` ${imports} test('${testCase.name}', async ({ page, context }) => { ${testCase.steps.join('\n')} });`; } private getOutputFilePath(session: CodegenSession): string { if (!session.id) { throw new Error('Session ID is required'); } const sanitizedPrefix = this.options.testNamePrefix.toLowerCase().replace(/[^a-z0-9_]/g, '_'); const fileName = `${sanitizedPrefix}_${session.id}.spec.ts`; return path.resolve(this.options.outputPath, fileName); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BhanuTJ93/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server