UNPKG

fintech-automation-test

Version:
194 lines (178 loc) 6.49 kB
const axios = require('axios'); const fs = require('fs'); const config = require('../../../config'); const log4js = require('log4js'); const FormData = require('form-data'); const { initializeOpenAI } = require('./openaiUtils'); const aiAssistant = require('codeceptjs/lib/ai'); const ora = require('ora-classic'); const output = require('codeceptjs/lib/output'); const { error } = require('codeceptjs/lib/output'); const recorder = require('codeceptjs/lib/recorder'); const I2 = require('codeceptjs/lib/actor'); const colors = require('chalk'); const { event } = require('codeceptjs'); const debug = require('debug')('codeceptjs:pause'); const defaultPrompts = { writeStep: (html, input) => [ { role: 'user', content: `I am test engineer writing test in CodeceptJS I have opened web page and I want to use CodeceptJS to ${input} on this page Provide me only one valid CodeceptJS command to accomplish it Use only locators from this HTML: \n\n${html}`, }, ], }; class AiUtils { async getAICommand(I, cmdText, filePath, step) { console.log('cmdText: ' + cmdText); let i = 0; let matches = []; let cmd; try { await this.addStepToFile('//Step-' + step + ':' + cmdText + '\n', filePath); do { if (cmdText.includes('pop up')) I.wait(12); I.wait(5); const res = await I.grabSource(); const html = res; await aiAssistant.setHtmlContext(html); const spinner = ora('Processing AI request...').start(); // await this.addStepToFile('I.wait(4)' + '\n', filePath) cmd = await this.writeSteps(cmdText); spinner.stop(); // Stop the spinner after the AI request is complete console.log('Response From AI: ' + cmd); //let removedText = await removeUnwantedCode(cmd); matches = await this.extractCodeceptJSCommands(cmd); i++; } while (matches.length == 0 && i < 3); //await addStepToFile(cmd+ '\n', filePath); console.log('commands: ' + matches); console.log('matches.length: ' + matches.length); if (matches.length > 0) { if (cmdText.includes('fill')) { for (const step of matches) { try { console.log(`Step ---->${step}`); I.wait(4); await eval(`${step}`); await this.addStepToFile(step + '\n', filePath); } catch (evalErr) { await this.addStepToFile( step + '//Suggestion: Replace with the correct locator.\n', filePath ); await recorder.catchWithoutStop((evalErr) => output.print(colors.yellow("Encountered an error while interacting with the page. A suggestion will be generated for this step."+evalErr)) ); // Continue execution even if this step fails } } } else { try { I.wait(4); await eval(`${matches[0]}`); await this.addStepToFile(matches[0] + '\n', filePath); await this.addStepToFile('I.wait(4)' + '\n', filePath); } catch (evalErr) { await this.addStepToFile( matches[0] + '//Suggestion: Replace with the correct locator.\n', filePath ); await this.addStepToFile('I.wait(4)' + '\n', filePath); await recorder.catchWithoutStop((evalErr) => output.print( colors.bgBlack.bold.white("Encountered an error while interacting with the page. A suggestion will be generated for this step: " + evalErr)) ); // Continue execution even if this step fails } } } else { await this.addStepToFile(cmd + '\n', filePath); await recorder.catchWithoutStop((evalErr) => output.print( colors.bgBlack.bold.white("Encountered an error while interacting with the page. A suggestion will be generated for this step: " + evalErr)) ); // Continue execution even if this step fails } } catch (err) { console.log('error==>' + err); await recorder.catchWithoutStop((evalErr) => output.print( colors.bgBlack.bold.white("Encountered an error while interacting with the page. A suggestion will be generated for this step: " + evalErr)) ); // Continue execution even if this step fails } } async removeUnwantedCode(text) { // Remove lines that contain "Navigate", "Assuming", `});`, and `const { I } = inject();` return text .split('\n') // Split the text into an array of lines .filter( (line) => !line.includes('Navigate') && !line.includes('Assuming') ) // Filter out lines containing "Navigate" and "Assuming" .join('\n') // Join the lines back into a single string .replace(/\}\);/g, '') // Remove closing `});` .replace(/const\s\{\sI\s\}\s=\sinject\(\);\s*/g, ''); // Remove `const { I } = inject();` } async extractCodeceptJSCommands(text) { const commandRegex = /(I\.\w+)\(([\s\S]+?)\);/g; const matches = []; let match; // Find all matching CodeceptJS commands using regex while ((match = commandRegex.exec(text)) !== null) { const actionWithI = match[1]; // Skip commands if they include 'wait' or 'see' or if their size is 3 or less if ( actionWithI.toLowerCase().includes('wait') || actionWithI.toLowerCase().includes('see') || actionWithI.length <= 3 // Skip if length is 3 or less ) { continue; } const args = match[2].trim(); matches.push(`${actionWithI}(${args})`); } return matches; } async extractCodeceptJSCommands2(text) { // const commandRegex = /(I\.\w+)\(([\s\S]+?)\);/g; // const matches = []; // let match; // while ((match = commandRegex.exec(text)) !== null) { // const actionWithI = match[1]; // if ( // actionWithI.toLowerCase().includes('wait') || // actionWithI.toLowerCase().includes('see') // ) { // continue; // } // const args = match[2].trim(); // matches.push(`${actionWithI}(${args})`); // } const linesArray = text .split('\n') .map((line) => line.trim()) .filter((line) => line.length > 0); return linesArray; } async addStepToFile(aiCommand, filePath) { fs.appendFileSync(filePath, aiCommand + '\n', 'utf-8'); } async writeSteps(input) { if (!aiAssistant.isEnabled) return; if (!aiAssistant.minifiedHtml) throw new Error('No HTML context provided'); const snippets = []; const response = await aiAssistant.createCompletion( defaultPrompts.writeStep(aiAssistant.minifiedHtml, input) ); if (!response) return; snippets.push(...aiAssistant.config.response(response)); debug(snippets[0]); return snippets[0]; } } module.exports = new AiUtils();