New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow reading bundle from stdin #269
Changes from 5 commits
f6305c0
36777d0
6d939ec
1a08cba
603069f
878518f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,10 @@ const opts = yargs(hideBin(process.argv)) | |
'$0 --config mochify.webdriver.js "./src/**/*.test.js" ', | ||
'Run all tests matching the given spec using the configuration from mochify.webdriver.js.' | ||
) | ||
.example( | ||
'browserify "./src/**/*.test.js" | $0 -', | ||
'Read a bundled test suite from stdin.' | ||
) | ||
.epilogue( | ||
`Mochify Resources: | ||
GitHub: https://github.com/mantoni/mochify.js` | ||
|
@@ -86,16 +90,19 @@ if (opts['server-option']) { | |
opts.server_options = opts['server-option']; | ||
} | ||
|
||
(async () => { | ||
if (opts._.length) { | ||
if (opts._.length) { | ||
if (opts._[0] === '-') { | ||
opts.spec = process.stdin; | ||
} else { | ||
opts.spec = opts._; | ||
} | ||
delete opts._; | ||
try { | ||
const { exit_code } = await mochify(opts); | ||
} | ||
delete opts._; | ||
mochify(opts) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unwrapping this and using a Promise chain is here to stop eslint from complaining. I'm not entirely sure if its complaints are correct or not yet. We could also keep the old version and ignore the rule, no real preference from my side here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably even easier to read than the self-invoking async function. 👍 |
||
.catch((err) => { | ||
console.error(err.stack); | ||
return { exit_code: 1 }; | ||
}) | ||
.then(({ exit_code }) => { | ||
process.exitCode = exit_code; | ||
} catch (e) { | ||
console.error(e.stack); | ||
process.exitCode = 1; | ||
} | ||
})(); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { assert } = require('@sinonjs/referee-sinon'); | ||
const execa = require('execa'); | ||
|
@@ -28,6 +29,27 @@ describe('puppeteer', () => { | |
assert.equals(json.tests[0].fullTitle, 'test passes'); | ||
}); | ||
|
||
it('reads from stdin', async () => { | ||
let result; | ||
try { | ||
const cp = execa('../../index.js', ['--driver', 'puppeteer', '-'], { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively we could also teach There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That'd make it rather complicated, no? |
||
cwd: path.join(__dirname, 'fixture') | ||
}); | ||
const fixture = fs.createReadStream( | ||
path.resolve(__dirname, './fixture/passes.js') | ||
); | ||
fixture.pipe(cp.stdin); | ||
result = await cp; | ||
} catch (err) { | ||
result = err; | ||
} | ||
|
||
assert.isFalse(result.failed); | ||
const json = JSON.parse(result.stdout); | ||
assert.equals(json.tests.length, 1); | ||
assert.equals(json.tests[0].fullTitle, 'test passes'); | ||
}); | ||
|
||
it('fails', async () => { | ||
const result = await run('fails.js'); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
const { readFile } = require('fs').promises; | ||
const { loadConfig } = require('./lib/load-config'); | ||
const { validateConfig } = require('./lib/validate-config'); | ||
const { setupClient } = require('./lib/setup-client'); | ||
const { createMochaRunner } = require('./lib/mocha-runner'); | ||
const { resolveBundle } = require('./lib/resolve-bundle'); | ||
|
@@ -14,11 +15,16 @@ exports.mochify = mochify; | |
async function mochify(options = {}) { | ||
const config = await loadConfig(options); | ||
|
||
const validation_error = validateConfig(config); | ||
if (validation_error) { | ||
throw validation_error; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like I've just been writing too much Go lately. I'll change this as it makes sense for this to behave like everything else (which is throwing to stop execution). |
||
|
||
// Create runner early to verify the reporter exists: | ||
const mocha_runner = createMochaRunner(config.reporter || 'spec'); | ||
const { mochifyDriver } = resolveMochifyDriver(config.driver); | ||
|
||
const [mocha, client, files] = await Promise.all([ | ||
const [mocha, client, resolved_spec] = await Promise.all([ | ||
readFile(require.resolve('mocha/mocha.js'), 'utf8'), | ||
readFile(require.resolve('./client'), 'utf8'), | ||
resolveSpec(config.spec) | ||
|
@@ -30,7 +36,7 @@ async function mochify(options = {}) { | |
let server = null; | ||
if (config.serve || config.esm) { | ||
const _scripts = [mocha, configured_client]; | ||
const _modules = config.esm ? files : []; | ||
const _modules = config.esm ? resolved_spec : []; | ||
server = await startServer( | ||
config.serve || process.cwd(), | ||
Object.assign({ _scripts, _modules }, config.server_options) | ||
|
@@ -41,7 +47,7 @@ async function mochify(options = {}) { | |
const driver_promise = mochifyDriver(driver_options); | ||
const bundler_promise = config.esm | ||
? Promise.resolve('') | ||
: resolveBundle(config.bundle, files); | ||
: resolveBundle(config.bundle, resolved_spec); | ||
|
||
let driver, bundle; | ||
try { | ||
|
@@ -72,12 +78,6 @@ async function mochify(options = {}) { | |
} | ||
|
||
function resolveMochifyDriver(name) { | ||
if (!name) { | ||
throw new Error( | ||
'Specifying a driver option is required. Mochify drivers need to be installed separately from the API or the CLI.' | ||
); | ||
} | ||
|
||
let driverModule; | ||
try { | ||
// eslint-disable-next-line node/global-require | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,9 @@ async function loadConfig(options) { | |
async function mergeWithDefault(default_config_promise, config) { | ||
const default_config = await default_config_promise; | ||
if (default_config) { | ||
return deepmerge(default_config.config, config); | ||
return deepmerge(default_config.config, config, { | ||
clone: false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cloning a stream apparently causes infinite recursion. Don't think not cloning will hurt us here. |
||
}); | ||
} | ||
return config; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,10 @@ const glob = promisify(require('glob')); | |
exports.resolveSpec = resolveSpec; | ||
|
||
async function resolveSpec(spec = 'test/**/*.js') { | ||
if (typeof spec === 'object' && typeof spec.pipe === 'function') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found it nicer to handle such situations at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I also get the feeling it's growing quite a bit. Maybe it's time to introduce more functions like |
||
return spec; | ||
} | ||
|
||
const patterns = Array.isArray(spec) ? spec : [spec]; | ||
const matches = await Promise.all(patterns.map((pattern) => glob(pattern))); | ||
return matches.reduce((all, match) => all.concat(match), []); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict'; | ||
|
||
exports.validateConfig = validateConfig; | ||
|
||
function validateConfig(config) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I left this function intentionally simple (i.e. manual checking) for now. We can start building our declarative mini DSL later ... |
||
if (!config.driver) { | ||
return new Error( | ||
'Specifying a `driver` is required. Mochify drivers need to be installed separately from the API or the CLI.' | ||
); | ||
} | ||
if (config.esm && config.bundle) { | ||
return new Error('`esm` cannot be used in conjunction with `bundle`'); | ||
} | ||
if ( | ||
config.bundle && | ||
typeof config.spec === 'object' && | ||
typeof config.spec.pipe === 'function' | ||
) { | ||
return new Error('`bundle` cannot be used when `spec` is a stream.'); | ||
} | ||
return null; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const { assert } = require('@sinonjs/referee-sinon'); | ||
const { validateConfig } = require('./validate-config'); | ||
|
||
describe('mochify/lib/validate-config', () => { | ||
it('returns an error when esm and bundle are given', () => { | ||
assert.isError( | ||
validateConfig({ | ||
driver: 'puppeteer', | ||
esm: true, | ||
bundle: 'browserify', | ||
spec: './test.js' | ||
}) | ||
); | ||
}); | ||
|
||
it('returns an error when bundle and a stream spec are given', () => { | ||
assert.isError( | ||
validateConfig({ | ||
driver: 'puppeteer', | ||
bundle: 'browserify', | ||
spec: fs.createReadStream(__filename) | ||
}) | ||
); | ||
}); | ||
|
||
it('returns an error on an empty config', () => { | ||
assert.isError(validateConfig({})); | ||
}); | ||
|
||
it('returns null on a valid config', () => { | ||
assert.isNull( | ||
validateConfig({ | ||
bundle: 'browserify -t babelify', | ||
spec: './test.js', | ||
driver: 'puppeteer' | ||
}) | ||
); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