diff --git a/.eslintrc b/.eslintrc index 160a64e4..161537e8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -62,6 +62,7 @@ "semi": [1, "always"], "global-require": 0, "import/no-unresolved": 0, - "import/no-extraneous-dependencies": 0 + "import/no-extraneous-dependencies": 0, + "valid-jsdoc": ["error", { "requireReturn": false }] } } diff --git a/bin/src/cli-main.js b/bin/src/cli-main.js index ba982fdc..8538ea03 100644 --- a/bin/src/cli-main.js +++ b/bin/src/cli-main.js @@ -18,6 +18,9 @@ const ERRORS = { /** * Validate the data file * + * @param {string} dataInFile Filename of test data + * + * @return {Object} JSON test data if valid, otherwise error object { err: message } */ function validateInFile(dataInFile) { let dataIn; @@ -52,10 +55,13 @@ function validateInFile(dataInFile) { /** * Get options to send to report generator * + * @param {Object} args Arguments passed in + * + * @return {Object} Options to pass to report generator */ function getOptions(args) { const { reportFilename, reportDir, reportTitle, reportPageTitle, - inlineAssets, enableCharts, enableCode, dev } = args; + inlineAssets, enableCharts, enableCode, autoOpen, dev } = args; const filename = `${reportFilename.replace(fileExtRegex, '')}.html`; return { reportHtmlFile: path.join(reportDir, filename), @@ -64,6 +70,7 @@ function getOptions(args) { inlineAssets, enableCharts, enableCode, + autoOpen, dev }; } @@ -71,6 +78,7 @@ function getOptions(args) { /** * Main CLI Program * + * @param {Object} processArgs CLI arguments */ function mareport(processArgs) { const args = processArgs || { _: [] }; diff --git a/bin/src/cli.js b/bin/src/cli.js index 9a63f326..b49750a8 100755 --- a/bin/src/cli.js +++ b/bin/src/cli.js @@ -15,6 +15,7 @@ const mareport = require('./cli-main'); * @property {boolean} inlineAssets Should assets be inlined into HTML file (default: false) * @property {boolean} charts Should charts be enabled (default: true) * @property {boolean} code Should test code output be enabled (default: true) + * @property {boolean} autoOpen Open the report after creation (default: false) * @property {boolean} dev Enable dev mode in the report, * asssets loaded via webpack (default: false) */ @@ -70,6 +71,11 @@ yargs describe: 'Display test code', boolean: true }, + autoOpen: { + default: false, + describe: 'Automatically open the report HTML', + boolean: true + }, dev: { default: false, describe: 'Enable dev mode', diff --git a/lib/src/main.js b/lib/src/main.js index 372e420d..a346e8b5 100644 --- a/lib/src/main.js +++ b/lib/src/main.js @@ -11,31 +11,39 @@ const inlineAssetsDir = path.join(distDir, 'assets', 'inline'); const externalAssetsDir = path.join(distDir, 'assets', 'external'); /** - * Private functions + * Saves a file + * + * @param {string} filename Name of file to save + * @param {string} data Data to be saved * + * @return {Promise} Resolves if file has been successfully saved */ +function saveFile(filename, data) { + return new Promise((resolve, reject) => { + fs.outputFile(filename, data, err => err === null ? resolve(true) : reject(err)); + }); +} /** - * Saves a file + * Opens a file * - * @param {String} filename - * @param {String} data - * @returns {Promise} + * @param {string} filename Name of file to open + * + * @return {Promise} Resolves if file has been successfully opened */ - -function saveFile(filename, data) { +function openFile(filename) { return new Promise((resolve, reject) => { - fs.outputFile(filename, data, err => err === null ? resolve(true) : reject(err)); + opener(filename, null, err => err === null ? resolve(true) : reject(err)); }); } /** * Synchronously loads a file with utf8 encoding * - * @param {String} filename - * @returns {String} + * @param {string} filename Name of file to load + * + * @return {string} File data as string */ - function loadFile(filename) { return fs.readFileSync(filename, 'utf8'); } @@ -44,10 +52,10 @@ function loadFile(filename) { * Get report options by extending base options * with user provided options * - * @param {Object} opts - * @returns {Object} + * @param {Object} opts Report options + * + * @return {Object} User options merged with default options */ - function getOptions(opts) { const userOptions = opts || {}; const baseOptions = { @@ -72,10 +80,8 @@ function getOptions(opts) { /** * Get the report assets for inline use * - * @param {Object} opts - * @returns {Object} + * @return {Object} Object with styles and scripts as strings */ - function getAssets() { return { styles: loadFile(path.join(inlineAssetsDir, 'app.css')), @@ -94,10 +100,9 @@ function getAssets() { * - Asset version is not found -> copy assets * - Asset version differs from current version -> copy assets * - * @param {Object} opts - * @returns {Object} + * @param {Object} opts Report options + * */ - function copyAssets(opts) { const assetsDir = path.join(opts.reportDir, 'assets'); const assetsExist = fs.existsSync(assetsDir); @@ -119,13 +124,13 @@ function copyAssets(opts) { /** * Renders the main report React component * - * @param {JSON} data - * @param {Object} options - * @param {String} styles - * @param {String} scripts - * @returns {String} html + * @param {Object} data JSON test data + * @param {Object} options Report options + * @param {string} styles Inline stylesheet + * @param {string} scripts Inline script + * + * @return {string} Rendered HTML string */ - function renderHtml(data, options, styles, scripts) { return render(React.createElement(MainHTML, { data, options, styles, scripts })); } @@ -134,11 +139,11 @@ function renderHtml(data, options, styles, scripts) { /** * Prepare options, assets, and html for saving * - * @param {String} data - * @param {Object} opts - * @returns {Object} + * @param {string} reportData JSON test data + * @param {Object} opts Report options + * + * @return {Object} Prepared data for saving */ - function prepare(reportData, opts) { // Stringify the data if needed let data = reportData; @@ -168,20 +173,34 @@ function prepare(reportData, opts) { } /** - * Exposed functions + * Create the report + * + * @param {string} data JSON test data + * @param {Object} opts Report options * + * @return {Promise} Resolves if report was created successfully */ - function create(data, opts) { const { html, reportFilename, options } = prepare(data, opts); return saveFile(reportFilename, html) - .then(() => { if (options.autoOpen) opener(reportFilename); }); + .then(() => options.autoOpen && openFile(reportFilename)); } +/** + * Create the report synchronously + * + * @param {string} data JSON test data + * @param {Object} opts Report options + * + */ function createSync(data, opts) { const { html, reportFilename, options } = prepare(data, opts); fs.outputFileSync(reportFilename, html); if (options.autoOpen) opener(reportFilename); } +/** + * Expose create/createSync functions + * + */ module.exports = { create, createSync }; diff --git a/package.json b/package.json index be2a51cc..f8809c9c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.1.1", "description": "Generates gorgeous HTML reports from mochawesome reporter.", "scripts": { - "lint": "eslint bin lib src/js src/components/**/*.js src/components/**/*.jsx test/**/*.js test/**/*.jsx", + "lint": "eslint bin/src lib/src src/js src/components/**/*.js src/components/**/*.jsx test/**/*.js test/**/*.jsx", "test": "cross-env UV_THREADPOOL_SIZE=100 BABEL_DISABLE_CACHE=1 NODE_ENV=test nyc $(npm bin)/mocha --require test/helper.js \"test/spec/**/*.test.+(js|jsx)\"", "test:single": "cross-env UV_THREADPOOL_SIZE=100 BABEL_DISABLE_CACHE=1 NODE_ENV=test nyc $(npm bin)/mocha --require test/helper.js ", "compile:main": "$(npm bin)/babel ./lib/src -d lib/", diff --git a/test/spec/cli/cli-main.test.js b/test/spec/cli/cli-main.test.js index 6c745c6c..4338fb93 100644 --- a/test/spec/cli/cli-main.test.js +++ b/test/spec/cli/cli-main.test.js @@ -20,6 +20,7 @@ const sharedOpts = { inlineAssets: false, enableCharts: true, enableCode: true, + autoOpen: false, dev: true }; diff --git a/test/spec/lib/main.test.js b/test/spec/lib/main.test.js index c1bc89d6..6a234b94 100644 --- a/test/spec/lib/main.test.js +++ b/test/spec/lib/main.test.js @@ -44,12 +44,15 @@ beforeEach(() => { opts = Object.assign({}, baseOpts); }); -afterEach(() => { +beforeEach(() => { outputFileStub.reset(); + outputFileStub.resetBehavior(); outputFileSyncStub.reset(); copySyncStub.reset(); readFileSyncStub.reset(); existsSyncStub.reset(); + openerStub.reset(); + openerStub.resetBehavior(); }); describe('lib/main', () => { @@ -60,6 +63,7 @@ describe('lib/main', () => { it('runs create with autoOpen', () => { opts.autoOpen = true; + openerStub.yields(null); outputFileStub.yields(null); return mareport.create(testData, opts).then(() => { expect(openerStub.called).to.equal(true); @@ -71,6 +75,13 @@ describe('lib/main', () => { return expect(mareport.create(testData, opts)).to.be.rejectedWith('save error'); }); + it('runs create with autoOpen and throws', () => { + opts.autoOpen = true; + openerStub.yields('open error'); + outputFileStub.yields(null); + return expect(mareport.create(testData, opts)).to.be.rejectedWith('open error'); + }); + it('runs createSync', () => { mareport.createSync(testData, opts); expect(outputFileSyncStub.calledWith('mochawesome-report/test.html')).to.equal(true); @@ -86,9 +97,8 @@ describe('lib/main', () => { expect(outputFileSyncStub.calledWith('mochawesome-report/mochawesome.html')).to.equal(true); }); - it('runs create with autoOpen', () => { + it('runs createSync with autoOpen', () => { opts.autoOpen = true; - outputFileStub.yields(null); mareport.createSync(testData, opts); expect(openerStub.called).to.equal(true); });