clock

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 19, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package clock provides a simulated time for Gost-DOM.

Index

Constants

View Source
const DefaultEventBufSize = 8

DefaultEventBufSize is the default capacity used when not specified explicitly for the internal channel events pushed to the event loop.

Variables

This section is empty.

Functions

This section is empty.

Types

type Clock

type Clock struct {
	Time   time.Time
	Logger *slog.Logger
	mutation.FlusherSet

	// Sets the number of times a task is allowed to run without seeing a
	// reduction in task list size. I.e., the task list doesn't need to be
	// emptied after the specified no of tasks executed, but the smallest
	// observed size of the queue must have decreased. The counter is reset
	// every time a new minimum of remaining number of tasks is noticed
	MaxLoopWithoutDecrement int

	// EventBufSize sets the event channel buffer capacity if non-zero.
	// Otherwise [DEFAULT_EVENT_BUF_SIZE] is used.
	EventBufSize int
	// contains filtered or unexported fields
}

Clock simulates passing of time, as well as potential future tasks. Simulated Time can be advanced using Clock.Advance or Clock.RunAll. The zero value for Clock represents Unix time 0, and will not panic.

Advancing time will perform the following - Run microtasks. - Flush any registered "Flushers" - Run timeout/interval callbacks

Microtasks are JavaScript callbacks that should execute when a script has completed, but before returning to the event loop. The script engine _may_ run microtasks, possibly making microtask management unnecessary in this space.

Flushers are operations that would run when returning to the event loop. Events generated by the MutationObserver are dispatched here.

Advance and RunAll will return an error if any of the executed tasks return an error; Advance and RunAll panics if the task list isn't reducing.

Advancing the clock panics if the task queue isn't decreasing, i.e, tasks are adding new tasks. This will happen if a JavaScript call to setInterval isn't cleared before calling [RunAll], or a setTimeout callback that continuously adds a new immediate callback, or a microtasks creating a new microtask.

This is designed to panic rather than return an error, as an error represents an error generated by the code being tested. You may choose to ignore it, or even assert on it's presence when testing error conditions. But a task list that doesn't decrease is an error, that the developer should be notified of; which is why the design is a panic.

The behaviour is configurable by the MaxLoopWithoutDecrement value.

func New

func New(options ...NewClockOption) *Clock

Creates a new clock. If the options don't set a specific time, the clock is initialised with the current system time as the initial simulated wall clock time.

If tests depend on an actual time, e.g., verifying a local time displaed in the user interface, then test code should pass a concrete starting time; letting the test execution be independent of the running environment.

The option should only be left out if the test only needs to verify behaviour due to passing of time. E.g., testing throttling/debouncing/timeouts.

func (*Clock) Advance

func (c *Clock) Advance(d time.Duration) error

Advances the clock by the specified amount of time. Any new tasks being registered while running will be executed; if they are scheduled _before_ the timeout. When returning, the clock time will be the current time + the duration.

Returns an error if any of the added tasks generate an error. Panics if the task list doesn't decrease in size. See Clock documentation for more info.

func (*Clock) BeginEvent added in v0.8.0

func (c *Clock) BeginEvent() *EventLoopCallback

BeginEvent tells the event loop that an event is expected to be added in the future. This should be called on the event loop goroutine.

BeginEvent returns an EventLoopCallback that the caller must use to pass the event to the event loop.

func (*Clock) Cancel

func (c *Clock) Cancel(handle TaskHandle)

Cancel removes the task that have been added using Clock.SetTimeout or Clock.SetInterval. This corresponds to either clearTimeout or clearInterval in the browser, which by specification can be used interchangably; but shouldn't for clarity.

func (*Clock) Do added in v0.11.0

func (c *Clock) Do(f func() error) (err error)

Do wraps a task call and runs microtasks when it has completed. Nested tasks will not trigger microtasks; only when the original root task completes.

func (*Clock) LogValue added in v0.10.0

func (c *Clock) LogValue() slog.Value

