Documentation
¶
Overview ¶
Package clock provides a simulated time for Gost-DOM.
Index ¶
- Constants
- type Clock
- func (c *Clock) AddMicrotask(task TaskCallback)
- func (c *Clock) AddSafeMicrotask(task SafeTaskCallback)
- func (c *Clock) AddSafeTask(task SafeTaskCallback, delay time.Duration) TaskHandle
- func (c *Clock) Advance(d time.Duration) error
- func (c *Clock) BeginEvent() *EventLoopCallback
- func (c *Clock) Cancel(handle TaskHandle)
- func (c *Clock) ProcessEvents(ctx context.Context) error
- func (c *Clock) ProcessEventsWhile(ctx context.Context, f func() bool) error
- func (c *Clock) RunAll() error
- func (c *Clock) SetInterval(task SafeTaskCallback, delay time.Duration) TaskHandle
- func (c *Clock) SetTimeout(task TaskCallback, delay time.Duration) TaskHandle
- func (c *Clock) Tick() error
- type EventLoopCallback
- type NewClockOption
- type SafeTaskCallback
- type TaskCallback
- type TaskHandle
Constants ¶
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) AddMicrotask ¶
func (c *Clock) AddMicrotask(task TaskCallback)
AddMicrotask 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) AddSafeMicrotask ¶
func (c *Clock) AddSafeMicrotask(task SafeTaskCallback)
AddSafeMicrotask is a version of AddMicrotask, where the caller can guarantee the task doesn't generate an error.
func (*Clock) AddSafeTask ¶
func (c *Clock) AddSafeTask(task SafeTaskCallback, delay time.Duration) TaskHandle
Schedules a task to run at a specified time in the future. Panics if the time is in the past.
func (*Clock) Advance ¶
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) ProcessEvents ¶ added in v0.8.0
ProcessEvents processes all pending events.
func (*Clock) ProcessEventsWhile ¶ added in v0.8.0
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) RunAll ¶
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 SafeTaskCallback, 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.
func (*EventLoopCallback) AddSafeEvent ¶ added in v0.8.0
func (c *EventLoopCallback) AddSafeEvent(cb SafeTaskCallback)
AddSafeEvent is like [Clock.addEvent], but with a simpler interface for events that cannot fail with an error.
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 SafeTaskCallback ¶
type SafeTaskCallback func()
A SafeTaskCallback is the callback that registered for a [futureTask] that can't generate an err.r
type TaskCallback ¶
type TaskCallback func() error
A TaskCallback is the callback registered for a [futureTask].
type TaskHandle ¶
type TaskHandle uint32