diff --git a/bin/tape b/bin/tape index 500f1b14..498910cd 100755 --- a/bin/tape +++ b/bin/tape @@ -1,12 +1,34 @@ #!/usr/bin/env node -var path = require('path'); +var resolveModule = require('resolve').sync; +var resolvePath = require('path').resolve; +var parseOpts = require('minimist'); var glob = require('glob'); -process.argv.slice(2).forEach(function (arg) { +var opts = parseOpts(process.argv.slice(2), { + alias: { r: 'require' }, + string: 'require', + default: { r: [] } + }); + +var cwd = process.cwd(); + +if (typeof opts.require === 'string') { + opts.require = [opts.require]; +} + +opts.require.forEach(function(module) { + if (module) { + /* This check ensures we ignore `-r ""`, trailing `-r`, or + * other silly things the user might (inadvertently) be doing. */ + require(resolveModule(module, { basedir: cwd })); + } +}); + +opts._.forEach(function (arg) { glob(arg, function (err, files) { files.forEach(function (file) { - require(path.resolve(process.cwd(), file)); + require(resolvePath(cwd, file)); }); }); }); diff --git a/package.json b/package.json index 0be3595b..892dfca5 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "glob": "~5.0.3", "has": "~1.0.1", "inherits": "~2.0.1", + "minimist": "~1.2.0", "object-inspect": "~1.0.0", + "resolve": "~1.1.6", "resumer": "~0.0.0", "string.prototype.trim": "^1.1.1", "through": "~2.3.4" diff --git a/readme.markdown b/readme.markdown index ca774862..04368de0 100644 --- a/readme.markdown +++ b/readme.markdown @@ -64,6 +64,26 @@ $ tape 'tests/**/*.js' $ tape "tests/**/*.js" ``` +## Preloading modules + +Additionally, it is possible to make `tape` load one or more modules before running any tests, by using the `-r` or `--require` flag. Here's an example that loads [babel-register](http://babeljs.io/docs/usage/require/) before running any tests, to allow for JIT compilation: + +```sh +$ tape -r babel-register tests/**/*.js +``` + +Depending on the module you're loading, you may be able to paramaterize it using environment variables or auxiliary files. Babel, for instance, will load options from [`.babelrc`](http://babeljs.io/docs/usage/babelrc/) at runtime. + +The `-r` flag behaves exactly like node's `require`, and uses the same module resolution algorithm. This means that if you need to load local modules, you have to prepend their path with `./` or `../` accordingly. + +For example: + +```sh +$ tape -r ./my/local/module tests/**/*.js +``` + +Please note that modules that all modules loaded using the `-r` flag will run *before* any tests, regardless of when they are specified. For example, `tape -r a b -r c` will actually load `a` and `c` *before` loading `b`, since they are flagged as required modules. + # things that go well with tape tape maintains a fairly minimal core. Additional features are usually added by using another module alongside tape. diff --git a/test/require.js b/test/require.js new file mode 100644 index 00000000..0385ea45 --- /dev/null +++ b/test/require.js @@ -0,0 +1,83 @@ +var tap = require('tap'); +var spawn = require('child_process').spawn; +var trim = require('string.prototype.trim'); + +tap.test('requiring a single module', function (t) { + t.plan(2); + + var tc = tap.createConsumer(); + + var rows = []; + tc.on('data', function (r) { rows.push(r) }); + tc.on('end', function () { + var rs = rows.map(function (r) { + if (r && typeof r === 'object') { + return { id : r.id, ok : r.ok, name : trim(r.name) }; + } + else return r; + }); + t.same(rs, [ + 'TAP version 13', + 'module-a', + { id: 1, ok: true, name: 'loaded module a' }, + 'test-a', + { id: 2, ok: true, name: 'module-a loaded in same context'}, + { id: 3, ok: true, name: 'test ran after module-a was loaded'}, + 'tests 3', + 'pass 3', + 'ok' + ]); + }); + + var ps = tape('-r ./require/a require/test-a.js'); + ps.stdout.pipe(tc); + ps.on('exit', function (code) { + t.equal(code, 0); + }); +}); + +tap.test('requiring multiple modules', function (t) { + t.plan(2); + + var tc = tap.createConsumer(); + + var rows = []; + tc.on('data', function (r) { rows.push(r) }); + tc.on('end', function () { + var rs = rows.map(function (r) { + if (r && typeof r === 'object') { + return { id : r.id, ok : r.ok, name : trim(r.name) }; + } + else return r; + }); + t.same(rs, [ + 'TAP version 13', + 'module-a', + { id: 1, ok: true, name: 'loaded module a' }, + 'module-b', + { id: 2, ok: true, name: 'loaded module b' }, + 'test-a', + { id: 3, ok: true, name: 'module-a loaded in same context'}, + { id: 4, ok: true, name: 'test ran after module-a was loaded'}, + 'test-b', + { id: 5, ok: true, name: 'module-b loaded in same context'}, + { id: 6, ok: true, name: 'test ran after module-b was loaded'}, + 'tests 6', + 'pass 6', + 'ok' + ]); + }); + + var ps = tape('-r ./require/a -r ./require/b require/test-a.js require/test-b.js'); + ps.stdout.pipe(tc); + ps.on('exit', function (code) { + t.equal(code, 0); + }); +}); + +function tape(args) { + var proc = require('child_process') + var bin = __dirname + '/../bin/tape' + + return proc.spawn(bin, args.split(' '), { cwd: __dirname }) +} \ No newline at end of file diff --git a/test/require/a.js b/test/require/a.js new file mode 100644 index 00000000..0947b7b9 --- /dev/null +++ b/test/require/a.js @@ -0,0 +1,8 @@ +var tape = require('../..'); + +tape.test('module-a', function(t) { + t.pass('loaded module a') + t.end() +}) + +global.module_a = true \ No newline at end of file diff --git a/test/require/b.js b/test/require/b.js new file mode 100644 index 00000000..18942e0c --- /dev/null +++ b/test/require/b.js @@ -0,0 +1,8 @@ +var tape = require('../..'); + +tape.test('module-b', function(t) { + t.pass('loaded module b') + t.end() +}) + +global.module_b = true \ No newline at end of file diff --git a/test/require/test-a.js b/test/require/test-a.js new file mode 100644 index 00000000..822ef540 --- /dev/null +++ b/test/require/test-a.js @@ -0,0 +1,7 @@ +var tape = require('../..'); + +tape.test('test-a', function(t) { + t.ok(global.module_a, 'module-a loaded in same context') + t.pass('test ran after module-a was loaded') + t.end() +}) \ No newline at end of file diff --git a/test/require/test-b.js b/test/require/test-b.js new file mode 100644 index 00000000..8efcba1c --- /dev/null +++ b/test/require/test-b.js @@ -0,0 +1,7 @@ +var tape = require('../..'); + +tape.test('test-b', function(t) { + t.ok(global.module_b, 'module-b loaded in same context') + t.pass('test ran after module-b was loaded') + t.end() +}) \ No newline at end of file