188 lines
6.4 KiB
JavaScript
188 lines
6.4 KiB
JavaScript
import { ActionRecorder } from './recorder.js';
|
|
import { PlaywrightGenerator } from './generator.js';
|
|
import * as fs from 'fs/promises';
|
|
import * as path from 'path';
|
|
// Helper function to get workspace root path
|
|
const getWorkspaceRoot = () => {
|
|
return process.cwd();
|
|
};
|
|
const DEFAULT_OPTIONS = {
|
|
outputPath: path.join(getWorkspaceRoot(), 'e2e'),
|
|
testNamePrefix: 'Test',
|
|
includeComments: true
|
|
};
|
|
export const startCodegenSession = {
|
|
name: 'start_codegen_session',
|
|
description: 'Start a new code generation session to record MCP tool actions',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
options: {
|
|
type: 'object',
|
|
description: 'Code generation options',
|
|
properties: {
|
|
outputPath: { type: 'string' },
|
|
testNamePrefix: { type: 'string' },
|
|
includeComments: { type: 'boolean' }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
handler: async ({ options = {} }) => {
|
|
try {
|
|
// Merge provided options with defaults
|
|
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
// Ensure output path is absolute and normalized
|
|
const workspaceRoot = getWorkspaceRoot();
|
|
const outputPath = path.isAbsolute(mergedOptions.outputPath)
|
|
? mergedOptions.outputPath
|
|
: path.join(workspaceRoot, mergedOptions.outputPath);
|
|
mergedOptions.outputPath = outputPath;
|
|
// Ensure output directory exists
|
|
try {
|
|
await fs.mkdir(outputPath, { recursive: true });
|
|
}
|
|
catch (mkdirError) {
|
|
throw new Error(`Failed to create output directory: ${mkdirError.message}`);
|
|
}
|
|
const sessionId = ActionRecorder.getInstance().startSession();
|
|
// Store options with the session
|
|
const recorder = ActionRecorder.getInstance();
|
|
const session = recorder.getSession(sessionId);
|
|
if (session) {
|
|
session.options = mergedOptions;
|
|
}
|
|
return {
|
|
sessionId,
|
|
options: mergedOptions,
|
|
message: `Started codegen session. Tests will be generated in: ${outputPath}`
|
|
};
|
|
}
|
|
catch (error) {
|
|
throw new Error(`Failed to start codegen session: ${error.message}`);
|
|
}
|
|
}
|
|
};
|
|
export const endCodegenSession = {
|
|
name: 'end_codegen_session',
|
|
description: 'End the current code generation session and generate Playwright test',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
sessionId: {
|
|
type: 'string',
|
|
description: 'ID of the session to end'
|
|
}
|
|
},
|
|
required: ['sessionId']
|
|
},
|
|
handler: async ({ sessionId }) => {
|
|
try {
|
|
const recorder = ActionRecorder.getInstance();
|
|
const session = recorder.endSession(sessionId);
|
|
if (!session) {
|
|
throw new Error(`Session ${sessionId} not found`);
|
|
}
|
|
if (!session.options) {
|
|
throw new Error(`Session ${sessionId} has no options configured`);
|
|
}
|
|
const generator = new PlaywrightGenerator(session.options);
|
|
const result = await generator.generateTest(session);
|
|
// Double check output directory exists
|
|
const outputDir = path.dirname(result.filePath);
|
|
await fs.mkdir(outputDir, { recursive: true });
|
|
// Write test file
|
|
try {
|
|
await fs.writeFile(result.filePath, result.testCode, 'utf-8');
|
|
}
|
|
catch (writeError) {
|
|
throw new Error(`Failed to write test file: ${writeError.message}`);
|
|
}
|
|
// Close Playwright browser and cleanup
|
|
try {
|
|
if (global.browser?.isConnected()) {
|
|
await global.browser.close();
|
|
}
|
|
}
|
|
catch (browserError) {
|
|
console.warn('Failed to close browser:', browserError.message);
|
|
}
|
|
finally {
|
|
global.browser = undefined;
|
|
global.page = undefined;
|
|
}
|
|
const absolutePath = path.resolve(result.filePath);
|
|
return {
|
|
filePath: absolutePath,
|
|
outputDirectory: outputDir,
|
|
testCode: result.testCode,
|
|
message: `Generated test file at: ${absolutePath}\nOutput directory: ${outputDir}`
|
|
};
|
|
}
|
|
catch (error) {
|
|
// Ensure browser cleanup even on error
|
|
try {
|
|
if (global.browser?.isConnected()) {
|
|
await global.browser.close();
|
|
}
|
|
}
|
|
catch {
|
|
// Ignore cleanup errors
|
|
}
|
|
finally {
|
|
global.browser = undefined;
|
|
global.page = undefined;
|
|
}
|
|
throw new Error(`Failed to end codegen session: ${error.message}`);
|
|
}
|
|
}
|
|
};
|
|
export const getCodegenSession = {
|
|
name: 'get_codegen_session',
|
|
description: 'Get information about a code generation session',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
sessionId: {
|
|
type: 'string',
|
|
description: 'ID of the session to retrieve'
|
|
}
|
|
},
|
|
required: ['sessionId']
|
|
},
|
|
handler: async ({ sessionId }) => {
|
|
const session = ActionRecorder.getInstance().getSession(sessionId);
|
|
if (!session) {
|
|
throw new Error(`Session ${sessionId} not found`);
|
|
}
|
|
return session;
|
|
}
|
|
};
|
|
export const clearCodegenSession = {
|
|
name: 'clear_codegen_session',
|
|
description: 'Clear a code generation session',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
sessionId: {
|
|
type: 'string',
|
|
description: 'ID of the session to clear'
|
|
}
|
|
},
|
|
required: ['sessionId']
|
|
},
|
|
handler: async ({ sessionId }) => {
|
|
const success = ActionRecorder.getInstance().clearSession(sessionId);
|
|
if (!success) {
|
|
throw new Error(`Session ${sessionId} not found`);
|
|
}
|
|
return { success };
|
|
}
|
|
};
|
|
export const codegenTools = [
|
|
startCodegenSession,
|
|
endCodegenSession,
|
|
getCodegenSession,
|
|
clearCodegenSession
|
|
];
|