const express = require("express"); const fs = require("fs"); const tap = require("tap"); const webdriver = require("selenium-webdriver"); const screenshot = require("./screenshooter"); const BlinkDiff = require("blink-diff"); const path = require("path"); // Command line arguments examples: // node test.js win ie11,chrome // node test.js macos safari,chrome,firefox const environmentId = process.argv[2] || ""; const enabledBrowsers = (process.argv[3] || "").split(/[,;]/g).filter(name => name); if (!enabledBrowsers.length) { throw new Error("Expected browser names"); } const screenshotDir = process.env.BROWSER_SCREENSHOT_DIR || path.join(__dirname, "artifacts/screenshots"); const diffDir = process.env.BROWSER_DIFF_DIR || path.join(__dirname, "artifacts/diffs"); const expectedDir = process.env.BROWSER_EXPECTED_DIR || path.join(__dirname, "expected"); // fs.mkdirSync(_ , { recursive: true }) did not work on GitHub Actions using Node v12.18.2 (Windows and macOS). // Worked fine locally however. Replacing it with a custom recursive implementation. // Ignored GitHub issue for tracking any status: // https://github.com/nodejs/node/issues/27293 function mkdirRecursive(dirPath) { if (!fs.existsSync(dirPath)) { const parent = path.dirname(dirPath) if (parent && parent !== dirPath) { mkdirRecursive(parent); } fs.mkdirSync(dirPath); } } mkdirRecursive(screenshotDir); mkdirRecursive(diffDir); const BROWSER_DEFINITIONS = [ { name: "ie11", uaCompatible: "IE=Edge", capabilities: { "browserName": webdriver.Browser.INTERNET_EXPLORER, "ie.ensureCleanSession": true, }, }, { name: "ie10", uaCompatible: "IE=10", capabilities: { "browserName": webdriver.Browser.INTERNET_EXPLORER, "ie.ensureCleanSession": true, }, }, { name: "ie9", uaCompatible: "IE=9", capabilities: { "browserName": webdriver.Browser.INTERNET_EXPLORER, "ie.ensureCleanSession": true, }, }, { name: "firefox", capabilities: { "browserName": webdriver.Browser.FIREFOX, }, }, { name: "chrome", capabilities: { "browserName": webdriver.Browser.CHROME, }, }, { name: "edge", capabilities: { "browserName": webdriver.Browser.EDGE, "ms:edgeChromium": true, }, }, { name: "safari", capabilities: { "browserName": webdriver.Browser.SAFARI, }, }, ] async function serve(root, options, asyncCallback) { const app = express(); app.use(express.static(root, options)); await new Promise((resolve, reject) => { const listener = app.listen(async () => { try { await asyncCallback(listener); resolve(); } catch (e) { reject(e); } finally { listener.close(); } }); }); } async function testBrowser(browserName) { const browser = BROWSER_DEFINITIONS.find(x => x.name === browserName); await tap.test(browserName, async t => { if (!browser) { t.fail(`Could not find a browser with the name ${browserName}.`); return; } await serve( path.join(__dirname, "../../"), { "index": ["index.html"], setHeaders: resp => { // Prevent stale files resp.setHeader("Cache-Control", "no-store"); if (browser.uaCompatible) { resp.setHeader("X-UA-Compatible", browser.uaCompatible); } } }, async listener => { const url = "http://localhost:" + listener.address().port + "/e2e/browser/assets/"; console.log(`Screenshot in ${browserName}`); console.log(url); const driver = await new webdriver.Builder() .withCapabilities(browser.capabilities) .build(); await driver.manage().window().setRect({ width: 1000, height: 2000 }); const documentInitialised = () => driver.executeScript("return true"); try { await driver.get(url); await driver.wait(() => documentInitialised(), 10000); await driver.sleep(2500); const screenshotBuffer = await screenshot(driver); fs.writeFileSync(path.join(screenshotDir, `${environmentId}-${browserName}.png`), screenshotBuffer); } finally { await driver.quit(); } var diff = new BlinkDiff({ imageAPath: path.join(expectedDir, `${environmentId}-${browserName}.png`), imageBPath: path.join(screenshotDir, `${environmentId}-${browserName}.png`), thresholdType: BlinkDiff.THRESHOLD_PIXEL, threshold: 1000, imageOutputPath: path.join(diffDir, `${environmentId}-${browserName}.png`), // Ignore test metadata area containing browser versions etc. blockOut: [{ x: 0, y: 0, width: 20000, height: 100 }], }); const diffResult = await diff.runWithPromise(); t.ok(diff.hasPassed(diffResult.code), `Found ${diffResult.differences} differences.`); }, ); }); } async function testBrowsers(enabledBrowsers) { for (var i = 0; i < enabledBrowsers.length; i++) { await testBrowser(enabledBrowsers[i]); } } testBrowsers(enabledBrowsers);