testing
Mock utilities for unit testing SLua modules
Work in progress
This module is under active development and has not been battle-tested in production. The API may change between releases.
The testing module mocks ll, LLEvents, LLTimers, coroutine,
Vector, Quaternion, UUID, and every SLua constant, so you can unit-test
modules in Bun, Vitest, or Jest without a Second Life runtime.
This module is for test environments only. It does not compile to Lua, so never import it from a production SLua script.
Usage
import { describe, it, expect, beforeEach, afterEach } from "bun:test"
import { setup, teardown, notecard, emit } from "./modules/testing"
import { loadConfig } from "./modules/config"
beforeEach(() => setup())
afterEach(() => teardown())
it("loads config from notecard", () => {
notecard("settings.yml", ["CHANNEL: -123", "MESSAGE: Hello"])
const config = { CHANNEL: 0, MESSAGE: "" }
loadConfig("settings.yml", { config }, () => {
expect(config.CHANNEL).toBe(-123)
expect(config.MESSAGE).toBe("Hello")
})
})API
Prop
Type
Mock behaviour
ll
The ll namespace is a Proxy, so any function it does not mock is a no-op.
Functions that return request IDs (RequestAgentData, HTTPRequest, etc.)
return auto-incrementing UUIDs.
Each setup() installs a fresh copy of the mock, so tests can freely
override functions (ll.RequestAgentData = () => "fixed-id") without leaking
into later tests.
Chat functions (Say, Whisper, Shout, OwnerSay, RegionSay,
RegionSayTo) are recorded and inspectable via chatMessages():
const avatarKey = "fc4d0b7a-6a5c-4b6b-8143-c724f820c12e"
ll.Say(0, "hello")
ll.RegionSayTo(avatarKey, 0, "psst")
expect(chatMessages()).toEqual([
{ func: "Say", channel: 0, text: "hello" },
{ func: "RegionSayTo", channel: 0, text: "psst", target: avatarKey },
])The log is cleared on every setup() and teardown().
Vector, Quaternion, and UUID
Constructible mock classes with the statics and instance math (add, mul,
neg, etc.) from the SLua API (Vector.zero, Vector.normalize,
Quaternion.identity, UUID.create, and so on), also installed under their
lowercase runtime names (vector, quaternion, uuid). Quaternion math is
intentionally simple (slerp is implemented as nlerp), so precise rotation
math should not be asserted against these mocks.
LLEvents
Full on/off/once implementation backed by an internal handler map. Use
emit() to trigger events in tests.
LLTimers
every() and once() register callbacks into a set. Use tick() to fire them.
coroutine
A fresh mock coroutine namespace is created per setup() call. Provides
create, resume, running, yield, status, isyieldable, wrap, and
close. Use setCoroutineYieldValue() to control what yield() returns.