UNPKG

cypress-native-coverage

Version:

156 lines 6.72 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.nativeCoveragePlugin = void 0; /// <reference types="cypress" /> const chrome_remote_interface_1 = __importDefault(require("chrome-remote-interface")); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const v8_to_istanbul_1 = __importDefault(require("v8-to-istanbul")); const istanbul_lib_coverage_1 = __importDefault(require("istanbul-lib-coverage")); const istanbul_lib_report_1 = __importDefault(require("istanbul-lib-report")); const istanbul_reports_1 = __importDefault(require("istanbul-reports")); const picomatch = require('picomatch'); const debug = require('debug')('cypress-native-coverage'); function nativeCoveragePlugin(on, options = {}) { if (typeof options !== 'object') { throw new Error('cypress-native-coverage plugin options must be an object'); } const ELECTRON_DEBUG_PORT = /remote-debugging-port\s*=\s*(\d+)/.exec(process.env.ELECTRON_EXTRA_LAUNCH_ARGS || ''); let { basedir = process.cwd(), outdir = 'build', port = ELECTRON_DEBUG_PORT ? parseInt(ELECTRON_DEBUG_PORT[1]) : 8500, include, exclude, reports = [], merge = false } = options; const { readFile, writeFile } = fs_1.default.promises; debug(`basedir: ${basedir}`); const OUTDIR = path_1.default.resolve(basedir, outdir); const NYC_OUTPUT = path_1.default.resolve(basedir, '.nyc_output'); const NYC_OUTFILE = path_1.default.join(NYC_OUTPUT, `out.json`); try { fs_1.default.mkdirSync(NYC_OUTPUT, { recursive: true }); } catch (e) { } let cdp = null; let attempts = 0; let coverageMap; let merged; async function startCoverage() { try { cdp = await (0, chrome_remote_interface_1.default)({ port }); cdp.on('disconnect', () => { debug('disconnected from chrome debugging protocol'); cdp = null; }); debug(`connected to chrome debugging protocol on port ${port}`); } catch (ignored) { if (++attempts < 10) { setTimeout(startCoverage, 50); } else { console.error(`unable to connect to chrome debugging protocol on port ${port}`); } return; } coverageMap = istanbul_lib_coverage_1.default.createCoverageMap(); if (merge) merged = readFile(NYC_OUTFILE, 'utf8') .then(text => { const data = JSON.parse(text); coverageMap.merge(data); debug('merged existing coverage map'); }) .catch(() => { console.error('unable to merge', NYC_OUTFILE); }); await cdp.Profiler.enable(); await cdp.Profiler.startPreciseCoverage({ detailed: true, callCount: true, allowTriggeredUpdates: true }); debug('started precise coverage'); } const includes = include && picomatch(include); const excludes = exclude && picomatch(exclude); const isMatch = include ? exclude ? (path) => includes(path) && !excludes(path) : includes : exclude ? excludes : () => false; async function takeCoverage() { const coverage = await cdp.Profiler.takePreciseCoverage(); debug('taken precise coverage'); for (const { url, functions } of coverage.result) { if (url) try { const { pathname } = new URL(url); if (isMatch(pathname)) { debug('matched', pathname); const converter = (0, v8_to_istanbul_1.default)(path_1.default.join(OUTDIR, pathname), 0, undefined, pathname => { const relative = path_1.default.relative(basedir, pathname).replace(/\\/g, '/'); const accept = relative.startsWith('src') || relative.startsWith('../../src'); return !accept; }); await converter.load(); converter.applyCoverage(functions); coverageMap.merge(converter.toIstanbul()); } } catch (ignored) { debug(`failed to collect coverage result for: ${url}`); } } } async function stopCoverage() { await cdp.Profiler.stopPreciseCoverage(); debug('stopped precise coverage'); } async function writeCoverageMap() { await writeFile(NYC_OUTFILE, JSON.stringify(coverageMap.toJSON())); } async function writeReports() { const context = istanbul_lib_report_1.default.createContext({ dir: path_1.default.resolve(basedir, 'coverage'), coverageMap }); for (const reporter of reports) { istanbul_reports_1.default.create(reporter, { skipEmpty: false }).execute(context); } } on('before:browser:launch', (browser, launchOptions) => { if (browser.name === 'chrome' || browser.name === 'edge' || browser.name === 'electron') { let rdpArg = launchOptions.args.find(arg => arg.startsWith('--remote-debugging-port')); if (!rdpArg) { // Too bad this code doesn't work with electron, you have to rely to the env property: // ELECTRON_EXTRA_LAUNCH_ARGS=--remote-debugging-port=???? rdpArg = `--remote-debugging-port=${port}`; launchOptions.args.push(rdpArg); } if (!options.port) { port = parseInt(rdpArg.split('=')[1]); } setTimeout(startCoverage, 50); } else { console.error(`native coverage is not available in '${browser.name}'`); } return launchOptions; }); on('after:spec', async (spec) => { if (cdp) { await merged; await takeCoverage(); await stopCoverage(); } }); on('after:run', () => Promise.all([ writeCoverageMap(), writeReports() ])); } exports.nativeCoveragePlugin = nativeCoveragePlugin; exports.default = nativeCoveragePlugin; //# sourceMappingURL=index.js.map