From 7f358b6b95ab00f40ad0354a4a9222f66331265c Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Sun, 3 Feb 2019 23:32:18 +0000 Subject: [PATCH] cleanup mocha implementation * Fixes #287 * Fixes #241 --- src/special/mocha.js | 85 +++++++++++++++++++++++++++++----------- src/utils/get-scripts.js | 6 +++ test/special/mocha.js | 64 +++++++++++++++++++++++++++++- 3 files changed, 132 insertions(+), 23 deletions(-) diff --git a/src/special/mocha.js b/src/special/mocha.js index 28f4de3b..b90c266d 100644 --- a/src/special/mocha.js +++ b/src/special/mocha.js @@ -1,41 +1,82 @@ import fs from 'fs'; import path from 'path'; -import lodash from 'lodash'; import requirePackageName from 'require-package-name'; import { getScripts } from '../utils'; -function getOpts(script) { - const argvs = script.split(' ').filter(argv => argv); +const knownReporters = [ + 'dot', 'doc', 'tap', 'json', 'html', 'list', + 'min', 'spec', 'nyan', 'xunit', 'markdown', 'progress', + 'landing', 'json-stream', +]; + +function getOptsConfig(root, config) { + const argvs = config.split(/\s+/); const optsIndex = argvs.indexOf('--opts'); - return optsIndex !== -1 ? argvs[optsIndex + 1] : null; + + if (optsIndex === -1) { + return null; + } + + const optsPath = argvs[optsIndex + 1]; + + if (!optsPath) { + return null; + } + + return fs.readFileSync(path.resolve(root, '..', optsPath), 'utf-8'); } -function getRequires(content, deps) { - return content - .split('\n') - .map(line => line.trim()) - .filter(line => line.indexOf('--require ') === 0) - .map(line => line.substring('--require '.length).trim()) +function getDependencies(content, deps) { + const lines = content.split(/\s+/); + const result = []; + + lines.forEach((line, idx) => { + if (line === '--require') { + const val = lines[idx + 1]; + if (val && !val.startsWith('--')) { + result.push(val); + } + } + if (line === '--reporter') { + const val = lines[idx + 1]; + if (val && !val.startsWith('--') && !knownReporters.includes(val)) { + result.push(val); + } + } + }); + + return result .map(requirePackageName) - .filter(name => deps.indexOf(name) !== -1); + .filter((v, k, arr) => arr.indexOf(v) === k) + .filter(name => deps.includes(name)); } export default function parseMocha(content, filepath, deps, rootDir) { const defaultOptPath = path.resolve(rootDir, 'test/mocha.opts'); + let config; + if (filepath === defaultOptPath) { - return getRequires(content, deps); + config = content; + } else { + const scripts = getScripts(filepath, content); + const mochaScript = scripts.find(s => s.indexOf('mocha') !== -1); + if (mochaScript) { + config = mochaScript.slice(mochaScript.indexOf('mocha')); + } + } + + if (!config) { + return []; + } + + const requires = []; + const optsConfig = getOptsConfig(filepath, config); + + if (optsConfig) { + requires.push(...getDependencies(optsConfig, deps)); } - // get mocha.opts from scripts - const requires = lodash(getScripts(filepath, content)) - .filter(script => script.indexOf('mocha') !== -1) - .map(script => getOpts(script)) - .filter(opts => opts) - .map(opts => path.resolve(filepath, '..', opts)) - .map(optPath => fs.readFileSync(optPath, 'utf-8')) // TODO async read file - .map(optContent => getRequires(optContent, deps)) - .flatten() - .value(); + requires.push(...getDependencies(config, deps)); return requires; } diff --git a/src/utils/get-scripts.js b/src/utils/get-scripts.js index 9e2f70f4..bf71f5b1 100644 --- a/src/utils/get-scripts.js +++ b/src/utils/get-scripts.js @@ -5,6 +5,12 @@ import lodash from 'lodash'; const scriptCache = {}; +export function clearCache() { + Object.keys(scriptCache).forEach((key) => { + scriptCache[key] = undefined; + }); +} + function getCacheOrFile(key, fn) { if (scriptCache[key]) { return scriptCache[key]; diff --git a/test/special/mocha.js b/test/special/mocha.js index 0a13b7d7..f3bf02df 100644 --- a/test/special/mocha.js +++ b/test/special/mocha.js @@ -1,11 +1,16 @@ -/* global describe, it */ +/* global describe, it, beforeEach */ import 'should'; import fs from 'fs'; import path from 'path'; import parse from '../../src/special/mocha'; +import { clearCache } from '../../src/utils/get-scripts'; describe('mocha special parser', () => { + beforeEach(() => { + clearCache(); + }); + it('should ignore when filename is not supported', () => { const result = parse('content', 'not-supported.txt', [], __dirname); result.should.deepEqual([]); @@ -33,4 +38,61 @@ describe('mocha special parser', () => { const result = parse(packageContent, packagePath, dependencies, rootDir); result.should.deepEqual(['babel', 'chai']); }); + + it('should recognise requires from scripts', () => { + const result = parse(`{ + "scripts": { + "test": "mocha --require chai --require chai/index *" + } + }`, path.resolve(__dirname, 'package.json'), [ + 'chai', + ], __dirname); + result.should.deepEqual(['chai']); + }); + + it('should recognise reporters from scripts', () => { + const result = parse(`{ + "scripts": { + "test": "mocha --reporter custom-reporter *" + } + }`, path.resolve(__dirname, 'package.json'), [ + 'custom-reporter', + ], __dirname); + result.should.deepEqual(['custom-reporter']); + }); + + it('should recognise requires from complex scripts', () => { + const result = parse(`{ + "scripts": { + "test": "someci command --require ignoreme && mocha --require chai *" + } + }`, path.resolve(__dirname, 'package.json'), [ + 'chai', + ], __dirname); + result.should.deepEqual(['chai']); + }); + + it('should recognise reporters from opts', () => { + const optPath = path.resolve(__dirname, 'test/mocha.opts'); + const result = parse('--reporter foo-bar', optPath, ['foo-bar'], __dirname); + result.should.deepEqual(['foo-bar']); + }); + + it('should ignore invalid flags', () => { + const optPath = path.resolve(__dirname, 'test/mocha.opts'); + const result = parse('--reporter --require --reporter', optPath, [], __dirname); + result.should.deepEqual([]); + }); + + [ + 'dot', 'doc', 'tap', 'json', 'html', 'list', + 'min', 'spec', 'nyan', 'xunit', 'markdown', 'progress', + 'landing', 'json-stream', + ].forEach((reporter) => { + it(`should ignore built-in reporters (${reporter})`, () => { + const optPath = path.resolve(__dirname, 'test/mocha.opts'); + const result = parse(`--reporter ${reporter}`, optPath, [], __dirname); + result.should.deepEqual([]); + }); + }); });