# TestClock

Most tests should run as fast as possible, and waiting for real time to pass is
both slow and flaky. `TestClock` replaces Effect's `Clock` service with one
whose time **only moves when you tell it to**. Anything built on the clock —
`Effect.sleep`, timeouts, retries, [schedules](https://effect.plants.sh/scheduling/), debouncing — is
then driven deterministically by advancing virtual time, so a test of a one-hour
delay completes instantly.

`it.effect` provides the `TestClock` for you, so you just describe("TestClock", () => {
  it.effect("completes a sleep when time is advanced", () =>
    Effect.gen(function*() {
      // Fork the sleeping effect first. The fork keeps running while we keep
      // control to advance the clock — otherwise the test would block here.
      const fiber = yield* Effect.forkChild(
        Effect.sleep("1 hour").pipe(Effect.as("done" as const))
      )

      // Move virtual time forward by one hour. Every sleep scheduled to
      // resume at or before the new time fires, in order.
      yield* TestClock.adjust("1 hour")

      // Now the forked fiber has finished; join it to read its result.
      const value = yield* Fiber.join(fiber)
      assert.strictEqual(value, "done")
    }))
})
```

## The fork-then-adjust pattern

This is the pattern you will use again and again. `Effect.sleep` (and everything
derived from it) **semantically blocks** until the clock reaches its scheduled
time. If you call `TestClock.adjust` *after* a sleep on the same fiber, the
sleep never gets a chance to run.

So the recipe is:

1. **Fork** the time-dependent effect with `Effect.forkChild` so it runs on its
   own fiber.
2. **Adjust** the clock to the time you want to simulate.
3. **Join** the fiber (or otherwise observe the effect) and assert.
**Why fork?:** Forking keeps the test fiber in control of the clock. The forked fiber parks
  on its sleep; advancing the clock wakes it up. Without the fork, the test
  fiber would block on the sleep and never reach the `adjust` call.

## Testing timeouts

`Effect.timeoutOption` returns `Option.none()` when the inner effect does not
complete in time. With `TestClock` we can drive it to either outcome
deterministically — here we advance less than the inner sleep, so it times out.

```ts
describe("timeouts", () => {
  it.effect("times out when the work takes too long", () =>
    Effect.gen(function*() {
      const fiber = yield* Effect.forkChild(
        // The work needs 5 minutes but is only allowed 1 minute.
        Effect.sleep("5 minutes").pipe(Effect.timeoutOption("1 minute"))
      )

      // Advance past the timeout but not past the work's own duration.
      yield* TestClock.adjust("1 minute")

      const result = yield* Fiber.join(fiber)
      // The timeout fired first, so the result is None.
      assert.deepStrictEqual(result, Option.none())
    }))
})
```

## Testing recurring effects

Schedules and repeats are also clock-driven, so you can step through a recurring
effect one period at a time and assert on each occurrence. Here a value is
enqueued every 60 minutes; advancing by exactly one period yields exactly one
value.

```ts
describe("recurring effects", () => {
  it.effect("emits one value per period", () =>
    Effect.gen(function*() {
      const queue = yield* Queue.unbounded<number>()

      // Offer a value every 60 minutes, forever, on its own fiber.
      yield* Effect.forkChild(
        Queue.offer(queue, 1).pipe(
          Effect.delay("60 minutes"),
          Effect.forever
        )
      )

      // Nothing has been offered yet — no time has passed.
      assert.deepStrictEqual(yield* Queue.poll(queue), Option.none())

      // Advance one period: exactly one value should be enqueued.
      yield* TestClock.adjust("60 minutes")
      assert.strictEqual(yield* Queue.take(queue), 1)

      // And no more than one.
      assert.deepStrictEqual(yield* Queue.poll(queue), Option.none())

      // Advance another period: the next occurrence fires.
      yield* TestClock.adjust("60 minutes")
      assert.strictEqual(yield* Queue.take(queue), 1)
    }))
})
```

## Reading the clock and jumping to a time

The `TestClock` starts at the Unix epoch (`0`). Reading the time through `Clock`
returns virtual time, which only changes when you `adjust` it. Use
`TestClock.setTime` to jump to an exact timestamp instead of moving by a
relative duration.

```ts
describe("reading the clock", () => {
  it.effect("advances virtual time", () =>
    Effect.gen(function*() {
      // TestClock starts at the epoch.
      assert.strictEqual(yield* Clock.currentTimeMillis, 0)

      // `adjust` moves by a relative duration...
      yield* TestClock.adjust("1 minute")
      assert.strictEqual(yield* Clock.currentTimeMillis, 60_000)

      // ...`setTime` jumps to an absolute timestamp.
      yield* TestClock.setTime(Duration.toMillis("2 hours"))
      assert.strictEqual(yield* Clock.currentTimeMillis, 7_200_000)
    }))
})
```
**Note:** Need real elapsed time for one specific effect while keeping the rest of the
  test deterministic? Wrap it with `TestClock.withLive`, which runs that effect
  against the live system clock.

If a test uses time but never advances the `TestClock`, the module logs a
warning after a short delay to help you spot a hanging test — a missing
`adjust` call is almost always the cause.

## Using TestClock without `@effect/vitest`

`it.effect` provides the `TestClock` for you, but the module is just an ordinary
service: you can drive virtual time in any program by providing
`TestClock.layer()` and reaching for the same `adjust` / `setTime` controls. The
layer constructs a `TestClock` and installs it as the `Clock` service, so every
clock-aware operator (`Effect.sleep`, timeouts, schedules) becomes virtual.

```ts
const program = Effect.gen(function*() {
  // Fork the sleeping work so we keep control to advance the clock.
  const fiber = yield* Effect.forkChild(
    Effect.sleep("1 hour").pipe(Effect.as("done" as const))
  )

  // Move virtual time forward — the forked sleep resumes immediately.
  yield* TestClock.adjust("1 hour")

  return yield* Fiber.join(fiber)
})

// Provide the TestClock layer instead of relying on `it.effect`.
Effect.runPromise(program.pipe(Effect.provide(TestClock.layer())))
  .then(console.log) // => "done"
```
**The hanging-test warning:** Because the program above advances the clock, no warning fires. If you sleep
  but never `adjust`, the `TestClock` logs *"A test is using time, but is not
  advancing the test clock, which may result in the test hanging. Use
  TestClock.adjust to manually advance the time."* after `warningDelay`
  (`1 second` by default). The warning timer itself runs on the **live** clock,
  so it appears in real time even though the rest of your program is virtual.
  Tune it with `TestClock.layer({ warningDelay: "5 seconds" })`.

## Reference

Everything below is exported from `effect/testing`'s `TestClock` module. The
top-level `adjust`, `setTime`, and `withLive` functions read the active
`TestClock` out of the fiber context, so they work directly inside `it.effect`
or any program that provided `TestClock.layer()`.

### adjust

`adjust(duration: Duration.Input)` increments virtual time by a relative
duration. Every sleep scheduled to resume at or before the new time fires, in
clock-time order. This is the workhorse covered in
[the fork-then-adjust pattern](#the-fork-then-adjust-pattern) above.

```ts
const program = Effect.gen(function*() {
  yield* TestClock.adjust("90 minutes")
  return yield* Clock.currentTimeMillis // => 5400000
})
```

### setTime

`setTime(timestamp: number)` jumps virtual time to an absolute epoch-millis
timestamp (rather than moving by a relative amount). Sleeps due at or before the
target still fire in order.

```ts
const program = Effect.gen(function*() {
  // Jump straight to "2 hours since the epoch".
  yield* TestClock.setTime(Duration.toMillis("2 hours"))
  return yield* Clock.currentTimeMillis // => 7200000
})
```

### withLive

`withLive(effect)` runs a single effect against the **live** system `Clock`
while the rest of the program stays on virtual time. Use it when you genuinely
need real elapsed time — e.g. measuring wall-clock latency or live logging.

```ts
const program = Effect.gen(function*() {
  const virtual = yield* Clock.currentTimeMillis // => 0 (TestClock at epoch)
  const real = yield* TestClock.withLive(Clock.currentTimeMillis)
  // real => actual system timestamp, e.g. 1748563200000
  return { virtual, real }
})
```

### testClockWith

`testClockWith(f)` hands you the underlying `TestClock` service so you can call
its methods (`adjust`, `setTime`, `currentTimeMillisUnsafe`, `withLive`)
directly. The convenience exports `adjust` / `setTime` / `withLive` are thin
wrappers over this.

```ts
const program = TestClock.testClockWith((clock) =>
  Effect.sync(() => clock.currentTimeMillisUnsafe()) // => 0
)
```

### make

`make(options?)` constructs a `TestClock` service value as an effect. The only
option is `warningDelay` (a `Duration.Input`, default `"1 second"`), which
controls how long before the hanging-test warning is logged. The returned
service implements the full [`Clock`](https://effect.plants.sh/scheduling/) interface plus the
test-only controls:

- `currentTimeMillis` / `currentTimeMillisUnsafe()` — read virtual time in millis.
- `currentTimeNanos` / `currentTimeNanosUnsafe()` — read virtual time in nanos.
- `adjust(duration)` — advance by a relative duration.
- `setTime(timestamp)` — jump to an absolute timestamp.
- `sleep(duration)` — the clock-aware sleep that the rest of Effect builds on.
- `withLive(effect)` — run an effect against the live clock.

```ts
const program = Effect.gen(function*() {
  const clock = yield* TestClock.make({ warningDelay: "5 seconds" })
  yield* clock.adjust("1 hour")
  return clock.currentTimeMillisUnsafe() // => 3600000
})
```

### layer

`layer(options?)` returns a `Layer.Layer<TestClock>` that builds a `TestClock`
and installs it as the `Clock` service. Provide it to any program that does not
go through `it.effect` (which already provides one for you).

```ts
const program = Effect.gen(function*() {
  yield* TestClock.adjust("1 day")
})

// Manually provide the layer (optionally configuring the warning delay).
Effect.runPromise(
  program.pipe(Effect.provide(TestClock.layer({ warningDelay: "10 seconds" })))
)
```

### TestClock.Options and TestClock.State

The `TestClock` namespace exposes two supporting types. `TestClock.Options` is
the `{ readonly warningDelay?: Duration.Input }` shape accepted by `make` and
`layer`. `TestClock.State` (`{ timestamp: number; sleeps: ReadonlyArray<[number, Latch.Latch]> }`)
describes the internal state a clock tracks — the current virtual timestamp and
the pending sleeps waiting to resume.

```ts
// A typed options value you can pass to make/layer.
const options: TestClock.Options = { warningDelay: "2 seconds" }
const delay: Duration.Input | undefined = options.warningDelay // => "2 seconds"
```