159 lines
5.6 KiB
JavaScript
159 lines
5.6 KiB
JavaScript
import * as path from 'path';
|
|
export class PlaywrightGenerator {
|
|
constructor(options = {}) {
|
|
this.validateOptions(options);
|
|
this.options = { ...PlaywrightGenerator.DEFAULT_OPTIONS, ...options };
|
|
}
|
|
validateOptions(options) {
|
|
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) {
|
|
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,
|
|
};
|
|
}
|
|
createTestCase(session) {
|
|
const testCase = {
|
|
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;
|
|
}
|
|
convertActionToStep(action) {
|
|
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;
|
|
}
|
|
}
|
|
generateNavigateStep(parameters) {
|
|
const { url, waitUntil } = parameters;
|
|
const options = waitUntil ? `, { waitUntil: '${waitUntil}' }` : '';
|
|
return `
|
|
// Navigate to URL
|
|
await page.goto('${url}'${options});`;
|
|
}
|
|
generateFillStep(parameters) {
|
|
const { selector, value } = parameters;
|
|
return `
|
|
// Fill input field
|
|
await page.fill('${selector}', '${value}');`;
|
|
}
|
|
generateClickStep(parameters) {
|
|
const { selector } = parameters;
|
|
return `
|
|
// Click element
|
|
await page.click('${selector}');`;
|
|
}
|
|
generateScreenshotStep(parameters) {
|
|
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} });`;
|
|
}
|
|
generateExpectResponseStep(parameters) {
|
|
const { url, id } = parameters;
|
|
return `
|
|
// Wait for response
|
|
const ${id}Response = page.waitForResponse('${url}');`;
|
|
}
|
|
generateAssertResponseStep(parameters) {
|
|
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}`;
|
|
}
|
|
generateHoverStep(parameters) {
|
|
const { selector } = parameters;
|
|
return `
|
|
// Hover over element
|
|
await page.hover('${selector}');`;
|
|
}
|
|
generateSelectStep(parameters) {
|
|
const { selector, value } = parameters;
|
|
return `
|
|
// Select option
|
|
await page.selectOption('${selector}', '${value}');`;
|
|
}
|
|
generateCustomUserAgentStep(parameters) {
|
|
const { userAgent } = parameters;
|
|
return `
|
|
// Set custom user agent
|
|
await context.setUserAgent('${userAgent}');`;
|
|
}
|
|
generateTestCode(testCase) {
|
|
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')}
|
|
});`;
|
|
}
|
|
getOutputFilePath(session) {
|
|
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);
|
|
}
|
|
}
|
|
PlaywrightGenerator.DEFAULT_OPTIONS = {
|
|
outputPath: 'tests',
|
|
testNamePrefix: 'MCP',
|
|
includeComments: true,
|
|
};
|