@kronoslive/codeceptjs
Version:
Supercharged End 2 End Testing Framework for NodeJS
155 lines (134 loc) • 4.61 kB
JavaScript
const debug = require('debug')('codeceptjs:plugin:puppeteerCoverage');
const fs = require('fs');
const path = require('path');
const Container = require('../container');
const recorder = require('../recorder');
const event = require('../event');
const output = require('../output');
const { clearString } = require('../utils');
const defaultConfig = {
coverageDir: 'output/coverage',
uniqueFileName: true,
};
const supportedHelpers = ['Puppeteer'];
function buildFileName(test, uniqueFileName) {
let fileName = clearString(test.title);
// This prevent data driven to be included in the failed screenshot file name
if (fileName.indexOf('{') !== -1) {
fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim();
}
if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') {
fileName = clearString(`${test.title}_${test.ctx.test.title}`);
}
if (uniqueFileName) {
const uuid = test.uuid
|| test.ctx.test.uuid
|| Math.floor(new Date().getTime() / 1000);
fileName = `${fileName.substring(0, 10)}_${uuid}.coverage.json`;
} else {
fileName = `${fileName}.coverage.json`;
}
return fileName;
}
/**
* Dumps puppeteers code coverage after every test.
*
* #### Configuration
*
* Configuration can either be taken from a corresponding helper (deprecated) or a from plugin config (recommended).
*
* ```js
* plugins: {
* puppeteerCoverage: {
* enabled: true
* }
* }
* ```
*
* Possible config options:
*
* * `coverageDir`: directory to dump coverage files
* * `uniqueFileName`: generate a unique filename by adding uuid
*
* First of all, your mileage may vary!
*
* To work, you need the client javascript code to be NOT uglified. They need to be built in "development" mode.
* And the end of your tests, you'll get a directory full of coverage per test run. Now what?
* You'll need to convert the coverage code to something istanbul can read. Good news is someone wrote the code
* for you (see puppeteer-to-istanbul link below). Then using istanbul you need to combine the converted
* coverage and create a report. Good luck!
*
* Links:
* * https://github.com/GoogleChrome/puppeteer/blob/v1.12.2/docs/api.md#class-coverage
* * https://github.com/istanbuljs/puppeteer-to-istanbul
* * https://github.com/gotwarlost/istanbul
*/
module.exports = function (config) {
const helpers = Container.helpers();
let coverageRunning = false;
let helper;
for (const helperName of supportedHelpers) {
if (Object.keys(helpers).indexOf(helperName) > -1) {
helper = helpers[helperName];
}
}
if (!helper) {
console.error('Coverage is only supported in Puppeteer');
return; // no helpers for screenshot
}
const options = Object.assign(defaultConfig, helper.options, config);
event.dispatcher.on(event.all.before, async () => {
output.debug('*** Collecting coverage for tests ****');
});
// Hack! we're going to try to "start" coverage before each step because this is
// when the browser is already up and is ready to start coverage.
event.dispatcher.on(event.step.before, async () => {
recorder.add(
'starting coverage',
async () => {
try {
if (!coverageRunning) {
debug('--> starting coverage <--');
coverageRunning = true;
await helper.page.coverage.startJSCoverage();
}
} catch (err) {
console.error(err);
}
},
true,
);
});
// Save puppeteer coverage data after every test run
event.dispatcher.on(event.test.after, async (test) => {
recorder.add(
'saving coverage',
async () => {
try {
if (coverageRunning) {
debug('--> stopping coverage <--');
coverageRunning = false;
const coverage = await helper.page.coverage.stopJSCoverage();
const coverageDir = path.resolve(
process.cwd(),
options.coverageDir,
);
// Checking if coverageDir already exists, if not, create new one
if (!fs.existsSync(coverageDir)) {
fs.mkdirSync(coverageDir, { recursive: true });
}
const coveragePath = path.resolve(
coverageDir,
buildFileName(test, options.uniqueFileName),
);
output.print(`writing ${coveragePath}`);
fs.writeFileSync(coveragePath, JSON.stringify(coverage));
}
} catch (err) {
console.error(err);
}
},
true,
);
});
};