UNPKG

less

Version:
211 lines (174 loc) 6.95 kB
'use strict'; const path = require('path'); const util = require('util'); const { chromium } = require('playwright'); const TIMEOUT_MILLISECONDS = 60000; function initMocha(reporter) { console.log = (console => { const log = console.log.bind(console); return (...args) => args.length ? log(...args) : log(''); })(console); function shimMochaInstance(m) { const originalReporter = m.reporter.bind(m); let reporterIsChanged = false; m.reporter = (...args) => { reporterIsChanged = true; originalReporter(...args); }; const run = m.run.bind(m); m.run = () => { const all = [], pending = [], failures = [], passes = []; function error(err) { if (!err) return {}; let res = {}; Object.getOwnPropertyNames(err).forEach(key => res[key] = err[key]); return res; } function clean(test) { return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, err: error(test.err) }; } function result(stats) { return { result: { stats: { tests: all.length, passes: passes.length, pending: pending.length, failures: failures.length, start: stats.start.toISOString(), end: stats.end.toISOString(), duration: stats.duration }, tests: all.map(clean), pending: pending.map(clean), failures: failures.map(clean), passes: passes.map(clean) }, coverage: window.__coverage__ }; } function setResult() { !window.__mochaResult__ && (window.__mochaResult__ = result(this.stats)); } !reporterIsChanged && m.setup({ reporter: Mocha.reporters[reporter] || Mocha.reporters.spec }); const runner = run(() => setTimeout(() => setResult.call(runner), 0)) .on('pass', test => { passes.push(test); all.push(test); }) .on('fail', test => { failures.push(test); all.push(test); }) .on('pending', test => { pending.push(test); all.push(test); }) .on('end', setResult); return runner; }; } function shimMochaProcess(M) { // Mocha needs a process.stdout.write in order to change the cursor position. !M.process && (M.process = {}); !M.process.stdout && (M.process.stdout = {}); M.process.stdout.write = data => console.log('stdout:', data); M.reporters.Base.useColors = true; M.reporters.none = function None(runner) { M.reporters.Base.call(this, runner); }; } Object.defineProperty(window, 'mocha', { get: function() { return undefined }, set: function(m) { shimMochaInstance(m); delete window.mocha; window.mocha = m }, configurable: true }) Object.defineProperty(window, 'Mocha', { get: function() { return undefined }, set: function(m) { shimMochaProcess(m); delete window.Mocha; window.Mocha = m; }, configurable: true }); } function configureViewport(width, height, page) { if (!width && !height) return page; let viewport = page.viewport(); width && (viewport.width = width); height && (viewport.height = height); return page.setViewport(viewport).then(() => page); } function handleConsole(msg) { const args = msg.args() || []; Promise.all(args.map(a => a.jsonValue().catch(error => { console.warn('Failed to retrieve JSON value from argument:', error); return ''; }))) .then(args => { // process stdout stub let isStdout = args[0] === 'stdout:'; isStdout && (args = args.slice(1)); let msg = util.format(...args); !isStdout && msg && (msg += '\n'); process.stdout.write(msg); }); } function prepareUrl(filePath) { if (/^[a-zA-Z]+:\/\//.test(filePath)) { // path is URL return filePath; } // local path let resolvedPath = path.resolve(filePath); return `file://${resolvedPath}`; } exports.runner = function ({ file, reporter, timeout, width, height, args, executablePath, visible, polling }) { return new Promise(resolve => { // validate options if (!file) { throw new Error('Test page path is required.'); } args = [].concat(args || []).map(arg => '--' + arg); !timeout && (timeout = TIMEOUT_MILLISECONDS); /^\d+$/.test(polling) && (polling = parseInt(polling)); const url = prepareUrl(file); const options = { ignoreHTTPSErrors: true, headless: !visible, executablePath, args }; const result = chromium.launch(options) .then(browser => browser.newContext() .then(context => context.newPage() .then(page => { if (width || height) { return page.setViewportSize({ width: width || 800, height: height || 600 }).then(() => page); } return page; }) .then(page => { page.on('console', handleConsole); page.on('dialog', dialog => dialog.dismiss()); page.on('pageerror', err => console.error(err)); return page.addInitScript(initMocha, reporter) .then(() => page.goto(url)) .then(() => page.waitForFunction(() => window.__mochaResult__, { timeout, polling })) .then(() => page.evaluate(() => window.__mochaResult__)) .then(result => { if (!result) { throw new Error('Mocha results not found after waiting. The tests may not have run correctly.'); } // Close browser before resolving result return browser.close().then(() => result); }); }) ) ); resolve(result); }); };