Fix checkin tests to use fake timers

* To speed the time the tests spend running
* To make them reliably execute and not depend on magic numbers

Additional changes:
* Use mw.now instead of Date on checkin.js
* Split big setVisibleTimeout test into several smaller ones
  * Extract helpers for the tests

Change-Id: I9d3233fccf6de0997f968d096e375df996e87786
This commit is contained in:
joakin 2017-01-09 16:35:14 -08:00
parent 7f25a8ce1a
commit 84043e86f9
2 changed files with 76 additions and 55 deletions

View file

@ -67,13 +67,13 @@
// Timer may not have been started if the document opened in a
// hidden tab for example. The timer will be started when the
// document is visible to the user.
if ( lastStartedAt ) {
millisecondsPassed = new Date().getTime() - lastStartedAt;
if ( lastStartedAt !== undefined ) {
millisecondsPassed = Math.round( mw.now() - lastStartedAt );
delay = Math.max( 0, delay - millisecondsPassed );
clearTimeout( timeoutId );
}
} else {
lastStartedAt = new Date().getTime();
lastStartedAt = Math.round( mw.now() );
timeoutId = setTimeout( done, delay );
}
}

View file

@ -10,6 +10,37 @@
checkin.haveCheckinActionsBeenSetup = false;
this.CHECKIN_TIMES = [ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,
377, 610, 987, 1597, 2584, 4181, 6765 ];
this.clock = this.sandbox.useFakeTimers( 0, 'setTimeout', 'clearTimeout', 'Date' );
// Stub performance.now to be Date.now to make timing work with the
// sinon timers and with integers.
performance && this.sandbox.stub( performance, 'now', Date.now );
this.callback = this.sandbox.spy();
this.delay = 5000;
this.miniDelay = 10;
this.pause = 2000;
this.setupInitialState = function () {
this.sandbox.stub( pageVisibility, 'getDocumentHiddenPropertyName' ).returns( 'customHidden' );
this.sandbox.stub( pageVisibility, 'getDocumentVisibilitychangeEventName' ).returns( 'customvisibilitychange' );
this.isDocumentHidden = this.sandbox.stub( pageVisibility, 'isDocumentHidden' ).returns( false );
};
this.setupPageHiddenState = function () {
this.isDocumentHidden.returns( true );
this.clock.tick( this.miniDelay );
};
this.setupPageVisibleState = function () {
// resume after `pause` milliseconds
this.isDocumentHidden.returns( false );
this.clock.tick( this.pause );
};
},
tearDown: function () {
performance && performance.now.restore();
this.clock.restore();
}
} );
@ -20,60 +51,47 @@
QUnit.test( 'visible timeout will not fire the callback if the' +
' browser does not support the visibility API', function ( assert ) {
var delay = 1000,
spy = this.sandbox.spy(),
done = assert.async();
assert.expect( 1 );
this.sandbox.stub( pageVisibility, 'getDocumentHiddenPropertyName' ).returns( undefined );
checkin.setVisibleTimeout( spy, delay );
setTimeout( function () {
assert.ok( spy.notCalled );
done();
}, 2 * delay ); // wait a little more in case the the event loop is busy
checkin.setVisibleTimeout( this.callback, 1000 );
this.clock.tick( 1001 );
assert.equal( this.callback.called, false, 'callback should not have been called' );
} );
QUnit.test( 'visible timeout pause works correctly', function ( assert ) {
var delay = 5000,
pause = 2000,
// error margin in milliseconds
delta = 50,
spy = this.sandbox.spy(),
done = assert.async();
QUnit.test( '#setVisibleTimeout calls callback if the page is visible', function ( assert ) {
this.setupInitialState();
checkin.setVisibleTimeout( this.callback, this.delay );
this.clock.tick( this.delay + 1 );
assert.expect( 2 );
assert.ok( this.callback.calledOnce, 'callback should have been called' );
} );
this.sandbox.stub( pageVisibility, 'getDocumentHiddenPropertyName' ).returns( 'customHidden' );
this.sandbox.stub( pageVisibility, 'getDocumentVisibilitychangeEventName' ).returns( 'customvisibilitychange' );
QUnit.test( '#setVisibleTimeout does not call the callback if the page becomes hidden', function ( assert ) {
this.setupInitialState();
checkin.setVisibleTimeout( this.callback, this.delay );
checkin.setVisibleTimeout( spy, delay );
// pause immediately, after making sure the document is hidden
this.sandbox.stub( pageVisibility, 'isDocumentHidden' ).returns( true );
this.setupPageHiddenState();
$( document ).trigger( 'customvisibilitychange' );
// resume after `pause` milliseconds
pageVisibility.isDocumentHidden.restore();
this.sandbox.stub( pageVisibility, 'isDocumentHidden' ).returns( false );
setTimeout( function () {
this.clock.tick( this.delay + 1 );
assert.notOk( this.callback.called, 'Callback should have not been called' );
} );
QUnit.test( '#setVisibleTimeout calls callback with the adjusted delay after the page becoming visible', function ( assert ) {
this.setupInitialState();
checkin.setVisibleTimeout( this.callback, this.delay );
this.setupPageHiddenState();
$( document ).trigger( 'customvisibilitychange' );
pageVisibility.isDocumentHidden.restore();
}, pause );
setTimeout( function () {
// make sure the spy is not called after `delay` as we've paused
assert.ok( spy.notCalled );
this.setupPageVisibleState();
$( document ).trigger( 'customvisibilitychange' );
setTimeout( function () {
// make sure the spy is called after `delay` + `pause` as we've resumed
assert.ok( spy.called );
done();
}, pause + delta );
}, delay + delta );
this.clock.tick( this.delay - this.miniDelay + 1 );
assert.equal( this.callback.callCount, 1, 'callback should have been called' );
} );
QUnit.test( 'checkin actions will not be set up if they already have been', function ( assert ) {
@ -89,20 +107,23 @@
QUnit.test( 'checkin actions are setup correctly', function ( assert ) {
var actionSpy = this.sandbox.spy(),
done = assert.async();
that = this;
checkin.CHECKIN_TIMES = [ 1, 2, 3 ];
assert.expect( checkin.CHECKIN_TIMES.length );
checkin.setupActions( actionSpy );
setTimeout( function () {
$.each( checkin.CHECKIN_TIMES, function ( i, time ) {
assert.ok( actionSpy.calledWith( time ),
'`action` has been called the correct checkin time: ' + time + '.' );
that.clock.tick( time * 1000 + 1 );
} );
done();
// give two more seconds to catch up
}, ( checkin.CHECKIN_TIMES[ checkin.CHECKIN_TIMES.length - 1 ] + 2 ) * 1000 );
assert.equal( actionSpy.callCount, 3, 'Action called at the appropiate times' );
assert.deepEqual( [
actionSpy.getCall( 0 ).args[ 0 ],
actionSpy.getCall( 1 ).args[ 0 ],
actionSpy.getCall( 2 ).args[ 0 ]
], [
1, 2, 3
], '`action` has been called the with the correct checkin times' );
} );
}( mediaWiki, jQuery ) );