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 c2105bc
Show file tree
Hide file tree
Showing 2 changed files with 283 additions and 9 deletions.
121 changes: 112 additions & 9 deletions src/Vitest.res
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,11 @@ 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"

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

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

Expand Down Expand Up @@ -1109,7 +1114,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 +1167,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 @@ -1180,29 +1194,118 @@ module Vi = {
@send external advanceTimersByTime: (t, int) => t = "advanceTimersByTime"
@inline let advanceTimersByTime = ms => vi_obj->advanceTimersByTime(ms)

@send external advanceTimersByTimeAsync: (t, int) => promise<t> = "advanceTimersByTimeAsync"
let advanceTimersByTimeAsync = time => vi_obj->advanceTimersByTimeAsync(time)

@send external advanceTimersToNextTimer: t => t = "advanceTimersToNextTimer"
@inline let advanceTimersToNextTimer = () => vi_obj->advanceTimersToNextTimer

@send external advanceTimersToNextTimerAsync: t => promise<t> = "advanceTimersToNextTimerAsync"
let advanceTimersToNextTimerAsync = () => vi_obj->advanceTimersToNextTimerAsync

@send external getTimerCount: t => int = "getTimerCount"
let getTimerCount = () => vi_obj->getTimerCount

@send external clearAllTimers: t => t = "clearAllTimers"
let clearAllTimers = () => vi_obj->clearAllTimers

@send external runAllTicks: t => t = "runAllTicks"
let runAllTicks = () => vi_obj->runAllTicks

@send external runAllTimers: t => t = "runAllTimers"
@inline let runAllTimers = () => vi_obj->runAllTimers

@send external runAllTimersAsync: t => promise<t> = "runAllTimersAsync"
let runAllTimersAsync = () => vi_obj->runAllTimersAsync

@send external runOnlyPendingTimers: t => t = "runOnlyPendingTimers"
@inline let runOnlyPendingTimers = () => vi_obj->runOnlyPendingTimers

@send external useFakeTimers: t => t = "useFakeTimers"
@inline let useFakeTimers = () => vi_obj->useFakeTimers
@send external runOnlyPendingTimersAsync: t => promise<t> = "runOnlyPendingTimersAsync"
let runOnlyPendingTimersAsync = () => vi_obj->runOnlyPendingTimersAsync

@send
external setSystemTime: (t, @unwrap [#Date(Js.Date.t) | #String(string) | #Int(int)]) => t =
"setSystemTime"
let setSystemTime = time => vi_obj->setSystemTime(time)

/**
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,
}

@send external useFakeTimers: (t, ~config: fakeTimersConfig=?, unit) => t = "useFakeTimers"
@inline let useFakeTimers = (~config=?, ()) => vi_obj->useFakeTimers(~config?, ())

@send external useRealTimers: t => t = "useRealTimers"
@inline let useRealTimers = () => vi_obj->useRealTimers

@send external mockCurrentDate: (t, Js.Date.t) => t = "mockCurrentDate"
@inline let mockCurrentDate = date => vi_obj->mockCurrentDate(date)
@send external isFakeTimers: t => bool = "isFakeTimers"
let isFakeTimers = () => vi_obj->isFakeTimers

@send @return(nullable)
external getMockedSystemTime: t => option<Js.Date.t> = "getMockedSystemTime"
let getMockedSystemTime = () => vi_obj->getMockedSystemTime

@send external getRealSystemTime: t => float = "getRealSystemTime"
let getRealSystemTime = () => vi_obj->getRealSystemTime

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

@send external waitFor: (t, unit => 'a, ~options: waitForOptions=?) => promise<'a> = "waitFor"

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

@send
external waitForAsync: (t, unit => promise<'a>, ~options: waitForOptions=?) => promise<'a> =
"waitFor"

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

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

@send
external waitUntil: (t, unit => 'a, ~options: waitUntilOptions=?) => promise<'a> = "waitUntil"

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

@send
external waitUntilAsync: (t, unit => promise<'a>, ~options: waitUntilOptions=?) => promise<'a> =
"waitUntil"

@send external restoreCurrentDate: (t, Js.Date.t) => t = "restoreCurrentDate"
@inline let restoreCurrentDate = date => vi_obj->restoreCurrentDate(date)
/**
@since(vitest >= 0.34.5)
*/
let waitUntilAsync = (callback, ~timeout=?, ~interval=?, ()) =>
waitUntilAsync(vi_obj, callback, ~options={?timeout, ?interval})

@send external getMockedDate: t => Js.null<Js.Date.t> = "getMockedDate"
@inline let getMockedDate = () => vi_obj->getMockedDate->Js.Null.toOption
@send external hoisted: (t, unit => 'a) => 'a = "hoisted"
let hoisted = callback => hoisted(vi_obj, callback)
}

@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 c2105bc

Please sign in to comment.