Start typing to search packages!
react-testing-library-luau
By @flipbook-labs
Roblox
Mirroredreact-testing-library-luau
Idiomatic-Luau testing library for react-lua components, running against real Instances in a live DataModel.
local React = require(Packages.React)
local ReactTesting = require(Packages.ReactTesting)
ReactTesting.installCleanup(JestGlobals.afterEach)
test("clicking increments", function()
local function Counter()
local count, setCount = React.useState(0)
return React.createElement("TextButton", {
Text = `Count: {count}`,
[React.Event.Activated] = function()
setCount(count + 1)
end,
})
end
local result = ReactTesting.render(React.createElement(Counter))
ReactTesting.fireEvent.activated(result.getByText("Count: 0") :: TextButton)
expect(result.getByText("Count: 1")).toBeDefined()
end)
Full reference: docs/API.md. Coming from Roblox's port? docs/migration-from-roblox-rtl.md.
Why not the existing port?
Roblox's react-testing-library-lua
is a verbatim transpilation of the JS library — and its fireEvent drives
VirtualInputManager, a RobloxScriptSecurity service that only exists in
Roblox's internal test infrastructure. Outside it (plugins, Studio command
bar, Open Cloud Luau execution), the port cannot simulate events at all.
This library keeps the Testing Library mental model but is designed for Luau and for user-level security:
- Event dispatch that works everywhere: React handler invocation through react-roblox's exported test internals, plus real engine signals where Luau can trigger them (docs/EVENT_DISPATCH.md)
--!strictthroughout; noanycasts in library source (CI-enforced); explicit option types instead of merge-based option objects- Roblox event names (
activated,textChanged,focus), not DOM aliases (click,change) - No global
screen— queries come fromrender()results andwithin(container); Roblox has no global document - No LuauPolyfill / Promise dependencies —
waitForandfindBy*are plain blocking calls polling withtask.wait
Queries
ByText, ByPlaceholderText, ByDisplayValue, and ByTestId
(CollectionService data-testid=<value> tags, compatible with the Roblox
port's convention) — each as get / getAll / query / queryAll / find / findAll. ByRole/ByLabelText/ByTitle/ByAltText are intentionally
absent: Roblox has no accessibility tree.
Workspace
Two Loom packages wired with a path dependency:
modules/instance-testing— queries over plain Instances (the folded dom-testing-library layer; no React dependency — usable with Roact/Fusion/hand-built UI too)modules/react-testing— render / fireEvent / act / waitFor, re-exporting the queries
Development
rokit install # toolchain (lute, rojo, darklua, selene, stylua, wally, ...)
lute run install # loom + wally dependencies
lute run lint # selene + stylua
lute run analyze # strict typecheck (luau-lsp, new solver)
lute run test # jest via rocale-cli cloud execution (needs ROBLOX_API_KEY in .env)
The e2e runbook (headless and in-Studio) lives in .agents/skills/e2e/SKILL.md.
License
MIT. Portions of test suites and query behavior derive from Roblox's MIT-licensed testing-library ports — see LICENSE.
Package Details
Install command (Click to copy)
Version
0.2.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
