@applitools/eyes-playwright
Version:
Applitools Eyes SDK for Playwright
217 lines (215 loc) • 9.73 kB
JavaScript
;
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);
}
}
}