func (*Clock) ProcessEvents added in v0.8.0

func (c *Clock) ProcessEvents(ctx context.Context) error

ProcessEvents processes all pending events.

func (*Clock) ProcessEventsWhile added in v0.8.0

func (c *Clock) ProcessEventsWhile(ctx context.Context, f func() bool) error

ProcessEvents processes pending events as long as predicate p evaluates to true. This is a more granular version of Clock.ProcessEvents that has it's use when certain expected events cannot have arrived.

An example: Using fetch from JavaScript

setState("REQUEST")
const response = await fetch(url)
setState("RESPONSE", response.statusCode)
const data = await response.json()
setState("SUCCESS", data)

This will create two promises. ProcessEvents would wait for both to resolve which would only succeed if the response has been fully generated. If you wish proceed until the "RESPONSE" state is set, this function can be called with a predicate inspecting the observable side effects of the call to setState.

clock.ProcessEventsWhile(ctx, func() bool {
	statusIndicator := win.Document().GetElementById("status-indicator")
	return statusIndicator.TextContent() == "RESPONSE"
})

func (*Clock) QueueMacrotask added in v0.11.0

func (c *Clock) QueueMacrotask(task TaskCallback) TaskHandle

QueueMacrotask places a task on the macrotask queue.

func (*Clock) QueueMicrotask added in v0.11.0

func (c *Clock) QueueMicrotask(task TaskCallback)

QueueMicrotask adds a task to the "microtask queue".

This shouldn't be called from Go code. Microtasks are a property of JavaScript execution and should really be carried out by the javascript engine.

func (*Clock) RunAll

func (c *Clock) RunAll() error

Keeps running as long as there are tasks in the task queue. New tasks appended while running will also run. When returning, the current time will be the time of the last executed task.

Returns an error if any of the added tasks generate an error. Panics if the task list doesn't decrease in size. See Clock documentation for more info.

func (*Clock) SetInterval

func (c *Clock) SetInterval(task TaskCallback, delay time.Duration) TaskHandle

SetInterval corresponds to the browser's [setInterval] function. Panics if the delay is negative.

func (*Clock) SetTimeout

func (c *Clock) SetTimeout(task TaskCallback, delay time.Duration) TaskHandle

SetInterval corresponds to the browser's [setTimeout] function. Panics if the delay is negative.

type EventLoopCallback added in v0.8.0

type EventLoopCallback struct {
	// contains filtered or unexported fields
}

EventLoopCallback is used to add an event to the event loop. You must call Clock.BeginEvent to get an instance, and each instance can only be used for one callback. Passing multiple event loop callbacks to the same instance will panic.

func (*EventLoopCallback) AddEvent added in v0.8.0

func (c *EventLoopCallback) AddEvent(cb TaskCallback)

AddEvent allows a goroutine to add an event to be executed on the event loop goroutine. This is safe to call from any goroutine.

EventLoopCallback.AddEvent/[EventLoopCallback.AddSafeEvent] may only be called once. Multiple calls will panic.

type NewClockOption

type NewClockOption func(*Clock)

NewClockOption are used to initialize a new Clock

func OfIsoString

func OfIsoString(iso string) NewClockOption

Initializes the clock's simulated time based on an RFC3339 time string. Panics if the string is not valid.

This is intended for the use case where the time is a constant in a test case, and as such will either fail or succeed consistently. For variable input, the caller should parse the time and use OfTime instead.

func OfTime

func OfTime(t time.Time) NewClockOption

Initializes the clock's simulated time from a concrete time.Time value.

func WithLogger added in v0.8.0

func WithLogger(l *slog.Logger) NewClockOption

type TaskCallback

type TaskCallback func() error

A TaskCallback is the callback registered for a [futureTask].

func SafeTask added in v0.11.0

func SafeTask(cb func()) TaskCallback

SafeTask creates a TaskCallback with a nil error from a simple callback function which cannot produce an error

type TaskHandle

type TaskHandle uint32

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL