aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-07-02 22:42:13 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-07-02 22:42:13 -0700
commitf0a795b568b741f71945e1078b87355d3217cc23 (patch)
tree25854f39b097f5cd9fbb0c53f11bbd24a7469b59
parentaa38e51afb73dab3071addc07f82fd96153ff450 (diff)
downloadbun-f0a795b568b741f71945e1078b87355d3217cc23.tar.gz
bun-f0a795b568b741f71945e1078b87355d3217cc23.tar.zst
bun-f0a795b568b741f71945e1078b87355d3217cc23.zip
Stub out `useFakeTimers` and `useRealTimers`
-rw-r--r--packages/bun-types/bun-test.d.ts30
-rw-r--r--src/bun.js/bindings/JSMockFunction.cpp12
-rw-r--r--src/bun.js/test/jest.zig31
-rw-r--r--test/js/bun/test/test-timers.test.ts35
4 files changed, 96 insertions, 12 deletions
diff --git a/packages/bun-types/bun-test.d.ts b/packages/bun-types/bun-test.d.ts
index 156585766..5182f7e93 100644
--- a/packages/bun-types/bun-test.d.ts
+++ b/packages/bun-types/bun-test.d.ts
@@ -29,6 +29,36 @@ declare module "bun:test" {
<T extends AnyFunction>(Function: T): Mock<T>;
};
+ /**
+ * Control the system time used by:
+ * - `Date.now()`
+ * - `new Date()`
+ * - `Intl.DateTimeFormat().format()`
+ *
+ * In the future, we may add support for more functions, but we haven't done that yet.
+ *
+ * @param now The time to set the system time to. If not provided, the system time will be reset.
+ * @returns `this`
+ * @since v0.6.13
+ *
+ * ## Set Date to a specific time
+ *
+ * ```js
+ * import { setSystemTime } from 'bun:test';
+ *
+ * setSystemTime(new Date('2020-01-01T00:00:00.000Z'));
+ * console.log(new Date().toISOString()); // 2020-01-01T00:00:00.000Z
+ * ```
+ * ## Reset Date to the current time
+ *
+ * ```js
+ * import { setSystemTime } from 'bun:test';
+ *
+ * setSystemTime();
+ * ```
+ */
+ export function setSystemTime(now?: Date | number): ThisType<void>;
+
interface Jest {
restoreAllMocks(): void;
fn<T extends AnyFunction>(func?: T): Mock<T>;
diff --git a/src/bun.js/bindings/JSMockFunction.cpp b/src/bun.js/bindings/JSMockFunction.cpp
index 0e24e761c..3a84f0139 100644
--- a/src/bun.js/bindings/JSMockFunction.cpp
+++ b/src/bun.js/bindings/JSMockFunction.cpp
@@ -66,6 +66,18 @@ JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockRejectedValueOnce);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionWithImplementationCleanup);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionWithImplementation);
+// This is a stub. Exists so that the same code can be run in Jest
+extern "C" EncodedJSValue JSMock__jsUseFakeTimers(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
+{
+ return JSValue::encode(callFrame->thisValue());
+}
+
+extern "C" EncodedJSValue JSMock__jsUseRealTimers(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
+{
+ globalObject->overridenDateNow = -1;
+ return JSValue::encode(callFrame->thisValue());
+}
+
extern "C" EncodedJSValue JSMock__jsNow(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
{
return JSValue::encode(jsNumber(globalObject->jsDateNow()));
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 727466835..55600ded8 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -333,7 +333,7 @@ pub const Jest = struct {
pub fn Bun__Jest__createTestModuleObject(globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue {
JSC.markBinding(@src());
- const module = JSC.JSValue.createEmptyObject(globalObject, 12);
+ const module = JSC.JSValue.createEmptyObject(globalObject, 13);
const test_fn = JSC.NewFunction(globalObject, ZigString.static("test"), 2, TestScope.call, false);
module.put(
@@ -431,17 +431,40 @@ pub const Jest = struct {
Expect.getConstructor(globalObject),
);
+ const setSystemTime = JSC.NewFunction(globalObject, ZigString.static("setSystemTime"), 0, JSMock__jsSetSystemTime, false);
+ module.put(
+ globalObject,
+ ZigString.static("setSystemTime"),
+ setSystemTime,
+ );
+ const useFakeTimers = JSC.NewFunction(globalObject, ZigString.static("useFakeTimers"), 0, JSMock__jsUseFakeTimers, false);
+ const useRealTimers = JSC.NewFunction(globalObject, ZigString.static("useRealTimers"), 0, JSMock__jsUseRealTimers, false);
+
const mockFn = JSC.NewFunction(globalObject, ZigString.static("fn"), 1, JSMock__jsMockFn, false);
const spyOn = JSC.NewFunction(globalObject, ZigString.static("spyOn"), 2, JSMock__jsSpyOn, false);
const restoreAllMocks = JSC.NewFunction(globalObject, ZigString.static("restoreAllMocks"), 2, JSMock__jsRestoreAllMocks, false);
module.put(globalObject, ZigString.static("mock"), mockFn);
- const jest = JSValue.createEmptyObject(globalObject, 3);
+ const jest = JSValue.createEmptyObject(globalObject, 7);
jest.put(globalObject, ZigString.static("fn"), mockFn);
jest.put(globalObject, ZigString.static("spyOn"), spyOn);
jest.put(globalObject, ZigString.static("restoreAllMocks"), restoreAllMocks);
+ jest.put(
+ globalObject,
+ ZigString.static("setSystemTime"),
+ setSystemTime,
+ );
+ jest.put(
+ globalObject,
+ ZigString.static("useFakeTimers"),
+ useFakeTimers,
+ );
+ jest.put(
+ globalObject,
+ ZigString.static("useRealTimers"),
+ useRealTimers,
+ );
jest.put(globalObject, ZigString.static("now"), JSC.NewFunction(globalObject, ZigString.static("now"), 0, JSMock__jsNow, false));
- jest.put(globalObject, ZigString.static("setSystemTime"), JSC.NewFunction(globalObject, ZigString.static("setSystemTime"), 0, JSMock__jsSetSystemTime, false));
module.put(globalObject, ZigString.static("jest"), jest);
module.put(globalObject, ZigString.static("spyOn"), spyOn);
@@ -462,6 +485,8 @@ pub const Jest = struct {
extern fn JSMock__jsSetSystemTime(*JSC.JSGlobalObject, *JSC.CallFrame) JSC.JSValue;
extern fn JSMock__jsRestoreAllMocks(*JSC.JSGlobalObject, *JSC.CallFrame) JSC.JSValue;
extern fn JSMock__jsSpyOn(*JSC.JSGlobalObject, *JSC.CallFrame) JSC.JSValue;
+ extern fn JSMock__jsUseFakeTimers(*JSC.JSGlobalObject, *JSC.CallFrame) JSC.JSValue;
+ extern fn JSMock__jsUseRealTimers(*JSC.JSGlobalObject, *JSC.CallFrame) JSC.JSValue;
pub fn call(
_: void,
diff --git a/test/js/bun/test/test-timers.test.ts b/test/js/bun/test/test-timers.test.ts
index 64da0abda..963467dee 100644
--- a/test/js/bun/test/test-timers.test.ts
+++ b/test/js/bun/test/test-timers.test.ts
@@ -1,11 +1,28 @@
test("we can go back in time", () => {
- const dateNow = Date.now;
- // jest.useFakeTimers();
- jest.setSystemTime(new Date("2020-01-01T00:00:00.000Z"));
- expect(new Date().toISOString()).toBe("2020-01-01T00:00:00.000Z");
- expect(Date.now()).toBe(1577836800000);
- expect(dateNow).toBe(Date.now);
-
- jest.setSystemTime();
- expect(new Date().toISOString()).not.toBe("2020-01-01T00:00:00.000Z");
+ const DateBeforeMocked = Date;
+ const orig = new Date();
+ orig.setHours(0, 0, 0, 0);
+ jest.useFakeTimers();
+ jest.setSystemTime(new Date("1995-12-19T00:00:00.000Z"));
+
+ expect(new Date().toISOString()).toBe("1995-12-19T00:00:00.000Z");
+ expect(Date.now()).toBe(819331200000);
+
+ if (typeof Bun !== "undefined") {
+ // In bun, the Date object remains the same despite being mocked.
+ // This prevents a whole bunch of subtle bugs in tests.
+ expect(DateBeforeMocked).toBe(Date);
+ expect(DateBeforeMocked.now).toBe(Date.now);
+
+ // Jest doesn't property mock new Intl.DateTimeFormat().format()
+ expect(new Intl.DateTimeFormat().format()).toBe("12/19/1995");
+ } else {
+ expect(DateBeforeMocked).not.toBe(Date);
+ expect(DateBeforeMocked.now).not.toBe(Date.now);
+ }
+
+ jest.useRealTimers();
+ const now = new Date();
+ now.setHours(0, 0, 0, 0);
+ expect(now.toISOString()).toBe(orig.toISOString());
});