UNPKG

@applitools/eyes-playwright

Version:
217 lines (215 loc) 9.73 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = __importStar(require("fs")); const path_1 = __importDefault(require("path")); const prompts_1 = require("@inquirer/prompts"); const yargs_1 = __importDefault(require("yargs/yargs")); const utils = __importStar(require("@applitools/utils")); const chalk_1 = __importDefault(require("chalk")); const { hideBin } = require('yargs/helpers'); (0, yargs_1.default)(hideBin(process.argv)) .command({ command: 'run-example', handler: handleError(runExample), }) .command({ command: '*', builder: yargs => { const args = yargs.options({ apiKey: { describe: "Your Applitools Team's API key (here's how to obtain it: https://applitools.com/docs/topics/overview/obtain-api-key.html)", type: 'string', }, serverUrl: { describe: 'Your Eyes dedicated cloud server URL', type: 'string' }, }); return args; }, handler: handleError(init), }) .help() .parse(); function handleError(asyncFunc) { return async (...args) => asyncFunc(...args).catch((err) => { if (err.name === 'ExitPromptError') { log('See you next time!'); } else { error(`Error while setting up Eyes: ${err.message}`); } process.exit(1); }); } async function init(args) { log(chalk_1.default.yellow('Setting up Eyes-Playwright fixture and reporter for your project:')); let wroteGray = false; const playwrightConfig = await fs_1.promises.readFile('playwright.config.ts', 'utf-8'); await updatePlaywrightConfig(); await createExampleTest(); await updateTestFiles(); printPostlude(); async function updatePlaywrightConfig() { var _a, _b; if (!/EyesFixture/.test(playwrightConfig)) { const apiKey = (_a = args.apiKey) !== null && _a !== void 0 ? _a : (await (0, prompts_1.input)({ message: 'Enter your API key (https://applitools.com/docs/topics/overview/obtain-api-key.html):', })); const serverUrl = (_b = args.serverUrl) !== null && _b !== void 0 ? _b : (await (0, prompts_1.input)({ message: 'Enter your Eyes server URL (the default is https://eyes.applitools.com):' })); const apiKeyStr = apiKey ? `apiKey: '${apiKey}'` : `// apiKey: ''`; const serverUrlStr = serverUrl ? `serverUrl: '${serverUrl}'` : `// serverUrl: 'https://eyes.applitools.com'`; const newPlaywrightConfig = "import { EyesFixture } from '@applitools/eyes-playwright/fixture';\n" + playwrightConfig .replace(/export default defineConfig\({/, 'export default defineConfig<EyesFixture>({') .replace(/(use: {)/, `$1 /* Configuration for Eyes VisualAI */ eyesConfig: { /* The following and other configuration parameters are documented at: https://applitools.com/tutorials/playwright/api/overview */ ${apiKeyStr}, // alternatively, set this via environment variable APPLITOOLS_API_KEY ${serverUrlStr}, // failTestsOnDiff: false, // appName: 'My App', // matchLevel: 'Strict', // batch: { name: 'My Batch' }, // proxy: {url: 'http://127.0.0.1:8888'}, // stitchMode: 'CSS', // matchTimeout: 0, // waitBeforeScreenshots: 50, // saveNewTests: true, }, `) .replace(/reporter: 'html'/, "reporter: '@applitools/eyes-playwright/reporter'"); await fs_1.promises.writeFile('playwright.config.ts', newPlaywrightConfig); log(''); log(chalk_1.default.gray('Updating playwright.config.ts with Eyes configuration')); log(chalk_1.default.gray('Updating playwright.config.ts with Eyes HTML reporter')); wroteGray = true; } } async function createExampleTest() { if (!fs_1.default.existsSync('./eyes-examples')) { if (!wroteGray) { log(''); wroteGray = true; } log(chalk_1.default.gray('Creating eyes-examples folder')); await fs_1.promises.mkdir('./eyes-examples'); await fs_1.promises.copyFile(path_1.default.join(__dirname, 'example', 'playwright-website.spec.ts'), './eyes-examples/playwright-website.spec.ts'); } } async function updateTestFiles() { const testDirMatch = playwrightConfig.match(/testDir\s*:\s*['"]([^'"]+)['"]/); if (testDirMatch) { const testDir = testDirMatch[1]; await forEachFile(path_1.default.resolve(testDir), async (filePath) => { const testContent = await fs_1.promises.readFile(filePath, 'utf-8'); await fs_1.promises.writeFile(filePath, testContent.replace(/import { test, expect } from '@playwright\/test'/, `import { test, expect } from '@applitools/eyes-playwright/fixture'`)); }); } else { log(chalk_1.default.yellow('Cannot automatically set up "import {test, expect} from \'@applitools/eyes-playwright/fixture\'" - Could not find testDir from configruation.')); } } function printPostlude() { log(''); if (wroteGray) { log(chalk_1.default.green('✔ Success!'), chalk_1.default.bold('Eyes-Playwright fixture and reporter are now set up!')); } else { log(chalk_1.default.cyan('✔ Good news!'), chalk_1.default.bold('Eyes-Playwright is already properly configured!')); } log(''); log('Try out the example test by running the following:'); log(''); log(chalk_1.default.cyan(' npx eyes-setup run-example')); log(''); log('👀 Tests that are already performing visual tests with expect(page).toHaveScreenshot() now automatically use Eyes'); log(''); log("👀 The Eyes HTML reporter extends Playwright's HTML reporter with improved side by side visual comparison"); log(''); log('Visit https://applitools.com/tutorials/playwright for more information.'); } } async function runExample() { const playwrightTmpConfigPath = './eyes-examples/playwright.tmp.config.ts'; const playwrightTmpExists = fs_1.default.existsSync(playwrightTmpConfigPath); await writeTmpPlaywrightConfig(); await runPlaywrightCommand(); await cleanupTmpPlaywrightConfig(); async function writeTmpPlaywrightConfig() { if (!playwrightTmpExists) { const playwrighConfig = await fs_1.promises.readFile('./playwright.config.ts', 'utf-8'); const apikeyMatch = playwrighConfig.match(/apiKey: ([^,]+)/); const apiKey = apikeyMatch ? apikeyMatch[1] : undefined; const serverUrlMatch = playwrighConfig.match(/serverUrl: ([^,]+)/); const serverUrl = serverUrlMatch ? serverUrlMatch[1] : undefined; const playwrightTmpConfig = `import { defineConfig, devices } from '@playwright/test'; import { EyesFixture } from '@applitools/eyes-playwright/fixture'; export default defineConfig<EyesFixture>({ testDir: '.', outputDir: './test-results', reporter: [['@applitools/eyes-playwright/reporter', {open: 'always', outputFolder: './eyes-playwright-report'}]], use: { eyesConfig: { apiKey: ${apiKey !== null && apiKey !== void 0 ? apiKey : ''}, serverUrl: ${serverUrl !== null && serverUrl !== void 0 ? serverUrl : ''} } } })`; await fs_1.promises.writeFile(playwrightTmpConfigPath, playwrightTmpConfig); } } async function cleanupTmpPlaywrightConfig() { if (!playwrightTmpExists) { await fs_1.promises.unlink(playwrightTmpConfigPath); } } async function runPlaywrightCommand() { await utils.process.sh(`npx playwright test --config ${playwrightTmpConfigPath}`, { spawnOptions: { stdio: 'inherit' }, }); } } function log(...args) { console.log(...args); // eslint-disable-line no-console } function error(...args) { console.error(...args); // eslint-disable-line no-console } async function forEachFile(folderPath, func) { const files = await fs_1.promises.readdir(folderPath); for (const file of files) { const filePath = path_1.default.join(folderPath, file); if ((await fs_1.promises.stat(filePath)).isDirectory()) { await forEachFile(filePath, func); } else { await func(filePath); } } }