This isn't comprehensive but it should be broad enough to ensure that most people who would be affected by blocking monkey patching see a warning. Covers the jasmine namespace as well as classes that are monkey patched by zone.js. Replacing globals (describe/it/etc) doesn't trigger a warning because they belong to the user and are expected to be replaced.
1272 lines
39 KiB
JavaScript
1272 lines
39 KiB
JavaScript
describe('Clock', function() {
|
|
const NODE_JS =
|
|
typeof process !== 'undefined' &&
|
|
process.versions &&
|
|
typeof process.versions.node === 'string';
|
|
|
|
it('does not replace setTimeout until it is installed', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
|
|
fakeGlobal = { setTimeout: fakeSetTimeout },
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['scheduleFunction']
|
|
),
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
|
|
expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0);
|
|
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
|
|
|
fakeSetTimeout.calls.reset();
|
|
|
|
clock.install();
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled();
|
|
expect(fakeSetTimeout).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not replace clearTimeout until it is installed', function() {
|
|
const fakeClearTimeout = jasmine.createSpy('global cleartimeout'),
|
|
fakeGlobal = { clearTimeout: fakeClearTimeout },
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['removeFunctionWithId']
|
|
),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.clearTimeout('foo');
|
|
|
|
expect(fakeClearTimeout).toHaveBeenCalledWith('foo');
|
|
expect(
|
|
delayedFunctionScheduler.removeFunctionWithId
|
|
).not.toHaveBeenCalled();
|
|
|
|
fakeClearTimeout.calls.reset();
|
|
|
|
clock.install();
|
|
fakeGlobal.clearTimeout('foo');
|
|
|
|
expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalled();
|
|
expect(fakeClearTimeout).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not replace setInterval until it is installed', function() {
|
|
const fakeSetInterval = jasmine.createSpy('global setInterval'),
|
|
fakeGlobal = { setInterval: fakeSetInterval },
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['scheduleFunction']
|
|
),
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.setInterval(delayedFn, 0);
|
|
|
|
expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 0);
|
|
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
|
|
|
fakeSetInterval.calls.reset();
|
|
|
|
clock.install();
|
|
fakeGlobal.setInterval(delayedFn, 0);
|
|
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled();
|
|
expect(fakeSetInterval).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not replace clearInterval until it is installed', function() {
|
|
const fakeClearInterval = jasmine.createSpy('global clearinterval'),
|
|
fakeGlobal = { clearInterval: fakeClearInterval },
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['removeFunctionWithId']
|
|
),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.clearInterval('foo');
|
|
|
|
expect(fakeClearInterval).toHaveBeenCalledWith('foo');
|
|
expect(
|
|
delayedFunctionScheduler.removeFunctionWithId
|
|
).not.toHaveBeenCalled();
|
|
|
|
fakeClearInterval.calls.reset();
|
|
|
|
clock.install();
|
|
fakeGlobal.clearInterval('foo');
|
|
|
|
expect(delayedFunctionScheduler.removeFunctionWithId).toHaveBeenCalled();
|
|
expect(fakeClearInterval).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not install if the current setTimeout is not the original function on the global', function() {
|
|
const originalFakeSetTimeout = function() {},
|
|
replacedSetTimeout = function() {},
|
|
fakeGlobal = { setTimeout: originalFakeSetTimeout },
|
|
delayedFunctionSchedulerFactory = jasmine.createSpy(
|
|
'delayedFunctionSchedulerFactory'
|
|
),
|
|
mockDate = {},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
delayedFunctionSchedulerFactory,
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.setTimeout = replacedSetTimeout;
|
|
|
|
expect(function() {
|
|
clock.install();
|
|
}).toThrowError(/unable to install/);
|
|
|
|
expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled();
|
|
expect(fakeGlobal.setTimeout).toBe(replacedSetTimeout);
|
|
});
|
|
|
|
it('does not install if the current clearTimeout is not the original function on the global', function() {
|
|
const originalFakeClearTimeout = function() {},
|
|
replacedClearTimeout = function() {},
|
|
fakeGlobal = { clearTimeout: originalFakeClearTimeout },
|
|
delayedFunctionSchedulerFactory = jasmine.createSpy(
|
|
'delayedFunctionSchedulerFactory'
|
|
),
|
|
mockDate = {},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
delayedFunctionSchedulerFactory,
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.clearTimeout = replacedClearTimeout;
|
|
|
|
expect(function() {
|
|
clock.install();
|
|
}).toThrowError(/unable to install/);
|
|
|
|
expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled();
|
|
expect(fakeGlobal.clearTimeout).toBe(replacedClearTimeout);
|
|
});
|
|
|
|
it('does not install if the current setInterval is not the original function on the global', function() {
|
|
const originalFakeSetInterval = function() {},
|
|
replacedSetInterval = function() {},
|
|
fakeGlobal = { setInterval: originalFakeSetInterval },
|
|
delayedFunctionSchedulerFactory = jasmine.createSpy(
|
|
'delayedFunctionSchedulerFactory'
|
|
),
|
|
mockDate = {},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
delayedFunctionSchedulerFactory,
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.setInterval = replacedSetInterval;
|
|
|
|
expect(function() {
|
|
clock.install();
|
|
}).toThrowError(/unable to install/);
|
|
|
|
expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled();
|
|
expect(fakeGlobal.setInterval).toBe(replacedSetInterval);
|
|
});
|
|
|
|
it('does not install if the current clearInterval is not the original function on the global', function() {
|
|
const originalFakeClearInterval = function() {},
|
|
replacedClearInterval = function() {},
|
|
fakeGlobal = { clearInterval: originalFakeClearInterval },
|
|
delayedFunctionSchedulerFactory = jasmine.createSpy(
|
|
'delayedFunctionSchedulerFactory'
|
|
),
|
|
mockDate = {},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
delayedFunctionSchedulerFactory,
|
|
mockDate
|
|
);
|
|
|
|
fakeGlobal.clearInterval = replacedClearInterval;
|
|
|
|
expect(function() {
|
|
clock.install();
|
|
}).toThrowError(/unable to install/);
|
|
|
|
expect(delayedFunctionSchedulerFactory).not.toHaveBeenCalled();
|
|
expect(fakeGlobal.clearInterval).toBe(replacedClearInterval);
|
|
});
|
|
|
|
it('restores the global timer functions on uninstall', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
|
|
fakeClearTimeout = jasmine.createSpy('global clearTimeout'),
|
|
fakeSetInterval = jasmine.createSpy('global setInterval'),
|
|
fakeClearInterval = jasmine.createSpy('global clearInterval'),
|
|
fakeGlobal = {
|
|
setTimeout: fakeSetTimeout,
|
|
clearTimeout: fakeClearTimeout,
|
|
setInterval: fakeSetInterval,
|
|
clearInterval: fakeClearInterval
|
|
},
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['scheduleFunction', 'reset']
|
|
),
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
clock.uninstall();
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
fakeGlobal.clearTimeout('foo');
|
|
fakeGlobal.setInterval(delayedFn, 10);
|
|
fakeGlobal.clearInterval('bar');
|
|
|
|
expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0);
|
|
expect(fakeClearTimeout).toHaveBeenCalledWith('foo');
|
|
expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10);
|
|
expect(fakeClearInterval).toHaveBeenCalledWith('bar');
|
|
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('can be installed for the duration of a passed in function and uninstalled when done', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
|
|
fakeClearTimeout = jasmine.createSpy('global clearTimeout'),
|
|
fakeSetInterval = jasmine.createSpy('global setInterval'),
|
|
fakeClearInterval = jasmine.createSpy('global clearInterval'),
|
|
fakeGlobal = {
|
|
setTimeout: fakeSetTimeout,
|
|
clearTimeout: fakeClearTimeout,
|
|
setInterval: fakeSetInterval,
|
|
clearInterval: fakeClearInterval
|
|
},
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['scheduleFunction', 'reset', 'removeFunctionWithId']
|
|
),
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
let passedFunctionCalled = false;
|
|
|
|
clock.withMock(function() {
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
fakeGlobal.clearTimeout('foo');
|
|
fakeGlobal.setInterval(delayedFn, 10);
|
|
fakeGlobal.clearInterval('bar');
|
|
passedFunctionCalled = true;
|
|
});
|
|
|
|
expect(passedFunctionCalled).toBe(true);
|
|
|
|
expect(fakeSetTimeout).not.toHaveBeenCalled();
|
|
expect(fakeClearTimeout).not.toHaveBeenCalled();
|
|
expect(fakeSetInterval).not.toHaveBeenCalled();
|
|
expect(fakeClearInterval).not.toHaveBeenCalled();
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled();
|
|
|
|
delayedFunctionScheduler.scheduleFunction.calls.reset();
|
|
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
fakeGlobal.clearTimeout('foo');
|
|
fakeGlobal.setInterval(delayedFn, 10);
|
|
fakeGlobal.clearInterval('bar');
|
|
|
|
expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0);
|
|
expect(fakeClearTimeout).toHaveBeenCalledWith('foo');
|
|
expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10);
|
|
expect(fakeClearInterval).toHaveBeenCalledWith('bar');
|
|
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('can be installed for the duration of a passed in function and uninstalled if an error is thrown', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('global setTimeout'),
|
|
fakeClearTimeout = jasmine.createSpy('global clearTimeout'),
|
|
fakeSetInterval = jasmine.createSpy('global setInterval'),
|
|
fakeClearInterval = jasmine.createSpy('global clearInterval'),
|
|
fakeGlobal = {
|
|
setTimeout: fakeSetTimeout,
|
|
clearTimeout: fakeClearTimeout,
|
|
setInterval: fakeSetInterval,
|
|
clearInterval: fakeClearInterval
|
|
},
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['scheduleFunction', 'reset', 'removeFunctionWithId']
|
|
),
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
let passedFunctionCalled = false;
|
|
|
|
expect(function() {
|
|
clock.withMock(function() {
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
fakeGlobal.clearTimeout('foo');
|
|
fakeGlobal.setInterval(delayedFn, 10);
|
|
fakeGlobal.clearInterval('bar');
|
|
passedFunctionCalled = true;
|
|
throw 'oops';
|
|
});
|
|
}).toThrow('oops');
|
|
|
|
expect(passedFunctionCalled).toBe(true);
|
|
|
|
expect(fakeSetTimeout).not.toHaveBeenCalled();
|
|
expect(fakeClearTimeout).not.toHaveBeenCalled();
|
|
expect(fakeSetInterval).not.toHaveBeenCalled();
|
|
expect(fakeClearInterval).not.toHaveBeenCalled();
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalled();
|
|
|
|
delayedFunctionScheduler.scheduleFunction.calls.reset();
|
|
|
|
fakeGlobal.setTimeout(delayedFn, 0);
|
|
fakeGlobal.clearTimeout('foo');
|
|
fakeGlobal.setInterval(delayedFn, 10);
|
|
fakeGlobal.clearInterval('bar');
|
|
|
|
expect(fakeSetTimeout).toHaveBeenCalledWith(delayedFn, 0);
|
|
expect(fakeClearTimeout).toHaveBeenCalledWith('foo');
|
|
expect(fakeSetInterval).toHaveBeenCalledWith(delayedFn, 10);
|
|
expect(fakeClearInterval).toHaveBeenCalledWith('bar');
|
|
expect(delayedFunctionScheduler.scheduleFunction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('identifies its timing functions', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('global setTimeout');
|
|
const fakeGlobal = { setTimeout: fakeSetTimeout };
|
|
const delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['scheduleFunction']
|
|
);
|
|
const mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
};
|
|
const clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
clock.install();
|
|
|
|
expect(
|
|
fakeGlobal.setTimeout[privateUnderTest.Clock.IsMockClockTimingFn]
|
|
).toEqual(true);
|
|
expect(
|
|
fakeGlobal.clearTimeout[privateUnderTest.Clock.IsMockClockTimingFn]
|
|
).toEqual(true);
|
|
expect(
|
|
fakeGlobal.setInterval[privateUnderTest.Clock.IsMockClockTimingFn]
|
|
).toEqual(true);
|
|
expect(
|
|
fakeGlobal.clearInterval[privateUnderTest.Clock.IsMockClockTimingFn]
|
|
).toEqual(true);
|
|
});
|
|
|
|
describe('setTimeout', function() {
|
|
it('schedules the delayed function with the fake timer', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('setTimeout'),
|
|
scheduleFunction = jasmine.createSpy('scheduleFunction'),
|
|
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
|
|
fakeGlobal = { setTimeout: fakeSetTimeout },
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
),
|
|
timeout = new clock.FakeTimeout();
|
|
|
|
clock.install();
|
|
clock.setTimeout(delayedFn, 0, 'a', 'b');
|
|
|
|
expect(fakeSetTimeout).not.toHaveBeenCalled();
|
|
|
|
if (!NODE_JS) {
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(
|
|
delayedFn,
|
|
0,
|
|
['a', 'b']
|
|
);
|
|
} else {
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(
|
|
delayedFn,
|
|
0,
|
|
['a', 'b'],
|
|
false,
|
|
timeout
|
|
);
|
|
}
|
|
});
|
|
|
|
it('returns an id for the delayed function', function() {
|
|
const fakeSetTimeout = jasmine.createSpy('setTimeout'),
|
|
scheduleId = 123,
|
|
scheduleFunction = jasmine
|
|
.createSpy('scheduleFunction')
|
|
.and.returnValue(scheduleId),
|
|
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
|
|
fakeGlobal = { setTimeout: fakeSetTimeout },
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
const timeout = clock.setTimeout(delayedFn, 0);
|
|
|
|
if (!NODE_JS) {
|
|
expect(timeout).toEqual(123);
|
|
} else {
|
|
expect(timeout.constructor.name).toEqual('FakeTimeout');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('clearTimeout', function() {
|
|
it('clears the scheduled function with the scheduler', function() {
|
|
const fakeClearTimeout = jasmine.createSpy('clearTimeout'),
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['removeFunctionWithId']
|
|
),
|
|
fakeGlobal = { setTimeout: fakeClearTimeout },
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
clock.clearTimeout(123);
|
|
|
|
expect(fakeClearTimeout).not.toHaveBeenCalled();
|
|
expect(
|
|
delayedFunctionScheduler.removeFunctionWithId
|
|
).toHaveBeenCalledWith(123);
|
|
});
|
|
});
|
|
|
|
describe('setInterval', function() {
|
|
it('schedules the delayed function with the fake timer', function() {
|
|
const fakeSetInterval = jasmine.createSpy('setInterval'),
|
|
scheduleFunction = jasmine.createSpy('scheduleFunction'),
|
|
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
|
|
fakeGlobal = { setInterval: fakeSetInterval },
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
),
|
|
timeout = new clock.FakeTimeout();
|
|
|
|
clock.install();
|
|
clock.setInterval(delayedFn, 0, 'a', 'b');
|
|
|
|
expect(fakeSetInterval).not.toHaveBeenCalled();
|
|
|
|
if (!NODE_JS) {
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(
|
|
delayedFn,
|
|
0,
|
|
['a', 'b'],
|
|
true
|
|
);
|
|
} else {
|
|
expect(delayedFunctionScheduler.scheduleFunction).toHaveBeenCalledWith(
|
|
delayedFn,
|
|
0,
|
|
['a', 'b'],
|
|
true,
|
|
timeout
|
|
);
|
|
}
|
|
});
|
|
|
|
it('returns an id for the delayed function', function() {
|
|
const fakeSetInterval = jasmine.createSpy('setInterval'),
|
|
scheduleId = 123,
|
|
scheduleFunction = jasmine
|
|
.createSpy('scheduleFunction')
|
|
.and.returnValue(scheduleId),
|
|
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
|
|
fakeGlobal = { setInterval: fakeSetInterval },
|
|
delayedFn = jasmine.createSpy('delayedFn'),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
const interval = clock.setInterval(delayedFn, 0);
|
|
|
|
if (!NODE_JS) {
|
|
expect(interval).toEqual(123);
|
|
} else {
|
|
expect(interval.constructor.name).toEqual('FakeTimeout');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('clearInterval', function() {
|
|
it('clears the scheduled function with the scheduler', function() {
|
|
const clearInterval = jasmine.createSpy('clearInterval'),
|
|
delayedFunctionScheduler = jasmine.createSpyObj(
|
|
'delayedFunctionScheduler',
|
|
['removeFunctionWithId']
|
|
),
|
|
fakeGlobal = { setInterval: clearInterval },
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
fakeGlobal,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
clock.clearInterval(123);
|
|
|
|
expect(clearInterval).not.toHaveBeenCalled();
|
|
expect(
|
|
delayedFunctionScheduler.removeFunctionWithId
|
|
).toHaveBeenCalledWith(123);
|
|
});
|
|
});
|
|
|
|
it('gives you a friendly reminder if the Clock is not installed and you tick', function() {
|
|
const clock = new privateUnderTest.Clock(
|
|
{},
|
|
jasmine.createSpyObj('delayedFunctionScheduler', ['tick'])
|
|
);
|
|
expect(function() {
|
|
clock.tick(50);
|
|
}).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('Clock (acceptance)', function() {
|
|
it('can run setTimeouts/setIntervals synchronously', function() {
|
|
const delayedFn1 = jasmine.createSpy('delayedFn1'),
|
|
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
|
delayedFn3 = jasmine.createSpy('delayedFn3'),
|
|
recurring1 = jasmine.createSpy('recurring1'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: setTimeout },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
clock.setTimeout(delayedFn1, 0);
|
|
const intervalId = clock.setInterval(recurring1, 50);
|
|
clock.setTimeout(delayedFn2, 100);
|
|
clock.setTimeout(delayedFn3, 200);
|
|
|
|
expect(delayedFn1).not.toHaveBeenCalled();
|
|
expect(delayedFn2).not.toHaveBeenCalled();
|
|
expect(delayedFn3).not.toHaveBeenCalled();
|
|
|
|
clock.tick(0);
|
|
|
|
expect(delayedFn1).toHaveBeenCalled();
|
|
expect(delayedFn2).not.toHaveBeenCalled();
|
|
expect(delayedFn3).not.toHaveBeenCalled();
|
|
|
|
clock.tick(50);
|
|
|
|
expect(recurring1).toHaveBeenCalled();
|
|
expect(recurring1.calls.count()).toBe(1);
|
|
expect(delayedFn2).not.toHaveBeenCalled();
|
|
expect(delayedFn3).not.toHaveBeenCalled();
|
|
|
|
clock.tick(50);
|
|
|
|
expect(recurring1.calls.count()).toBe(2);
|
|
expect(delayedFn2).toHaveBeenCalled();
|
|
expect(delayedFn3).not.toHaveBeenCalled();
|
|
|
|
clock.tick(100);
|
|
|
|
expect(recurring1.calls.count()).toBe(4);
|
|
expect(delayedFn3).toHaveBeenCalled();
|
|
|
|
clock.clearInterval(intervalId);
|
|
clock.tick(50);
|
|
|
|
expect(recurring1.calls.count()).toBe(4);
|
|
});
|
|
|
|
describe('auto tick mode', () => {
|
|
let delayedFunctionScheduler;
|
|
let mockDate;
|
|
let clock;
|
|
|
|
beforeEach(() => {
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler();
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
};
|
|
// window setTimeout to window to make firefox happy
|
|
const _setTimeout =
|
|
typeof window !== 'undefined' ? setTimeout.bind(window) : setTimeout;
|
|
// passing a fake global allows us to preserve the real timing functions for use in tests
|
|
const _global = { setTimeout: _setTimeout, setInterval: setInterval };
|
|
clock = new privateUnderTest.Clock(
|
|
_global,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
clock.install().autoTick();
|
|
});
|
|
|
|
afterEach(() => {
|
|
clock.uninstall();
|
|
});
|
|
|
|
it('flushes microtask queue between macrotasks', async () => {
|
|
const log = [];
|
|
await new Promise(r => clock.setTimeout(r, 10)).then(() => {
|
|
log.push(1);
|
|
Promise.resolve().then(() => log.push(2));
|
|
Promise.resolve().then(() => log.push(3));
|
|
});
|
|
await new Promise(r => clock.setTimeout(r, 10)).then(() => {
|
|
log.push(4);
|
|
Promise.resolve().then(() => log.push(5));
|
|
});
|
|
expect(log).toEqual([1, 2, 3, 4, 5]);
|
|
});
|
|
|
|
it('can run setTimeouts/setIntervals asynchronously', function() {
|
|
const recurring = jasmine.createSpy('recurring'),
|
|
fn1 = jasmine.createSpy('fn1'),
|
|
fn2 = jasmine.createSpy('fn2'),
|
|
fn3 = jasmine.createSpy('fn3');
|
|
|
|
const intervalId = clock.setInterval(recurring, 50);
|
|
// In a microtask, add some timeouts.
|
|
Promise.resolve()
|
|
.then(function() {
|
|
return new Promise(function(resolve) {
|
|
clock.setTimeout(resolve, 25);
|
|
});
|
|
})
|
|
.then(function() {
|
|
fn1();
|
|
return new Promise(function(resolve) {
|
|
clock.setTimeout(resolve, 200);
|
|
});
|
|
})
|
|
.then(function() {
|
|
fn2();
|
|
return new Promise(function(resolve) {
|
|
clock.setTimeout(resolve, 100);
|
|
});
|
|
})
|
|
.then(function() {
|
|
fn3();
|
|
});
|
|
|
|
expect(recurring).not.toHaveBeenCalled();
|
|
expect(fn1).not.toHaveBeenCalled();
|
|
expect(fn2).not.toHaveBeenCalled();
|
|
expect(fn3).not.toHaveBeenCalled();
|
|
|
|
return new Promise(resolve => clock.setTimeout(resolve, 50))
|
|
.then(function() {
|
|
expect(recurring).toHaveBeenCalledTimes(1);
|
|
expect(fn1).toHaveBeenCalled();
|
|
expect(fn2).not.toHaveBeenCalled();
|
|
expect(fn3).not.toHaveBeenCalled();
|
|
|
|
return new Promise(resolve => clock.setTimeout(resolve, 175));
|
|
})
|
|
.then(function() {
|
|
expect(recurring).toHaveBeenCalledTimes(4);
|
|
expect(fn1).toHaveBeenCalled();
|
|
expect(fn2).toHaveBeenCalled();
|
|
expect(fn3).not.toHaveBeenCalled();
|
|
|
|
clock.clearInterval(intervalId);
|
|
return new Promise(resolve => clock.setTimeout(resolve, 100));
|
|
})
|
|
.then(function() {
|
|
expect(recurring).toHaveBeenCalledTimes(4);
|
|
expect(fn1).toHaveBeenCalled();
|
|
expect(fn2).toHaveBeenCalled();
|
|
expect(fn3).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
it('aborts auto ticking when uninstalled, even if installed again synchonrously', async () => {
|
|
clock.uninstall();
|
|
clock.install();
|
|
|
|
let resolved = false;
|
|
const promise = new Promise(resolve => {
|
|
clock.setTimeout(resolve, 1);
|
|
}).then(() => {
|
|
resolved = true;
|
|
});
|
|
|
|
// wait some real time and verify that the clock did not flush the timer above automatically
|
|
await new Promise(resolve => setTimeout(resolve, 2));
|
|
expect(resolved).toBe(false);
|
|
|
|
// enabling auto tick again will flush the timer
|
|
clock.autoTick();
|
|
await expectAsync(promise).toBeResolved();
|
|
});
|
|
|
|
it('speeds up the execution of the timers in all browsers', async () => {
|
|
const startTimeMs = performance.now() / 1000;
|
|
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
|
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
|
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
|
await new Promise(resolve => clock.setTimeout(resolve, 5000));
|
|
const endTimeMs = performance.now() / 1000;
|
|
// Ensure we didn't take 20s to complete the awaits above and, in fact, can do it in a fraction of a second
|
|
expect(endTimeMs - startTimeMs).toBeLessThan(100);
|
|
});
|
|
|
|
it('is easy to test async functions with interleaved timers and microtasks', async () => {
|
|
async function blackBoxWithLotsOfAsyncStuff() {
|
|
await new Promise(r => clock.setTimeout(r, 10));
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
await new Promise(r => clock.setTimeout(r, 20));
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
return 'done';
|
|
}
|
|
const result = await blackBoxWithLotsOfAsyncStuff();
|
|
expect(result).toBe('done');
|
|
});
|
|
});
|
|
|
|
it('can clear a previously set timeout', function() {
|
|
const clearedFn = jasmine.createSpy('clearedFn'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: function() {} },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
const timeoutId = clock.setTimeout(clearedFn, 100);
|
|
expect(clearedFn).not.toHaveBeenCalled();
|
|
|
|
clock.clearTimeout(timeoutId);
|
|
clock.tick(100);
|
|
|
|
expect(clearedFn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("can clear a previously set interval using that interval's handler", function() {
|
|
const spy = jasmine.createSpy('spy'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setInterval: function() {} },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
const intervalId = clock.setInterval(function() {
|
|
spy();
|
|
clock.clearInterval(intervalId);
|
|
}, 100);
|
|
clock.tick(200);
|
|
|
|
expect(spy.calls.count()).toEqual(1);
|
|
});
|
|
|
|
it('correctly schedules functions after the Clock has advanced', function() {
|
|
const delayedFn1 = jasmine.createSpy('delayedFn1'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: function() {} },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
clock.tick(100);
|
|
clock.setTimeout(delayedFn1, 10, ['some', 'arg']);
|
|
clock.tick(5);
|
|
expect(delayedFn1).not.toHaveBeenCalled();
|
|
clock.tick(5);
|
|
expect(delayedFn1).toHaveBeenCalled();
|
|
});
|
|
|
|
it('correctly schedules functions while the Clock is advancing', function() {
|
|
const delayedFn1 = jasmine.createSpy('delayedFn1'),
|
|
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: function() {} },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
delayedFn1.and.callFake(function() {
|
|
clock.setTimeout(delayedFn2, 0);
|
|
});
|
|
clock.install();
|
|
clock.setTimeout(delayedFn1, 5);
|
|
|
|
clock.tick(5);
|
|
expect(delayedFn1).toHaveBeenCalled();
|
|
expect(delayedFn2).not.toHaveBeenCalled();
|
|
|
|
clock.tick();
|
|
expect(delayedFn2).toHaveBeenCalled();
|
|
});
|
|
|
|
it('correctly calls functions scheduled while the Clock is advancing', function() {
|
|
const delayedFn1 = jasmine.createSpy('delayedFn1'),
|
|
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: function() {} },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
delayedFn1.and.callFake(function() {
|
|
clock.setTimeout(delayedFn2, 1);
|
|
});
|
|
clock.install();
|
|
clock.setTimeout(delayedFn1, 5);
|
|
|
|
clock.tick(6);
|
|
expect(delayedFn1).toHaveBeenCalled();
|
|
expect(delayedFn2).toHaveBeenCalled();
|
|
});
|
|
|
|
it('correctly schedules functions scheduled while the Clock is advancing but after the Clock is uninstalled', function() {
|
|
const delayedFn1 = jasmine.createSpy('delayedFn1'),
|
|
delayedFn2 = jasmine.createSpy('delayedFn2'),
|
|
delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
mockDate = {
|
|
install: function() {},
|
|
tick: function() {},
|
|
uninstall: function() {}
|
|
},
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: function() {} },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
delayedFn1.and.callFake(function() {
|
|
clock.uninstall();
|
|
clock.install();
|
|
clock.setTimeout(delayedFn2, 0);
|
|
});
|
|
|
|
clock.install();
|
|
clock.setTimeout(delayedFn1, 1);
|
|
|
|
clock.tick(1);
|
|
expect(delayedFn1).toHaveBeenCalled();
|
|
expect(delayedFn2).not.toHaveBeenCalled();
|
|
|
|
clock.tick(1);
|
|
expect(delayedFn2).toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not mock the Date object by default', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: setTimeout },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
expect(global.Date).toEqual(Date);
|
|
|
|
const now = new global.Date().getTime();
|
|
|
|
clock.tick(50);
|
|
|
|
expect(new global.Date().getTime() - now).not.toEqual(50);
|
|
});
|
|
|
|
it('mocks the Date object and sets it to current time', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: setTimeout },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install().mockDate();
|
|
|
|
const now = new global.Date().getTime();
|
|
|
|
clock.tick(50);
|
|
|
|
expect(new global.Date().getTime() - now).toEqual(50);
|
|
|
|
let timeoutDate = 0;
|
|
clock.setTimeout(function() {
|
|
timeoutDate = new global.Date().getTime();
|
|
}, 100);
|
|
|
|
clock.tick(100);
|
|
|
|
expect(timeoutDate - now).toEqual(150);
|
|
});
|
|
|
|
it('mocks the Date object and sets it to a given time', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: setTimeout },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
),
|
|
baseTime = new Date(2013, 9, 23);
|
|
|
|
clock.install().mockDate(baseTime);
|
|
|
|
const now = new global.Date().getTime();
|
|
|
|
expect(now).toEqual(baseTime.getTime());
|
|
|
|
clock.tick(50);
|
|
|
|
expect(new global.Date().getTime()).toEqual(baseTime.getTime() + 50);
|
|
|
|
let timeoutDate = 0;
|
|
clock.setTimeout(function() {
|
|
timeoutDate = new global.Date().getTime();
|
|
}, 100);
|
|
|
|
clock.tick(100);
|
|
|
|
expect(timeoutDate).toEqual(baseTime.getTime() + 150);
|
|
});
|
|
|
|
it('throws mockDate is called with a non-Date', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: setTimeout },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
expect(() => clock.mockDate(12345)).toThrowError(
|
|
'The argument to jasmine.clock().mockDate(), if specified, should be ' +
|
|
'a Date instance.'
|
|
);
|
|
});
|
|
|
|
it('mocks the Date object and updates the date per delayed function', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
{ setTimeout: setTimeout },
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
),
|
|
baseTime = new Date();
|
|
|
|
clock.install().mockDate(baseTime);
|
|
|
|
const actualTimes = [];
|
|
const pushCurrentTime = function() {
|
|
actualTimes.push(global.Date().getTime());
|
|
};
|
|
delayedFunctionScheduler.scheduleFunction(pushCurrentTime);
|
|
delayedFunctionScheduler.scheduleFunction(pushCurrentTime, 1);
|
|
delayedFunctionScheduler.scheduleFunction(pushCurrentTime, 3);
|
|
|
|
clock.tick(1);
|
|
expect(global.Date().getTime()).toEqual(baseTime.getTime() + 1);
|
|
|
|
clock.tick(3);
|
|
expect(global.Date().getTime()).toEqual(baseTime.getTime() + 4);
|
|
|
|
clock.tick(1);
|
|
expect(global.Date().getTime()).toEqual(baseTime.getTime() + 5);
|
|
|
|
expect(actualTimes).toEqual([
|
|
baseTime.getTime(),
|
|
baseTime.getTime() + 1,
|
|
baseTime.getTime() + 3
|
|
]);
|
|
});
|
|
|
|
it('correctly clears a scheduled timeout while the Clock is advancing', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date, setTimeout: undefined },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
global,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
let timerId2;
|
|
|
|
global.setTimeout(function() {
|
|
global.clearTimeout(timerId2);
|
|
}, 100);
|
|
|
|
timerId2 = global.setTimeout(fail, 100);
|
|
|
|
clock.tick(100);
|
|
});
|
|
|
|
it('correctly clears a scheduled interval while the Clock is advancing', function() {
|
|
const delayedFunctionScheduler = new privateUnderTest.DelayedFunctionScheduler(),
|
|
global = { Date: Date, setTimeout: undefined },
|
|
mockDate = new privateUnderTest.MockDate(global),
|
|
clock = new privateUnderTest.Clock(
|
|
global,
|
|
function() {
|
|
return delayedFunctionScheduler;
|
|
},
|
|
mockDate
|
|
);
|
|
|
|
clock.install();
|
|
|
|
let timerId2;
|
|
global.setInterval(function() {
|
|
global.clearInterval(timerId2);
|
|
}, 100);
|
|
|
|
timerId2 = global.setInterval(fail, 100);
|
|
|
|
clock.tick(400);
|
|
});
|
|
|
|
describe('Warning about monkey patching', function() {
|
|
for (const name of ['tick', 'mockDate', 'install', 'uninstall']) {
|
|
it(`warns if Clock#${name} is monkey patched`, function() {
|
|
spyOn(console, 'error');
|
|
const clock = new privateUnderTest.Clock({}, function() {}, {});
|
|
const patch = {};
|
|
clock[name] = patch;
|
|
|
|
// eslint-disable-next-line no-console
|
|
expect(console.error).toHaveBeenCalledOnceWith(
|
|
jasmine.stringContaining('DEPRECATION: Monkey patching detected.')
|
|
);
|
|
// eslint-disable-next-line no-console
|
|
expect(console.error).toHaveBeenCalledOnceWith(
|
|
jasmine.stringContaining('ClockSpec.js')
|
|
);
|
|
expect(clock[name]).toBe(patch);
|
|
});
|
|
}
|
|
});
|
|
});
|