src/lib/options.js
const path = require('path');
const isFunction = require('lodash.isfunction');
/** CLI Arguments
*
* @argument {string} test-data Data to use for rendering report
*
* @property {string} reportFilename Filename of saved report
* @property {string} reportDir Path to save report to (default: cwd/mochawesome-report)
* @property {string} reportTitle Title to use on the report (default: mochawesome)
* @property {string} reportPageTitle Title of the report document (default: mochawesome-report)
* @property {string} assetsDir Path to save report assets to (default: cwd/mochawesome-report/assets)
* @property {boolean} inlineAssets Should assets be inlined into HTML file (default: false)
* @property {boolean} cdn Should assets be loaded via CDN (default: false)
* @property {boolean} charts Should charts be enabled (default: false)
* @property {boolean} code Should test code output be enabled (default: true)
* @property {boolean} autoOpen Open the report after creation (default: false)
* @property {boolean} overwrite Overwrite existing files (default: true)
* @property {string} timestamp Append timestamp in specified format to the filename.
* Ensures a new file is created on each run.
* Accepts any format string that dateformat can handle.
* See https://github.com/felixge/node-dateformat
* Defaults to 'isoDateTime' when no format is specified
* @property {boolean} showPassed Initial state of "Show Passed" filter (default: true)
* @property {boolean} showFailed Initial state of "Show Failed" filter (default: true)
* @property {boolean} showPending Initial state of "Show Pending" filter (default: true)
* @property {boolean} showSkipped Initial state of "Show Skipped" filter (default: false)
* @property {string} showHooks Determines when hooks should display in the report
* Choices:
* - always: display all hooks
* - never: do not display hooks
* - failed: display only failed hooks (default)
* - context: display only hooks with context
* @property {boolean} saveJson Should report data be saved to JSON file (default: false)
* @property {boolean} saveHtml Should report be saved to HTML file (default: true)
* @property {boolean} dev Enable dev mode in the report,
* asssets loaded via webpack (default: false)
*/
export const yargsOptions = {
f: {
alias: ['reportFilename'],
describe: 'Filename of saved report',
string: true,
requiresArg: true,
},
o: {
alias: ['reportDir'],
default: 'mochawesome-report',
describe: 'Path to save report',
string: true,
normalize: true,
requiresArg: true,
},
t: {
alias: ['reportTitle'],
default: () =>
process
.cwd()
.split(path.sep)
.pop(),
describe: 'Report title',
string: true,
requiresArg: true,
},
p: {
alias: ['reportPageTitle'],
default: 'Mochawesome Report',
describe: 'Browser title',
string: true,
requiresArg: true,
},
i: {
alias: ['inline', 'inlineAssets'],
default: false,
describe: 'Inline report assets (styles, scripts)',
boolean: true,
},
assetsDir: {
describe: 'Path to save assets',
string: true,
normalize: true,
requiresArg: true,
},
cdn: {
default: false,
describe: 'Load report assets via CDN',
boolean: true,
},
charts: {
alias: ['enableCharts'],
default: false,
describe: 'Display charts',
boolean: true,
},
code: {
alias: ['enableCode'],
default: true,
describe: 'Display test code',
boolean: true,
},
autoOpen: {
default: false,
describe: 'Automatically open the report HTML',
boolean: true,
},
overwrite: {
default: true,
describe: 'Overwrite existing files when saving',
boolean: true,
},
timestamp: {
alias: ['ts'],
default: false,
describe: 'Append timestamp in specified format to filename',
string: true,
},
showPassed: {
default: true,
describe: 'Set intial state for "Show Passed" filter',
boolean: true,
},
showFailed: {
default: true,
describe: 'Set intial state for "Show Failed" filter',
boolean: true,
},
showPending: {
default: true,
describe: 'Set intial state for "Show Pending" filter',
boolean: true,
},
showSkipped: {
default: false,
describe: 'Set intial state for "Show Skipped" filter',
boolean: true,
},
showHooks: {
default: 'failed',
describe: 'Display hooks in the report',
choices: ['always', 'never', 'failed', 'context'],
},
saveJson: {
default: false,
describe: 'Save report data to JSON file',
boolean: true,
},
saveHtml: {
default: true,
describe: 'Save report to HTML file',
boolean: true,
},
dev: {
default: false,
describe: 'Enable dev mode',
boolean: true,
},
};
/**
* Retrieve the value of a user supplied option.
* Order of precedence
* 1. User-supplied option
* 2. Environment variable
*
* @param {object} userOptions Options to parse through
* @param {string} optToGet Option name
* @param {boolean} isBool Treat option as Boolean
*
* @return {string|boolean|undefined} Option value
*/
function _getUserOption(userOptions, optToGet, isBool) {
const envVar = `MOCHAWESOME_${optToGet.toUpperCase()}`;
if (userOptions && typeof userOptions[optToGet] !== 'undefined') {
return isBool && typeof userOptions[optToGet] === 'string'
? userOptions[optToGet] === 'true'
: userOptions[optToGet];
}
if (typeof process.env[envVar] !== 'undefined') {
return isBool ? process.env[envVar] === 'true' : process.env[envVar];
}
return undefined;
}
/*
* Helper to create properties and assign values in an object.
* Properties with `undefined` values are ignored. *mutative*
* @param {object} obj Object to assign properties to
*/
function assignVal(obj, prop, userVal, defaultVal) {
const val = userVal !== undefined ? userVal : defaultVal;
if (val !== undefined) {
obj[prop] = val; // eslint-disable-line
}
}
/**
* Return parsed user options merged with base config
*
* @param {Object} userOptions User-supplied options
*
* @return {Object} Merged options
*/
export const getMergedOptions = function getMergedOptions(userOptions) {
const mergedOptions = {};
Object.keys(yargsOptions).forEach(optKey => {
const yargOpt = yargsOptions[optKey];
const aliases = yargOpt.alias;
const defaultVal = isFunction(yargOpt.default)
? yargOpt.default()
: yargOpt.default;
const isBool = yargOpt.boolean;
let userVal = _getUserOption(userOptions, optKey, isBool);
// Most options are single-letter so we add the aliases as properties
if (Array.isArray(aliases) && aliases.length) {
// If the main prop does not have a user supplied value
// we need to check the aliases, stopping if we get a user value
if (userVal === undefined) {
for (let i = 0; i < aliases.length; i += 1) {
userVal = _getUserOption(userOptions, aliases[i], isBool);
if (userVal !== undefined) {
break;
}
}
}
// Handle cases where the main option is not a single letter
if (optKey.length > 1)
assignVal(mergedOptions, optKey, userVal, defaultVal);
// Loop through aliases to set val
aliases.forEach(alias =>
assignVal(mergedOptions, alias, userVal, defaultVal)
);
} else {
// For options without aliases, use the option regardless of length
assignVal(mergedOptions, optKey, userVal, defaultVal);
}
});
// Special handling for defining `assetsDir`
if (!mergedOptions.assetsDir) {
mergedOptions.assetsDir = path.join(mergedOptions.reportDir, 'assets');
}
return mergedOptions;
};