Skip to content

Instantly share code, notes, and snippets.

@dralletje
Created August 8, 2017 23:25
Show Gist options
  • Select an option

  • Save dralletje/52cf89e93d22d235de4d2a854f90ab21 to your computer and use it in GitHub Desktop.

Select an option

Save dralletje/52cf89e93d22d235de4d2a854f90ab21 to your computer and use it in GitHub Desktop.
// @flow
const useful_times = {
ten_am_monday: 1500884100000,
};
// '2017-07-27T21:29:45.301'
const base_time_timestamp = useful_times.ten_am_monday;
const Original_Date = Date;
const Mock_Date = Object.assign(
function(value = Mock_Date.now()) {
return new Original_Date(value);
},
{
mocked_current_time: base_time_timestamp,
now: () => {
const time = Mock_Date.mocked_current_time;
Mock_Date.mocked_current_time = time + 1;
return time;
},
UTC: Original_Date.UTC,
prototype: Original_Date.prototype,
},
);
global.Date = Mock_Date;
type TTimer = {
id: number,
type: 'interval' | 'timeout' | 'immediate',
projected_time: number, // timestamp it is supposed to have it's next run
duration: number, // Necessary for interval to repeat
fn_to_execute: () => mixed,
};
class TimeMockerClass {
initial_id = 1;
mocked_timers = ([]: Array<TTimer>);
// mocked_nextTicks = [];
mocks = {
setInterval: _setInterval => (fn, duration) => {
this.mocked_timers.push({
id: this.initial_id,
type: 'interval',
projected_time: Date.now() + duration,
duration: duration,
fn_to_execute: fn,
});
this.initial_id = this.initial_id + 1;
return this.initial_id;
},
setImmediate: _setImmediate => fn => {
fn();
// this.mocked_nextTicks.push({
// fn: fn,
// });
},
setTimeout: _setTimeout => (fn, duration) => {
this.mocked_timers.push({
id: this.initial_id,
type: 'timeout',
projected_time: Date.now() + duration,
duration: duration,
fn_to_execute: fn,
});
this.initial_id = this.initial_id + 1;
return this.initial_id;
},
clearTimeout: _clearTimeout => id => {
this.mocked_timers = this.mocked_timers.filter(x => x.id !== id);
},
clearInterval: _clearInterval => id => {
this.mocked_timers = this.mocked_timers.filter(x => x.id !== id);
},
};
original_functions = {};
active = false;
constructor(obj) {
Object.entries(this.mocks).forEach(([key, mockFn]) => {
this.original_functions[key] = obj[key];
const with_original = mockFn(obj[key]);
obj[key] = (...args) => {
if (this.active) {
return with_original(...args);
} else {
return this.original_functions[key](...args);
}
};
});
}
activate() {
this.active = true;
Mock_Date.mocked_current_time = base_time_timestamp;
}
deactivate() {
this.active = false;
}
mock_forward_time = async (to_date: Date) => {
const timers = this.mocked_timers
.filter(timer => timer.projected_time <= to_date)
// TODO Make sure this is sorting the right way
.sort((a, b) => a.projected_time - b.projected_time);
const current = timers[0];
if (!current) return;
this.mocked_timers = this.mocked_timers.filter(x => x.id !== current.id);
Mock_Date.mocked_current_time = current.projected_time;
const x = current.fn_to_execute();
// Give it another second to execute... wondering if there is another way
// to wait for all async/await calls to finish :(
await new Promise(yell => {
const fn = this.original_functions.setTimeout;
fn(() => yell(), 20);
});
return this.mock_forward_time(to_date);
};
}
// global.nextTick = fn => {
// console.log('fn:', fn);
// throw new Error(`Nexttick`);
// };
global.TimeMocker = new TimeMockerClass(global);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment