Skip to content

Commit

Permalink
feat: binds more Vi utilities, and creates tests
Browse files Browse the repository at this point in the history
  • Loading branch information
illusionalsagacity committed Jun 5, 2024
1 parent 347237e commit 3872753
Show file tree
Hide file tree
Showing 2 changed files with 307 additions and 20 deletions.
156 changes: 136 additions & 20 deletions src/Vitest.res
Original file line number Diff line number Diff line change
Expand Up @@ -968,13 +968,20 @@ external afterEachPromise: (@uncurry (unit => promise<'a>), Js.Undefined.t<int>)
let afterEachPromise = (~timeout=?, callback) =>
afterEachPromise(callback, timeout->Js.Undefined.fromOption)

@module("vitest")
external afterAll: (unit => 'a, Js.Undefined.t<int>) => unit = "afterAll"

@inline
let afterAll = (~timeout=?, callback) => afterAll(callback, timeout->Js.Undefined.fromOption)

@module("vitest")
external afterAllPromise: (@uncurry (unit => promise<'a>), Js.Undefined.t<int>) => unit = "afterAll"

@inline
let afterAllPromise = (~timeout=?, callback) =>
afterAllPromise(callback, timeout->Js.Undefined.fromOption)


module Matchers = (
Config: {
type return<'a>
Expand Down Expand Up @@ -1109,7 +1116,9 @@ module Matchers = (

@inline
let toMatch = (expected, list) => {
expected->dangerously_reinforce_assertion(Belt.List.toArray)->Array.toMatch(list->Belt.List.toArray)
expected
->dangerously_reinforce_assertion(Belt.List.toArray)
->Array.toMatch(list->Belt.List.toArray)
}
}

Expand Down Expand Up @@ -1160,6 +1169,13 @@ module Assert = {

%%private(@module("vitest") @val external assert_obj: t = "assert")

@module("vitest")
external assert_: (bool, Js.undefined<string>) => unit = "assert"
let assert_ = (~message=?, value) => assert_(value, message->Js.Undefined.fromOption)

@module("vitest") @scope("expect")
external unreachable: (~message: string=?, unit) => unit = "unreachable"

@send external equal: (t, 'a, 'a, Js.undefined<string>) => unit = "equal"

@inline
Expand All @@ -1175,34 +1191,134 @@ module Assert = {
module Vi = {
type t

%%private(@module("vitest") @val external vi_obj: t = "vi")
@module("vitest") @scope("vi")
external advanceTimersByTime: int => t = "advanceTimersByTime"

@module("vitest") @scope("vi")
external advanceTimersByTimeAsync: int => promise<t> = "advanceTimersByTimeAsync"

@module("vitest") @scope("vi")
external advanceTimersToNextTimer: unit => t = "advanceTimersToNextTimer"

@module("vitest") @scope("vi")
external advanceTimersToNextTimerAsync: unit => promise<t> = "advanceTimersToNextTimerAsync"

@module("vitest") @scope("vi")
external getTimerCount: unit => int = "getTimerCount"

@send external advanceTimersByTime: (t, int) => t = "advanceTimersByTime"
@inline let advanceTimersByTime = ms => vi_obj->advanceTimersByTime(ms)
@module("vitest") @scope("vi")
external clearAllTimers: unit => t = "clearAllTimers"

@send external advanceTimersToNextTimer: t => t = "advanceTimersToNextTimer"
@inline let advanceTimersToNextTimer = () => vi_obj->advanceTimersToNextTimer
@module("vitest") @scope("vi")
external runAllTicks: unit => t = "runAllTicks"

@send external runAllTimers: t => t = "runAllTimers"
@inline let runAllTimers = () => vi_obj->runAllTimers
@module("vitest") @scope("vi") external runAllTimers: unit => t = "runAllTimers"

@send external runOnlyPendingTimers: t => t = "runOnlyPendingTimers"
@inline let runOnlyPendingTimers = () => vi_obj->runOnlyPendingTimers
@module("vitest") @scope("vi")
external runAllTimersAsync: unit => promise<t> = "runAllTimersAsync"

@send external useFakeTimers: t => t = "useFakeTimers"
@inline let useFakeTimers = () => vi_obj->useFakeTimers
@module("vitest") @scope("vi") external runOnlyPendingTimers: unit => t = "runOnlyPendingTimers"

@send external useRealTimers: t => t = "useRealTimers"
@inline let useRealTimers = () => vi_obj->useRealTimers
@module("vitest") @scope("vi")
external runOnlyPendingTimersAsync: unit => promise<t> = "runOnlyPendingTimersAsync"

@send external mockCurrentDate: (t, Js.Date.t) => t = "mockCurrentDate"
@inline let mockCurrentDate = date => vi_obj->mockCurrentDate(date)
@module("vitest") @scope("vi")
external setSystemTime: @unwrap [#Date(Js.Date.t) | #String(string) | #Int(int)] => t =
"setSystemTime"

@send external restoreCurrentDate: (t, Js.Date.t) => t = "restoreCurrentDate"
@inline let restoreCurrentDate = date => vi_obj->restoreCurrentDate(date)
/**
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/sinonjs__fake-timers/index.d.ts
*/
type fakeTimersConfig = {
now?: Js.Date.t, // or int
toFake?: array<string>,
loopLimit?: int,
shouldAdvanceTime?: bool,
advanceTimeDelta?: int,
shouldClearNativeTimers?: bool,
}

@module("vitest") @scope("vi")
external useFakeTimers: (~config: fakeTimersConfig=?, unit) => t = "useFakeTimers"

@module("vitest") @scope("vi")
external useRealTimers: unit => t = "useRealTimers"

@module("vitest") @scope("vi")
external isFakeTimers: unit => bool = "isFakeTimers"

@return(nullable) @scope("vi") @module("vitest")
external getMockedSystemTime: unit => option<Js.Date.t> = "getMockedSystemTime"

@scope("vi") @module("vitest")
external getRealSystemTime: unit => float = "getRealSystemTime"

type waitForOptions = {
timeout?: int,
interval?: int,
}

/**
@since(vitest >= 0.34.5)
*/
@module("vitest")
@scope("vi")
external waitFor: (unit => 'a, ~options: waitForOptions=?) => promise<'a> = "waitFor"

/**
@since(vitest >= 0.34.5)
*/
let waitFor = (callback, ~timeout=?, ~interval=?, ()) =>
waitFor(callback, ~options={?timeout, ?interval})

/**
@since(vitest >= 0.34.5)
*/
@module("vitest")
@scope("vi")
external waitForAsync: (unit => promise<'a>, ~options: waitForOptions=?) => promise<'a> =
"waitFor"

/**
@since(vitest >= 0.34.5)
*/
let waitForAsync = (callback, ~timeout=?, ~interval=?, ()) =>
waitForAsync(callback, ~options={?timeout, ?interval})

type waitUntilOptions = {
timeout?: int,
interval?: int,
}

@send external getMockedDate: t => Js.null<Js.Date.t> = "getMockedDate"
@inline let getMockedDate = () => vi_obj->getMockedDate->Js.Null.toOption
/**
@since(vitest >= 0.34.5)
*/
@module("vitest")
@scope("vi")
external waitUntil: (unit => 'a, ~options: waitUntilOptions=?) => promise<'a> = "waitUntil"

/**
@since(vitest >= 0.34.5)
*/
let waitUntil = (callback, ~timeout=?, ~interval=?, ()) =>
waitUntil(callback, ~options={?timeout, ?interval})

/**
@since(vitest >= 0.34.5)
*/
@module("vitest")
@scope("vi")
external waitUntilAsync: (unit => promise<'a>, ~options: waitUntilOptions=?) => promise<'a> =
"waitUntil"

/**
@since(vitest >= 0.34.5)
*/
let waitUntilAsync = (callback, ~timeout=?, ~interval=?, ()) =>
waitUntilAsync(callback, ~options={?timeout, ?interval})

@module("vitest") @scope("vi")
external hoisted: (unit => 'a) => 'a = "hoisted"
}

@scope("import.meta") @val
Expand Down
171 changes: 171 additions & 0 deletions tests/vi.test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
open Vitest

@val external nextTick: (unit => unit) => unit = "process.nextTick"

describe("Vi", () => {
beforeEach(() => {
let _ = Vi.useRealTimers()
})

afterAll(() => {
let _ = Vi.useRealTimers()
})

let _promise = () => Js.Promise2.resolve()

itAsync("should compile fake timers correctly", async _t => {
let _ = Vi.useFakeTimers()
Vi.isFakeTimers()->expect->Expect.toBe(true)

let called = ref(false)
let called2 = ref(false)

let _ = Js.Global.setTimeout(() => called := true, 100)
let _ = Js.Global.setTimeout(() => called2 := true, 200)
let _ = Vi.advanceTimersByTime(10)
called->expect->Expect.toEqual({contents: false})
called2->expect->Expect.toEqual({contents: false})

let _ = Vi.advanceTimersByTime(100)
called->expect->Expect.toEqual({contents: true})
called2->expect->Expect.toEqual({contents: false})
called := false

let _ = await Vi.advanceTimersByTimeAsync(1000)
called2->expect->Expect.toEqual({contents: true})
called2 := false
Vi.getTimerCount()->expect->Expect.toBe(0)

let _ = Js.Global.setTimeout(() => called := true, 1000)
let _ = Js.Global.setTimeout(() => called2 := true, 2000)
Vi.getTimerCount()->expect->Expect.toBe(2)
let _ = Vi.runAllTimers()
called->expect->Expect.toEqual({contents: true})
called2->expect->Expect.toEqual({contents: true})
called := false
called2 := false

let _ = Js.Global.setTimeout(() => called := true, 1000)
let _ = Js.Global.setTimeout(() => called2 := true, 2000)
Vi.getTimerCount()->expect->Expect.toBe(2)
let _ = await Vi.runAllTimersAsync()
called->expect->Expect.toEqual({contents: true})
called2->expect->Expect.toEqual({contents: true})
called := false
called2 := false

let _ = Js.Global.setTimeout(() => called := true, 1000)
Vi.getTimerCount()->expect->Expect.toBe(1)
let _ = Vi.runOnlyPendingTimers()
called->expect->Expect.toEqual({contents: true})
called := false

let _ = Js.Global.setTimeout(() => called := true, 1000)
Vi.getTimerCount()->expect->Expect.toBe(1)
let _ = await Vi.runOnlyPendingTimersAsync()
called->expect->Expect.toEqual({contents: true})
called := false

let _ = Js.Global.setTimeout(() => called := true, 1000)
let _ = Js.Global.setTimeout(() => called2 := true, 2000)
Vi.getTimerCount()->expect->Expect.toBe(2)
let _ = Vi.advanceTimersToNextTimer()
called->expect->Expect.toEqual({contents: true})
called2.contents->expect->Expect.toBe(false)

let _ = await Vi.advanceTimersToNextTimerAsync()
called2.contents->expect->Expect.toBe(true)

let _ = Js.Global.setTimeout(() => called := true, 1000)
Vi.getTimerCount()->expect->Expect.toBe(1)
let _ = Vi.clearAllTimers()
Vi.getTimerCount()->expect->Expect.toBe(0)

nextTick(() => called := true)
let _ = Vi.runAllTicks()
called->expect->Expect.toEqual({contents: true})
called := false
})

itAsync("should compile waitFor correctly", async _t => {
let called = ref(false)
let _ = Js.Global.setTimeout(() => called := true, 100)
await Vi.waitFor(() => Assert.assert_(called.contents == true), ())
called->expect->Expect.toEqual({contents: true})

let called = ref(false)
let _ = Js.Global.setTimeout(() => called := true, 100)
await Vi.waitFor(() => Assert.assert_(called.contents == true), ~timeout=200, ())
called->expect->Expect.toEqual({contents: true})

let called = ref(false)
let _ = Js.Global.setTimeout(() => called := true, 100)
await Vi.waitFor(() => Assert.assert_(called.contents == true), ~interval=50, ())
called->expect->Expect.toEqual({contents: true})

let called = ref(false)
let _ = Js.Global.setTimeout(() => called := true, 100)
await Vi.waitFor(() => Assert.assert_(called.contents == true), ~timeout=200, ~interval=50, ())
called->expect->Expect.toEqual({contents: true})

let run = async () => {
let called = ref(false)
let _ = Js.Global.setTimeout(() => called := true, 100)
await Vi.waitFor(() => Assert.assert_(called.contents == true), ~timeout=50, ())
called->expect->Expect.toEqual({contents: false})
}

await run()
->expect
->Expect.Promise.rejects
->Expect.Promise.toThrow
})

itAsync("should compile waitForAsync correctly", async _t => {
let _ = Vi.useFakeTimers()

let sleep = ms => {
Js.Promise2.make(
(~resolve, ~reject as _) => {
let _ = Js.Global.setTimeout(() => resolve(), ms)
},
)
}

await Vi.waitForAsync(() => sleep(1), ())
await Vi.waitForAsync(() => sleep(20), ~timeout=100, ())
await Vi.waitForAsync(() => sleep(50), ~interval=50, ())
await Vi.waitForAsync(() => sleep(150), ~timeout=200, ~interval=50, ())

let run = () => Vi.waitForAsync(() => sleep(100), ~timeout=50, ())

await run()
->expect
->Expect.Promise.rejects
->Expect.Promise.toThrow
})

it("compile mocking system time correctly", _t => {
Vi.getMockedSystemTime()->expect->Expect.toBeNone

let date = Js.Date.makeWithYMD(~year=2021., ~month=1., ~date=1., ())
let _ = Vi.setSystemTime(#Date(date))
// FIXME: Expect.toBeSome is not working
/*
AssertionError: expected 2021-02-01T05:00:00.000Z to not deeply equal 2021-02-01T05:00:00.000Z
❯ Object.toBeSome src/Vitest.mjs:671:21
669| expected.not.toBeUndefined();
670| if (some !== undefined) {
671| return expected.toEqual(Caml_option.valFromOption(some));
| ^
672| }
*/
Vi.getMockedSystemTime()->Belt.Option.getExn->expect->Expect.toStrictEqual(date)
Vi.getRealSystemTime()->expect->Expect.Float.toBeGreaterThan(Js.Date.getTime(date))

Vi.getRealSystemTime()->expect->Expect.Float.toBeGreaterThanOrEqual(0.0)
let _ = Vi.useRealTimers()
Vi.isFakeTimers()->expect->Expect.toBe(false)
Vi.getMockedSystemTime()->expect->Expect.toBeNone
})
})

0 comments on commit 3872753

Please sign in to comment.