Skip to content

Commit f72bc17

Browse files
dhdainesJoshuaKGoldberg
andauthoredOct 29, 2024··
fix: handle case of invalid package.json with no explicit config (#5198)
* fix: report syntax errors in package.json (fixes: #5141) * fix(tests): incorrect test (should use existing result) Since `readFileSync` is only stubbed `onFirstCall` we get a different answer the second time around which is probably Not What You Want. But also we *already checked that config = false*. So you could just remove this test, it does nothing useful. * fix: separate read and parse errors * fix: clarify invalid JSON Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com> * fix(test): expect only a SyntaxError nothing else --------- Co-authored-by: Josh Goldberg ✨ <git@joshuakgoldberg.com>
1 parent 68803b6 commit f72bc17

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed
 

‎lib/cli/options.js

+22-8
Original file line numberDiff line numberDiff line change
@@ -181,22 +181,36 @@ const loadPkgRc = (args = {}) => {
181181
result = {};
182182
const filepath = args.package || findUp.sync(mocharc.package);
183183
if (filepath) {
184+
let configData;
184185
try {
185-
const pkg = JSON.parse(fs.readFileSync(filepath, 'utf8'));
186+
configData = fs.readFileSync(filepath, 'utf8');
187+
} catch (err) {
188+
// If `args.package` was explicitly specified, throw an error
189+
if (filepath == args.package) {
190+
throw createUnparsableFileError(
191+
`Unable to read ${filepath}: ${err}`,
192+
filepath
193+
);
194+
} else {
195+
debug('failed to read default package.json at %s; ignoring',
196+
filepath);
197+
return result;
198+
}
199+
}
200+
try {
201+
const pkg = JSON.parse(configData);
186202
if (pkg.mocha) {
187203
debug('`mocha` prop of package.json parsed: %O', pkg.mocha);
188204
result = pkg.mocha;
189205
} else {
190206
debug('no config found in %s', filepath);
191207
}
192208
} catch (err) {
193-
if (args.package) {
194-
throw createUnparsableFileError(
195-
`Unable to read/parse ${filepath}: ${err}`,
196-
filepath
197-
);
198-
}
199-
debug('failed to read default package.json at %s; ignoring', filepath);
209+
// If JSON failed to parse, throw an error.
210+
throw createUnparsableFileError(
211+
`Unable to parse ${filepath}: ${err}`,
212+
filepath
213+
);
200214
}
201215
}
202216
return result;

‎test/node-unit/cli/options.spec.js

+32-2
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ describe('options', function () {
149149
loadOptions('--package /something/wherever --require butts');
150150
},
151151
'to throw',
152-
'Unable to read/parse /something/wherever: bad file message'
152+
'Unable to read /something/wherever: bad file message'
153153
);
154154
});
155155
});
@@ -199,6 +199,36 @@ describe('options', function () {
199199
});
200200
});
201201

202+
describe('when path to package.json unspecified and package.json exists but is invalid', function () {
203+
beforeEach(function () {
204+
const filepath = '/some/package.json';
205+
readFileSync = sinon.stub();
206+
// package.json
207+
readFileSync
208+
.onFirstCall()
209+
.returns('{definitely-invalid');
210+
findConfig = sinon.stub().returns('/some/.mocharc.json');
211+
loadConfig = sinon.stub().returns({});
212+
findupSync = sinon.stub().returns(filepath);
213+
loadOptions = proxyLoadOptions({
214+
readFileSync,
215+
findConfig,
216+
loadConfig,
217+
findupSync
218+
});
219+
});
220+
221+
it('should throw', function () {
222+
expect(
223+
() => {
224+
loadOptions();
225+
},
226+
'to throw',
227+
/SyntaxError/,
228+
);
229+
});
230+
});
231+
202232
describe('when called with package = false (`--no-package`)', function () {
203233
let result;
204234
beforeEach(function () {
@@ -287,7 +317,7 @@ describe('options', function () {
287317
});
288318

289319
it('should set config = false', function () {
290-
expect(loadOptions(), 'to have property', 'config', false);
320+
expect(result, 'to have property', 'config', false);
291321
});
292322
});
293323

0 commit comments

Comments
 (0)
Please sign in to comment.