2

I've just started using mochawesome with Cypress (9.7). Our test structure is basically a number of spec files, each following something like the following format:

describe('(A): description of this spec', () => {
  describe ('(B): description of test abc', () => {
    before(() => {
      // do specific set up bits for this test
    })
    it('(C): runs test abc', () => {
      // do actual test stuff
    })
  })
})

Where within each spec file there would be a single 'A' describe block, but there can be many 'B' level blocks (each with a single 'C') - done this way because the before block for each 'C' is always different - I couldn't use a beforeEach.

When I run my various spec files, each structured similarly to the above, the mochaewsome output is mostly correct - I get a collapsible block for each spec file at level 'A', each with multiple collapsible blocks at level B, each with test info as expected at level C.

But... The circular charts are only displayed at level B. What I was hoping, was that it might be possible to have aggregated charts at level A, and a further aggregated chart for all the level A blocks.

Not sure I've explained this brilliantly(!), but hopefully someone understands, and can offer a suggestion?!

Fody
  • 23,754
  • 3
  • 20
  • 37
Steve H
  • 280
  • 1
  • 2
  • 11

1 Answers1

4

In cypress-mochawesome-reporter there's an alternative setup using on('after:run') which can perform the aggregation.

In Cypress v9.7.0

// cypress/plugins/index.js

const { beforeRunHook, afterRunHook } = require('cypress-mochawesome-reporter/lib');
const { aggregateResults } = require('./aggregate-mochawesome-report-chart');

module.exports = (on, config) => {
  on('before:run', async (details) => {
    await beforeRunHook(details);
  });

  on('after:run', async () => {
    aggregateResults(config)
    await afterRunHook();
  });
};

In Cypress v10+

// cypress.config.js

const { defineConfig } = require('cypress');
const { beforeRunHook, afterRunHook } = require('cypress-mochawesome-reporter/lib');
const { aggregateResults } = require('./aggregate-mochawesome-report-chart');

module.exports = defineConfig({
  reporter: 'cypress-mochawesome-reporter',
  video: false,
  retries: 1,
  reporterOptions: {
    reportDir: 'test-report',
    charts: true,
    reportPageTitle: 'custom-title',
    embeddedScreenshots: true,
    inlineAssets: false,
    saveAllAttempts: false,
    saveJson: true
  },
  e2e: {
    setupNodeEvents(on, config) {
      on('before:run', async (details) => {
        await beforeRunHook(details);
      });

      on('after:run', async () => {
        aggregateResults(config)
        await afterRunHook();
      });
    },
  },
});

The module to do the aggregation is

// aggregate-mochawesome-reporter-chart.js

const path = require('path');
const fs = require('fs-extra')

function aggregateResults(config) {
  const jsonPath = path.join(config.reporterOptions.reportDir , '/.jsons', '\mochawesome.json');
  const report = fs.readJsonSync(jsonPath)
  const topSuite = report.results[0].suites[0]
  aggregate(topSuite)
  fs.writeJsonSync(jsonPath, report)
}
function aggregate(suite, level = 0) {
  const childSuites = suite.suites.map(child => aggregate(child, ++level))
  suite.passes = suite.passes.concat(childSuites.map(child => child.passes)).flat()
  suite.failures = suite.failures.concat(childSuites.map(child => child.failures)).flat()
  suite.pending = suite.pending.concat(childSuites.map(child => child.pending)).flat()
  suite.skipped = suite.skipped.concat(childSuites.map(child => child.skipped)).flat()
  if (!suite.tests.length && suite.suites[0].tests.length) {
    // trigger chart when to describe has no tests
    suite.tests = [               
      {
        "title": "Aggregate of tests",
        "duration": 20,
        "pass": true,
        "context": null,
        "err": {},
        "uuid": "0",
        "parentUUID": suite.uuid,
      },
    ]
  }
  return suite
}

module.exports = {
  aggregateResults
}

The function aggregate() recursively loops down through child suites and adds the test results to the parent.

json files

Note the json file is different at the point where afterRunHook runs and at the end of the test run.

If you have the option saveJson: true set, you will get a final json file in the report directory called index.json.

At the afterRunHook stage the file is mochawesome.json.

Before aggregation

After aggregation

Fody
  • 23,754
  • 3
  • 20
  • 37
  • Thanks for that Fody.... Sadly, it still isn't working for me. However, I notice in your before/after screenshots, even your 'before' functionality is different to me - at the "(A)" level you DO get a chart (albeit an incorrect one of course!)... I'm not getting a chart at that level at all, even with/without your code suggestions above. Can I ask what version of cypress-mochawesome-reporter you are using? – Steve H Jul 11 '22 at 07:56
  • The chart appearing on the `describe()` is dependent on having at least one test at that level. To overcome that problem, I've added a dummy test record called "Aggregate of tests" to force the chart to appear. (Not in the spec, but added during the aggregation phase) – Fody Jul 11 '22 at 10:05
  • I was wondering if it was something about Cypress 9.7 causing probs, so I've migrated to 10.... no change. Curiously though (not sure if this is just a learning thing for me with 10) - if I run the test in interactive mode, the report doesn't get produced at all, but it IS with run mode.... I've even put some console.log statements into the e2e before/after hook definitions, AND in the aggregate function - all get produced in run mode, nothing in open mode? – Steve H Jul 11 '22 at 15:04
  • 1
    Perfect, or nearly so! Thanks so much. – Eddy Gilmour Jul 16 '22 at 00:25