Skip to content
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

[WIP] Browser support #887

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 23 additions & 24 deletions api.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ var debounce = require('lodash.debounce');
var ms = require('ms');
var AvaError = require('./lib/ava-error');
var fork = require('./lib/fork');
var CachingPrecompiler = require('./lib/caching-precompiler');
var AvaFiles = require('./lib/ava-files');
var RunStatus = require('./lib/run-status');

function Api(options) {
Expand Down Expand Up @@ -43,13 +41,17 @@ util.inherits(Api, EventEmitter);
module.exports = Api;

Api.prototype._runFile = function (file, runStatus) {
var hash = this.precompiler.precompileFile(file);
var precompiled = {};
precompiled[file] = hash;
var options = objectAssign({}, this.options);

var options = objectAssign({}, this.options, {
precompiled: precompiled
});
var babelEnabled = this.options.babelEnabled !== false;

if (babelEnabled) {
var hash = this.precompiler.precompileFile(file);
var precompiled = {};
precompiled[file] = hash;

options.precompiled = precompiled;
}

var emitter = fork(file, options);

Expand All @@ -70,17 +72,7 @@ Api.prototype._onTimeout = function (runStatus) {
runStatus.emit('timeout');
};

Api.prototype.run = function (files, options) {
var self = this;

return new AvaFiles(files)
.findTestFiles()
.then(function (files) {
return self._run(files, options);
});
};

Api.prototype._run = function (files, _options) {
Api.prototype.run = function (files, _options) {
var self = this;
var runStatus = new RunStatus({
prefixTitles: this.options.explicitTitles || files.length > 1,
Expand Down Expand Up @@ -108,12 +100,19 @@ Api.prototype._run = function (files, _options) {
return Promise.resolve(runStatus);
}

var cacheEnabled = self.options.cacheEnabled !== false;
var cacheDir = (cacheEnabled && findCacheDir({name: 'ava', files: files})) ||
uniqueTempDir();
var babelEnabled = self.options.babelEnabled !== false;

if (babelEnabled) {
var CachingPrecompiler = require('./lib/caching-precompiler');

var cacheEnabled = self.options.cacheEnabled !== false;
var cacheDir = (cacheEnabled && findCacheDir({name: 'ava', files: files})) ||
uniqueTempDir();

self.options.cacheDir = cacheDir;
self.precompiler = new CachingPrecompiler(cacheDir, self.options.babelConfig);
}

self.options.cacheDir = cacheDir;
self.precompiler = new CachingPrecompiler(cacheDir, self.options.babelConfig);
self.fileCount = files.length;

var overwatch;
Expand Down
91 changes: 91 additions & 0 deletions browser-index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';
var path = require('path');
var chalk = require('chalk');
var serializeError = require('./lib/serialize-error');
var globals = require('./lib/globals');
var Runner = require('./lib/runner');
var send = require('./lib/send');

var opts = globals.options;
var runner = new Runner({
serial: opts.serial,
bail: opts.failFast,
match: opts.match
});

// note that test files have require('ava')
require('./lib/test-worker').avaRequired = true;

// if fail-fast is enabled, use this variable to detect
// that no more tests should be logged
var isFailed = false;

Error.stackTraceLimit = Infinity;

function test(props) {
if (isFailed) {
return;
}

var hasError = typeof props.error !== 'undefined';

// don't display anything if it's a passed hook
if (!hasError && props.type !== 'test') {
return;
}

if (hasError) {
props.error = serializeError(props.error);
} else {
props.error = null;
}

send('test', props);

if (hasError && opts.failFast) {
isFailed = true;
exit();
}
}

function exit() {
var stats = runner._buildStats();

send('results', {
stats: stats
});

globals.setTimeout(close, 100);
}

globals.setImmediate(function () {
var hasExclusive = runner.tests.hasExclusive;
var numberOfTests = runner.tests.tests.concurrent.length + runner.tests.tests.serial.length;

if (numberOfTests === 0) {
send('no-tests', {avaRequired: true});
return;
}

send('stats', {
testCount: numberOfTests,
hasExclusive: hasExclusive
});

runner.on('test', test);

globals.events.on('ava-run', function (options) {
runner.run(options).then(exit);
});

globals.events.on('ava-init-exit', function () {
exit();
});
});

module.exports = runner.test;

// TypeScript imports the `default` property for
// an ES2015 default import (`import test from 'ava'`)
// See: https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181
module.exports.default = runner.test;
49 changes: 49 additions & 0 deletions browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

var arrify = require('arrify');
var globals = require('./lib/globals');
var Api = require('./api');

var state = require('./state');
var files = state.files;
var conf = state.conf;
var cli = state.cli;

var api = new Api({
failFast: cli.flags.failFast,
serial: cli.flags.serial,
babelEnabled: false,
cacheEnabled: false,
explicitTitles: false,
match: arrify(cli.flags.match),
babelConfig: conf.babel,
timeout: cli.flags.timeout,
concurrency: cli.flags.concurrency ? parseInt(cli.flags.concurrency, 10) : 0
});

api.on('test-run', function (runStatus) {
runStatus.on('test', function (test) {
console.log('test');
console.log(test);
});

// runStatus.on('error', logger.unhandledError);

// runStatus.on('stdout', logger.stdout);
// runStatus.on('stderr', logger.stderr);
});

api.run(files)
.then(function (runStatus) {
console.log('finish');
console.log(runStatus);
// logger.finish(runStatus);
// logger.exit(runStatus.failCount > 0 || runStatus.rejectionCount > 0 || runStatus.exceptionCount > 0 ? 1 : 0);
})
.catch(function (err) {
// Don't swallow exceptions. Note that any expected error should already
// have been logged.
globals.setImmediate(function () {
throw err;
});
});
84 changes: 79 additions & 5 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ if (debug.enabled) {
require('time-require');
}

var fs = require('fs');
var uniqueTempDir = require('unique-temp-dir');
var findCacheDir = require('find-cache-dir');
var updateNotifier = require('update-notifier');
var figures = require('figures');
var arrify = require('arrify');
Expand All @@ -26,10 +29,13 @@ var pkgConf = require('pkg-conf');
var chalk = require('chalk');
var isCi = require('is-ci');
var hasFlag = require('has-flag');
var through = require('through');
var colors = require('./lib/colors');
var CachingPrecompiler = require('./lib/caching-precompiler');
var verboseReporter = require('./lib/reporters/verbose');
var miniReporter = require('./lib/reporters/mini');
var tapReporter = require('./lib/reporters/tap');
var AvaFiles = require('./lib/ava-files');
var Logger = require('./lib/logger');
var Watcher = require('./lib/watcher');
var Api = require('./api');
Expand Down Expand Up @@ -97,7 +103,8 @@ var cli = meow([
'verbose',
'serial',
'tap',
'watch'
'watch',
'browser'
],
default: conf,
alias: {
Expand All @@ -109,7 +116,8 @@ var cli = meow([
w: 'watch',
S: 'source',
T: 'timeout',
c: 'concurrency'
c: 'concurrency',
b: 'browser'
}
});

Expand All @@ -128,6 +136,74 @@ if (
process.exit(1);
}

var patterns = cli.input.length ? cli.input : arrify(conf.files);
var files = new AvaFiles(patterns)
.findTestFilesSync();

if (cli.flags.browser) {
var browserify = require('browserify');

var cacheDirPath = findCacheDir({name: 'ava', files: files}) || uniqueTempDir();
var precompiler = new CachingPrecompiler(cacheDirPath, cli.flags.babelConfig);

function precompile (file) {
if (files.indexOf(file) < 0) {
return through();
}

precompiler.precompileFile(file);

var hash = precompiler.fileHashes[file];
var path = __dirname + '/node_modules/.cache/ava/' + hash + '.js';

var fileStream = fs.createReadStream(path);
var transformStream = through(function () {}, function () {});

fileStream.on('data', function (data) {
transformStream.queue(data);
});

fileStream.on('end', function () {
transformStream.queue(null);
});

return transformStream;
}

var state = {
files: files,
conf: conf,
cli: cli
};

var statePath = cacheDirPath + '/state.json';
fs.writeFileSync(statePath, JSON.stringify(state), 'utf8');

var browserBundle = browserify(['browser.js'], {
fullPaths: true,
insertGlobals: true
});

browserBundle.require(statePath, { expose: './state' });

var browserStream = fs.createWriteStream('tests.js');
browserBundle.bundle().pipe(browserStream);

var workerBundle = browserify(['lib/browser-test-worker.js'], {
fullPaths: true,
insertGlobals: true
});

workerBundle.transform(precompile);
workerBundle.require(arrify(cli.flags.require));
workerBundle.require(files);

var workerStream = fs.createWriteStream('test-worker.js');
workerBundle.bundle().pipe(workerStream);

return;
}

var api = new Api({
failFast: cli.flags.failFast,
serial: cli.flags.serial,
Expand Down Expand Up @@ -164,11 +240,9 @@ api.on('test-run', function (runStatus) {
runStatus.on('stderr', logger.stderr);
});

var files = cli.input.length ? cli.input : arrify(conf.files);

if (cli.flags.watch) {
try {
var watcher = new Watcher(logger, api, files, arrify(cli.flags.source));
var watcher = new Watcher(logger, api, patterns, arrify(cli.flags.source));
watcher.observeStdin(process.stdin);
} catch (err) {
if (err.name === 'AvaError') {
Expand Down
Loading