adamgruber / mochawesome

A Gorgeous HTML/CSS Reporter for Mocha.js
https://gitter.im/mochawesome/general
MIT License
1.06k stars 160 forks source link

Report vanishes on load, returns: "Uncaught TypeError: Expected a finite number" #378

Closed selfagency closed 2 years ago

selfagency commented 2 years ago

Describe the bug The report will render for a split second and then disappear, throwing the following console error:

app.js:2 Uncaught TypeError: Expected a finite number
    at e.exports (app.js:2:79540)
    at t.formatDuration (app.js:2:317108)
    at t.value (app.js:2:317514)
    at Ha (app.js:2:221191)
    at Ba (app.js:2:220986)
    at xs (app.js:2:256600)
    at gl (app.js:2:248041)
    at ml (app.js:2:247966)
    at sl (app.js:2:244996)
    at app.js:2:196637

Code Reproduce

mochawesome.zip

Expected behavior

The report should not vanish, even in the event of an error, which should preferably be displayed in a human-readable way to help troubleshoot the cause.

Screenshots

https://share.cleanshot.com/5MdqWp

Environment (please complete the following information):

Additional context

Here's my custom Jest reporter:

const fs = require('fs');
const uuid = require('uuid-v4');

const buildMargeInput = (testResults) => {
  const elapsed = buildElapsedTime(testResults.testResults);
  const testSuites = testResults.testResults.map(createSuite);
  const input = {};
  input.stats = {
    suites: testResults.numTotalTestSuites,
    tests: testResults.numTotalTests,
    testsRegistered: testResults.numTotalTests,
    passes: testResults.numPassedTests,
    pending: testResults.numPendingTests,
    failures: testResults.numFailedTests,
    start: new Date(testResults.startTime), // Jest does epochs
    end: new Date(testResults.startTime + elapsed),
    duration: elapsed,
    passPercent: (testResults.numPassedTests / testResults.numTotalTests) * 100,
    pendingPercent:
      (testResults.numPendingTests / testResults.numTotalTests) * 100,
    other: 0,
    hasOther: false,
    skipped: 0,
    hasSkipped: false,
  };
  input.results = testSuites;
  return input;
};

const createSuite = (suite) => {
  const id = uuid();
  const tests = suite.testResults.map((test) => {
    return createTest(test, id);
  });
  const passes = tests.filter((test) => test.pass).map((test) => test.uuid);
  const failures = tests.filter((test) => test.fail).map((test) => test.uuid);
  const isPending = tests
    .filter((test) => test.pending)
    .map((test) => test.uuid);
  return {
    title: suite?.testResults[0]?.ancestorTitles[0],
    suites: [],
    tests,
    pending: isPending,
    root: false,
    uuid: id,
    _timeout: 5000,
    fullFile: suite.testFilePath,
    file: suite.testFilePath.split('/').pop(),
    beforeHooks: [],
    afterHooks: [],
    passes,
    failures,
    skipped: [],
    duration: suite.perfStats.end - suite.perfStats.start,
  };
};

const createTest = (test, parentId) => {
  console.log(test);

  return {
    title: test.title,
    fullTitle: fullTitle(test),
    timedOut: false,
    duration: test.duration,
    pass: passed(test),
    fail: failed(test),
    pending: pending(test),
    code: '',
    // isRoot: false,
    uuid: uuid(),
    parentUUID: parentId,
    skipped: false,
    isHook: false,
    err: {},
  };
};

const passed = (test) => {
  return test.status === 'passed';
};

const failed = (test) => {
  return test.status === 'failed';
};

const pending = (test) => {
  return test.status === 'pending';
};

const fullTitle = (test) => {
  if (test.fullName) {
    return test.fullName;
  }
  return test.ancestorTitles.reduce((sum, val) => sum + val + ' ', '');
};

const buildElapsedTime = (suites) => {
  return suites.reduce((sum, suite) => {
    return (
      sum +
      suite.testResults.reduce((_sum, test) => {
        return _sum + test.duration;
      }, 0)
    );
  }, 0);
};

const writeOutput = (payload, filepath) => {
  const json = JSON.stringify(payload);
  fs.writeFile(filepath, json, 'utf8', (err) => {
    if (err) {
      throw err;
    }
    console.log('file saved');
  });
};

class JestMochawesomeReporter {
  constructor(globalConfig, options) {
    this._globalConfig = globalConfig;
    this._options = options;
  }

  onRunComplete(contexts, results) {
    const report = buildMargeInput(results);
    writeOutput(
      report,
      `${this._globalConfig.rootDir}/test-report-${uuid()}.json`,
    );
  }
}

module.exports = JestMochawesomeReporter;
adamgruber commented 2 years ago

Take a closer look at the JSON output. There are several instances where "duration": null which is causing the error. This must be a number.

selfagency commented 2 years ago

Thanks that worked.