Skip to content

Commit

Permalink
fix extension handling; closes #3808
Browse files Browse the repository at this point in the history
  • Loading branch information
boneskull committed Mar 14, 2019
1 parent a3089ad commit 253100d
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 12 deletions.
29 changes: 27 additions & 2 deletions lib/cli/options.js
Expand Up @@ -10,7 +10,8 @@ const fs = require('fs');
const yargsParser = require('yargs-parser');
const {types, aliases} = require('./run-option-metadata');
const {ONE_AND_DONE_ARGS} = require('./one-and-dones');
const mocharc = require('../mocharc.json');
// paranoia
const mocharc = Object.freeze(require('../mocharc.json'));
const {list} = require('./run-helpers');
const {loadConfig, findConfig} = require('./config');
const findup = require('findup-sync');
Expand Down Expand Up @@ -321,14 +322,38 @@ const loadOptions = (argv = []) => {
args.opts = false;
args._ = args._.concat(optsConfig._ || []);
}
// special case: "extension" option should not combine with default value.
// normally we want to combine "array"-type options, and we _do_ with "extension", but only
// within user-defined configuration (args or anything else).
// we must also search through any aliases of "extension" because while the arguments are ///
// normalized by this point, the config file values are not.
// only the "canonical" option name is used in `mocharc`, so we needn't worry about clearing
// multiple options.
// NOTE: as of this writing, "extension" is the only default value which is of an "array" type;
// it's unknown whether the the below strategy should be generalized to any other future
// "array"-type default option.
const processedMocharc = Object.assign({}, mocharc);
if (
args.extension ||
['extension']
.concat(aliases.extension)
.some(
opt =>
Object.hasOwnProperty(rcConfig, opt) ||
Object.hasOwnProperty(pkgConfig, opt) ||
Object.hasOwnProperty(optsConfig, opt)
)
) {
delete processedMocharc.extension;
}

args = parse(
args._,
args,
rcConfig || {},
pkgConfig || {},
optsConfig || {},
mocharc
processedMocharc
);

// recombine positional arguments and "spec"
Expand Down
12 changes: 9 additions & 3 deletions lib/utils.js
Expand Up @@ -575,9 +575,15 @@ exports.lookupFiles = function lookupFiles(filepath, extensions, recursive) {
var stat;

if (!fs.existsSync(filepath)) {
if (fs.existsSync(filepath + '.js')) {
filepath += '.js';
} else {
// check all extensions
if (
!extensions.some(function(ext) {
if (fs.existsSync(filepath + '.' + ext)) {
filepath += '.' + ext;
return true;
}
})
) {
// Handle glob
files = glob.sync(filepath);
if (!files.length) {
Expand Down
90 changes: 83 additions & 7 deletions test/node-unit/cli/options.spec.js
Expand Up @@ -25,7 +25,9 @@ const defaults = {
timeout: 1000,
timeouts: 1000,
t: 1000,
opts: '/default/path/to/mocha.opts'
opts: '/default/path/to/mocha.opts',
extension: ['js'],
'watch-extensions': ['js']
};

describe('options', function() {
Expand Down Expand Up @@ -57,6 +59,7 @@ describe('options', function() {
describe('loadOptions()', function() {
describe('when no parameter provided', function() {
beforeEach(function() {
this.timeout(500);
readFileSync = sandbox.stub();
readFileSync.onFirstCall().returns('{}');
readFileSync.onSecondCall().returns('--retries 3');
Expand Down Expand Up @@ -495,8 +498,8 @@ describe('options', function() {
beforeEach(function() {
readFileSync = sandbox.stub();
config = '/some/.mocharc.json';
readFileSync.onFirstCall().returns('--retries 3');
readFileSync.onSecondCall().returns('{}');
readFileSync.onFirstCall().returns('{}');
readFileSync.onSecondCall().returns('--retries 3');
findConfig = sandbox.stub();
loadConfig = sandbox.stub().throws('Error', 'failed to parse');
findupSync = sandbox.stub().returns('/some/package.json');
Expand Down Expand Up @@ -540,8 +543,8 @@ describe('options', function() {

beforeEach(function() {
readFileSync = sandbox.stub();
readFileSync.onFirstCall().returns('--retries 3');
readFileSync.onSecondCall().returns('{}');
readFileSync.onFirstCall().returns('{}');
readFileSync.onSecondCall().throws();
findConfig = sandbox.stub().returns('/some/.mocharc.json');
loadConfig = sandbox.stub().returns({});
findupSync = sandbox.stub().returns('/some/package.json');
Expand Down Expand Up @@ -576,8 +579,8 @@ describe('options', function() {

beforeEach(function() {
readFileSync = sandbox.stub();
readFileSync.onFirstCall().returns('--retries 3');
readFileSync.onSecondCall().returns('{}');
readFileSync.onFirstCall().returns('{}');
readFileSync.onSecondCall().throws();
findConfig = sandbox.stub().returns(null);
loadConfig = sandbox.stub().returns({});
findupSync = sandbox.stub().returns('/some/package.json');
Expand Down Expand Up @@ -714,5 +717,78 @@ describe('options', function() {
});
});
});

describe('"extension" handling', function() {
describe('when user supplies "extension" option', function() {
let result;

beforeEach(function() {
readFileSync = sandbox.stub();
readFileSync.onFirstCall().throws();
findConfig = sandbox.stub().returns('/some/.mocharc.json');
loadConfig = sandbox.stub().returns({extension: ['tsx']});
findupSync = sandbox.stub();
loadOptions = proxyLoadOptions({
readFileSync,
findConfig,
loadConfig,
findupSync
});
result = loadOptions(['--extension', 'ts']);
});

it('should not concatenate the default value', function() {
expect(result, 'to have property', 'extension', ['ts', 'tsx']);
});
});

describe('when user does not supply "extension" option', function() {
let result;

beforeEach(function() {
readFileSync = sandbox.stub();
readFileSync.onFirstCall().throws();
findConfig = sandbox.stub().returns('/some/.mocharc.json');
loadConfig = sandbox.stub().returns({});
findupSync = sandbox.stub();
loadOptions = proxyLoadOptions({
readFileSync,
findConfig,
loadConfig,
findupSync
});
result = loadOptions();
});

it('should retain the default', function() {
expect(result, 'to have property', 'extension', ['js']);
});
});
});

describe('"spec" handling', function() {
describe('when user supplies "spec" in config and positional arguments', function() {
let result;

beforeEach(function() {
readFileSync = sandbox.stub();
readFileSync.onFirstCall().throws();
findConfig = sandbox.stub().returns('/some/.mocharc.json');
loadConfig = sandbox.stub().returns({spec: '*.spec.js'});
findupSync = sandbox.stub();
loadOptions = proxyLoadOptions({
readFileSync,
findConfig,
loadConfig,
findupSync
});
result = loadOptions(['*.test.js']);
});

it('should place both into the positional arguments array', function() {
expect(result, 'to have property', '_', ['*.test.js', '*.spec.js']);
});
});
});
});
});

0 comments on commit 253100d

Please sign in to comment.