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

test(watch): add some test coverage for watch build plugin #1890

Closed
wants to merge 3 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions gulpfile.js
Expand Up @@ -85,7 +85,8 @@ var angularBuilder = {
var treatTestErrorsAsFatal = true;

function runJasmineTests(globs, done) {
fork('./tools/traceur-jasmine', globs, {
var args = ['--'].concat(globs);
fork('./tools/traceur-jasmine', args, {
stdio: 'inherit'
}).on('close', function jasmineCloseHandler(exitCode) {
if (exitCode && treatTestErrorsAsFatal) {
Expand Down Expand Up @@ -466,7 +467,7 @@ gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function (neverDon


gulp.task('test.unit.tools/ci', function(done) {
runJasmineTests(['dist/tools/**/*.spec.js'], done);
runJasmineTests(['dist/tools/**/*.spec.js', 'tools/**/*.spec.js'], done);
});


Expand Down
5 changes: 4 additions & 1 deletion npm-shrinkwrap.clean.json
Expand Up @@ -8181,6 +8181,9 @@
"reflect-metadata": {
"version": "0.1.0"
},
"rewire": {
"version": "2.3.3"
},
"run-sequence": {
"version": "1.1.0",
"dependencies": {
Expand Down Expand Up @@ -9405,5 +9408,5 @@
}
},
"name": "angular",
"version": "2.0.0-alpha.22"
"version": "2.0.0-alpha.23"
}
7 changes: 6 additions & 1 deletion npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -99,6 +99,7 @@
"protractor": "2.0.0",
"q": "^1.0.1",
"react": "^0.13.2",
"rewire": "^2.3.3",
"run-sequence": "^1.1.0",
"semver": "^4.3.4",
"sorted-object": "^1.0.0",
Expand Down
154 changes: 154 additions & 0 deletions tools/build/watch.spec.js
@@ -0,0 +1,154 @@
var rewire = require('rewire');

describe('watch()', function() {
var timeout;
var watch;
var watcher;
var unmock;

beforeEach(function() {
timeout = mockTimeout();
var watchModule = rewire('./watch');
unmock = watchModule.__set__(timeout.mocks);
watch = watchModule.__get__('watch');
});

afterEach(function() {
// Shouldn't really be necessary, but...
if (watcher) {
watcher.close();
watcher = null;
}
unmock();
expect(timeout.pending).toBe(0);
timeout = null;
});


it('should fire callback once for events which occur within `delay` window', function() {
var cb = jasmine.createSpy('callback');
watcher = watch('./$$fake_path/**/*', { delay: 10 }, cb);

watcher._emit('add', './$$fake_path/test.txt');
timeout.flush(9);
expect(cb).not.toHaveBeenCalled();

watcher._emit('change', './$$fake_path/test.txt');
watcher._emit('add', './$$fake_path/test2.txt');
watcher._emit('change', './$$fake_path/test2.txt');
watcher._emit('add', './$$fake_path/test3.txt');
watcher._emit('change', './$$fake_path/test3.txt');
expect(cb).not.toHaveBeenCalled();

timeout.flush(1);
expect(cb.calls.count()).toBe(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeout.flush();
expect(cb.calls.count()).toBe(1);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean an extra timeout.flush after the existing one, or just getting rid of the 1? (like the 1.x test suite, this one asserts that there are no pending timer events waiting at the end of the spec, so it's the same thing either way)

});


it('should trigger callback if events are collected during task running', function() {
var calls = 0;
function cb(done) {
if (++calls !== 1) return done();

watcher._emit('change', './$$fake_path/test1.txt');
watcher._emit('change', './$$fake_path/test2.txt');

// Before the done callback, there are no pending timer events
expect(timeout.pending).toBe(0);
done();

// Afterwards, there is one
expect(timeout.pending).toBe(1);
}

var watcher = watch('./$$fake_path/**/*', { delay: 10 }, cb);

watcher._emit('change', './$$fake_path/test1.txt');
expect(timeout.pending).toBe(1);
expect(calls).toBe(0);

timeout.flush(10);
expect(calls).toBe(2);
});


it('should cancel pending callback if FSWatcher is closed', function() {
var cb = jasmine.createSpy('callback');
var watcher = watch('./$$fake_path/**/*', { delay: 10 }, cb);

watcher._emit('change', './$$fake_path/test1.txt');
expect(timeout.pending).toBe(1);
expect(cb).not.toHaveBeenCalled();

watcher.close();
expect(timeout.pending).toBe(0);
});


it('should cancel followup pending callback if FSWatcher is closed during task', function() {
var calls = 0;
function cb(done) {
if (++calls !== 1) return done();

watcher._emit('change', './$$fake_path/test2.txt');
done();
expect(timeout.pending).toBe(1);
watcher.close();
expect(timeout.pending).toBe(0);
}

var watcher = watch('./$$fake_path/**/*', { delay: 10 }, cb);
watcher._emit('change', './$$fake_path/test1.txt');

timeout.flush(10);

expect(calls).toBe(1);
});
});


// setTimeout/clearTimeout mocking, mostly stolen from angular-mocks.js
function mockTimeout() {
var events = [];
var id = 0;
var now = 0;

return {
mocks: {
setTimeout: mockSetTimeout,
clearTimeout: mockClearTimeout
},
flush: flush,
get pending() { return events.length; }
};

function mockSetTimeout(fn, delay) {
delay = delay || 0;
events.push({
time: now + delay,
fn: fn,
id: id
});
events.sort(function(a, b) { return a.time - b.time; });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but this might arbitrarily sort events with the sane time. A more deterministic sorting (e.g. taking the id into account when time is the same) might be in place :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's pretty minor, but nobody has complained in angular-mocks yet. unit tests generally don't need to worry about scenarios where it comes up

return id++;
}

function mockClearTimeout(id) {
for (var i = 0; i < events.length; ++i) {
if (events[i].id === id) {
events.splice(i, 1);
break;
}
}
}

function flush(delay) {
if (delay !== undefined) now += delay;
else if (events.length) now = events[events.length - 1].time;
else throw new Error('No timer events registered');

while (events.length && events[0].time <= now) {
events.shift().fn();
}
}
}
31 changes: 21 additions & 10 deletions tools/traceur-jasmine/index.js
Expand Up @@ -7,14 +7,25 @@ var path = require('path');
require('traceur/bin/traceur-runtime.js');
require('reflect-metadata/Reflect');

glob(process.argv[2], function (error, specFiles) {
minijasminenode2.executeSpecs({
includeStackTrace: true,
defaultTimeoutInterval: 1000,
showColors: process.argv.indexOf('--no-color') === -1,
specs: specFiles,
onComplete: function(passed) {
process.exit(passed ? 0 : 1);
}
});
// Support passing multiple globs
var globsIndex = process.argv.indexOf('--');
var args;
if (globsIndex < 0) {
args = [process.argv[2]];
} else {
args = process.argv.slice(globsIndex + 1);
}

var specFiles = args.
map(function(globstr) { return glob.sync(globstr); }).
reduce(function(specFiles, paths) { return specFiles.concat(paths); }, []);

minijasminenode2.executeSpecs({
includeStackTrace: true,
defaultTimeoutInterval: 1000,
showColors: process.argv.indexOf('--no-color') === -1,
specs: specFiles,
onComplete: function(passed) {
process.exit(passed ? 0 : 1);
}
});