Skip to content

Commit

Permalink
feat: support cypress-parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
LironEr committed Aug 5, 2023
1 parent 208863c commit aef067d
Show file tree
Hide file tree
Showing 20 changed files with 327 additions and 18 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ Add extra information to the report manually by using `cy.addTestContext()` as s
3. [With `mochawesome-report-generator` flags](examples/mochawesome-flags)
4. [Change default screenshots folder in `cypress.json`](examples/screenshots-folder)
5. [Using `cypress-mochawesome-reporter` with typescript](examples/simple-typescript)
6. [Using `cypress-mochawesome-reporter` with `cypress-parallel`](examples/cypress-parallel)

Run `npm i` in root directory then:

Expand Down
43 changes: 43 additions & 0 deletions cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env node

const { Command } = require('commander');
const fse = require('fs-extra');
const { setSimpleConfig } = require('./lib/config');
const { log, initDebugLog, debugLog } = require('./lib/logger');
const generateReport = require('./lib/generateReport');
const consts = require('./lib/consts');
const packageJson = require('./package.json');

(async () => {
const program = new Command();
program
.name('generate-mochawesome-report')
.description('CLI merge and generate Cypress Mochawesome report')
.version(packageJson.version)
.option('-c, --config <path>', 'should be the same as "configOutput" reporter option', consts.defaultConfigOutput)
.option('-o, --output <path>', 'report output folder')
.option('--debug', 'print debug logs', false);

program.parse();
const options = program.opts();

initDebugLog(options.debug === true);

debugLog(`cwd: ${process.cwd()}`);

log(`read config from ${options.config}`);

const config = await fse.readJson(options.config);
debugLog(`config: ${JSON.stringify(config)}`);

if (options.output) {
debugLog(`override output with: ${options.output}`);
config.outputDir = options.output;
config.reporterOptions.reportDir = options.output;
}

setSimpleConfig(config);

log('generate report');
await generateReport();
})();
3 changes: 2 additions & 1 deletion cypress/e2e/reportOutput.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ describe('Report output', () => {
'mochawesome-flags',
'screenshots-folder',
'simple-typescript',
'cypress-parallel',
].forEach((folder) => {
describe(`${folder} folder`, () => {
beforeEach(() => {
Expand Down Expand Up @@ -57,7 +58,7 @@ describe('Report output', () => {
});

describe('Video output', () => {
['simple', 'screenshots-folder', 'simple-typescript'].forEach((folder) => {
['simple', 'screenshots-folder', 'simple-typescript', 'cypress-parallel'].forEach((folder) => {
describe(`Validate video exists in ${folder} folder`, () => {
beforeEach(() => {
cy.visit(`examples/${folder}/cypress/reports/html/index.html`);
Expand Down
7 changes: 7 additions & 0 deletions examples/cypress-parallel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
cypress/reports
cypress/screenshots
cypress/videos
runner-results
multi-reporter-config.json
.tmp
50 changes: 50 additions & 0 deletions examples/cypress-parallel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Setup with `cypress-parallel`

1. Follow the steps in the [main README](../../README.md) to setup the reporter.

1. Change `cypress.config.js` to only use `beforeRunHook`, otherwise the reporter will try to create multiple HTML reporters without all the tests.

```js
const { defineConfig } = require('cypress');
const { beforeRunHook } = require('cypress-mochawesome-reporter/lib');

module.exports = defineConfig({
video: true,
retries: 0,
e2e: {
setupNodeEvents(on, config) {
on('before:run', async (details) => {
await beforeRunHook(details);
});
},
},
});
```

1. How to run:

1. Because cypress parallel runs in threads you will need to manually clear the report output folder before run.

1. Set `cypress-parallel` reporter to `cypress-mochawesome-reporter`

```sh
cypress-parallel -s cy:run -t 2 -d 'cypress/e2e/**/*.cy.js' -r 'cypress-mochawesome-reporter' -o 'cypressParallel=true'"
```
1. Create report after test run:
```sh
npx generate-mochawesome-report
```
Example scripts section in `package.json`:
```json
"scripts": {
"cy:run": "cypress run",
"cy:run:parallel": "cypress-parallel -s cy:run -t 2 -d 'cypress/e2e/**/*.cy.js' -r 'cypress-mochawesome-reporter' -o 'cypressParallel=true'",
"clean": "rimraf cypress/reports",
"generate-report": "generate-mochawesome-report",
"test": "npm run clean && npm run cy:run:parallel || true && npm run generate-report"
},
```
14 changes: 14 additions & 0 deletions examples/cypress-parallel/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { defineConfig } = require('cypress');
const { beforeRunHook } = require('cypress-mochawesome-reporter/lib');

module.exports = defineConfig({
video: true,
retries: 0,
e2e: {
setupNodeEvents(on, config) {
on('before:run', async (details) => {
await beforeRunHook(details);
});
},
},
});
27 changes: 27 additions & 0 deletions examples/cypress-parallel/cypress/e2e/sub-dir/test1.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
it('fail test #tag1', () => {
cy.visit('site/index.html');

cy.screenshot('custom-name');

cy.get('#todo-list li').should('have.length', 10);
});

describe('Test 1 #tag2', () => {
it('default todos exists', () => {
cy.visit('site/index.html');

cy.get('#todo-list li').should('have.length', 4);

cy.screenshot();
});

describe('hierarchy', () => {
it('fail test hierarchy #tag3', () => {
cy.visit('site/index.html');

cy.screenshot('custom-name2');

cy.get('#todo-list li').should('have.length', 10);
});
});
});
19 changes: 19 additions & 0 deletions examples/cypress-parallel/cypress/e2e/test2.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
describe('Test 2', () => {
it('todo exists', () => {
cy.visit('site/index.html');

cy.get('#todo-list').should('be.visible');
});

it('add context to mochawesome report', () => {
cy.visit('site/index.html');

cy.get('#todo-list > li').then(($liElements) => {
cy.addTestContext(`There were ${$liElements.length.toString()} items found in the todo-list`);
});
});

it.skip('skipped test', () => {
cy.visit('site/index.html');
});
});
11 changes: 11 additions & 0 deletions examples/cypress-parallel/cypress/e2e/test3.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
describe('Test 3 - fail before hook', () => {
before(() => {
cy.visit('site/index.html');

cy.get('#todo-list li').should('have.length', 10);
});

it('before hook fail', () => {
cy.visit('site/index.html');
});
});
15 changes: 15 additions & 0 deletions examples/cypress-parallel/cypress/e2e/test4.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
describe('Test 4 - fail beforeEach hook', () => {
beforeEach(() => {
cy.visit('site/index.html');

cy.get('#todo-list li').should('have.length', 10);
});

it('beforeEach hook fail 1', () => {
cy.visit('site/index.html');
});

it('beforeEach hook fail 2', () => {
cy.visit('site/index.html');
});
});
Empty file.
22 changes: 22 additions & 0 deletions examples/cypress-parallel/cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands';

import 'cypress-mochawesome-reporter/register';

// Alternatively you can use CommonJS syntax:
// require('./commands')
18 changes: 18 additions & 0 deletions examples/cypress-parallel/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@example/simple",
"version": "1.0.0",
"scripts": {
"cy:run": "cypress run",
"cy:run:parallel": "cypress-parallel -s cy:run -t 2 -d 'cypress/e2e/**/*.cy.js' -r 'cypress-mochawesome-reporter' -o 'cypressParallel=true'",
"clean": "rimraf cypress/reports",
"generate-report": "generate-mochawesome-report",
"test": "npm run clean && npm run cy:run:parallel || true && npm run generate-report"
},
"license": "MIT",
"devDependencies": {
"cypress": "^12.3.0",
"cypress-mochawesome-reporter": "../../",
"cypress-parallel": "^0.13.0",
"rimraf": "^5.0.1"
}
}
11 changes: 11 additions & 0 deletions examples/cypress-parallel/site/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<html>
<body>
<h1>TODO list</h1>
<ul id="todo-list">
<li>todo1</li>
<li>todo2</li>
<li>todo3</li>
<li>todo4</li>
</ul>
</body>
</html>
39 changes: 37 additions & 2 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ function getConfig() {
return _config;
}

module.exports = { setConfig, getConfig };
function setSimpleConfig(config) {
_config = config;
}

module.exports = { setConfig, getConfig, setSimpleConfig };

async function extractConfigFileOptions(configFile) {
const configFilePath = path.resolve(configFile);
Expand Down Expand Up @@ -75,11 +79,42 @@ async function getSimpleCypressConfig(config) {

const jsonDir = path.join(reporterOptions.reportDir, '/.jsons');

if (reporterOptions.cypressParallel === 'true') {
// cypress-parallel is passing booleans as strings, covert them to booleans
for (const key in reporterOptions) {
const value = reporterOptions[key];

if (value === 'true') {
reporterOptions[key] = true;
} else if (value === 'false') {
reporterOptions[key] = false;
}
}

// because we run in parallel, we dont want to overwrite the JSONs from other threads
reporterOptions.overwrite = false;

reporterOptions.configOutput = reporterOptions.configOutput || true;
reporterOptions.removeJsonsFolderAfterMerge = false;
}

let { configOutput, removeJsonsFolderAfterMerge, ...restReporterOptions } = reporterOptions;

if (configOutput !== undefined && configOutput !== false) {
configOutput = typeof configOutput === 'string' ? configOutput : consts.defaultConfigOutput;
}

if (removeJsonsFolderAfterMerge === undefined) {
removeJsonsFolderAfterMerge = true;
}

return {
jsonDir,
reporterOptions,
reporterOptions: restReporterOptions,
screenshotsDir: config.screenshotsFolder,
videosFolder: config.videosFolder,
outputDir: reporterOptions.reportDir,
configOutput,
removeJsonsFolderAfterMerge,
};
}
3 changes: 2 additions & 1 deletion lib/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ const path = require('path');

module.exports = {
defaultHtmlOutputFolder: 'cypress/reports/html',
}
defaultConfigOutput: 'cypress/.tmp/cypressMochawesomeReporterConfig.json',
};
8 changes: 5 additions & 3 deletions lib/generateReport.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ async function copyMediaDir(inputDir, outputDir) {
const isExists = fse.existsSync(inputDir);

if (isExists) {

if (inputDir !== outputDir) {
log(`Copy media folder from "${inputDir}" to "${outputDir}"`);

Expand All @@ -50,7 +49,8 @@ async function copyMediaDir(inputDir, outputDir) {
async function generateReport() {
log('Start generate report process');

const { outputDir, reporterOptions, screenshotsDir, videosFolder, jsonDir } = getConfig();
const { outputDir, reporterOptions, screenshotsDir, videosFolder, jsonDir, removeJsonsFolderAfterMerge } =
getConfig();

const actions = [mergeAndCreate(jsonDir, screenshotsDir, reporterOptions)];

Expand All @@ -66,7 +66,9 @@ async function generateReport() {
log('HTML report successfully created!');
log(htmlPath);

await fse.remove(jsonDir);
if (removeJsonsFolderAfterMerge) {
await fse.remove(jsonDir);
}
}

module.exports = generateReport;
13 changes: 12 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const fse = require('fs-extra');
const path = require('path');
const { setConfig } = require('./config');
const { log, debugLog } = require('./logger');
const generateReport = require('./generateReport');
Expand All @@ -11,7 +12,17 @@ async function beforeRunHook({ config }) {
return;
}

const { outputDir, jsonDir, reporterOptions } = await setConfig(config);
const simpleConfig = await setConfig(config);
const { outputDir, jsonDir, reporterOptions, configOutput } = simpleConfig;

if (configOutput) {
debugLog(`Write simple config to ${configOutput}`);
// create folder if not exist
await fse.mkdirp(path.dirname(configOutput));

// write simple config to file
await fse.writeJSON(configOutput, simpleConfig, { spaces: 2 });
}

// Only if overwrite is set to false delete only .jsons folder and keep the html files
// By default overwrite is set to undefined (which means true by mochawesome-report-generator)
Expand Down
Loading

0 comments on commit aef067d

Please sign in to comment.