test: use lute for tests

This commit is contained in:
littensy 2025-12-01 17:29:39 -08:00
parent 72b290219d
commit a20ee3698a
47 changed files with 190 additions and 236 deletions

View file

@ -15,10 +15,10 @@ jobs:
- uses: CompeyDev/setup-rokit@v0.1.2 - uses: CompeyDev/setup-rokit@v0.1.2
- name: Check code quality - name: Check code quality
run: sh bin/check.sh run: pnpm check
- name: Run tests - name: Run tests
run: lune run test/spec.server.luau run: pnpm test
- name: Build models - name: Build models
run: sh bin/build.sh run: pnpm build

4
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "test/suite"] [submodule "tests/test"]
path = test/suite path = tests/test
url = https://gist.github.com/littensy/fa9afcc5d66d25e86538634982be4ee4 url = https://gist.github.com/littensy/fa9afcc5d66d25e86538634982be4ee4

14
.luaurc
View file

@ -1,6 +1,10 @@
{ {
"languageMode": "strict", "languageMode": "strict",
"lint": { "aliases": {
"LocalShadow": false "lute": "~/.lute/typedefs/0.1.0/lute",
} "std": "~/.lute/typedefs/0.1.0/std"
} },
"lint": {
"LocalShadow": false
}
}

6
.lute/build.luau Normal file
View file

@ -0,0 +1,6 @@
local fs = require("@std/fs")
local process = require("@lute/process")
fs.createdirectory("build")
process.run({ "rojo", "build", "--output=build/charm.rbxm" }, { stdio = "inherit" })

30
.lute/check.luau Normal file
View file

@ -0,0 +1,30 @@
local fs = require("@std/fs")
local net = require("@lute/net")
local process = require("@lute/process")
process.run({ "rojo", "sourcemap", "--output=sourcemap.json" }, { stdio = "inherit" })
fs.writestringtofile(
"roblox.d.luau",
net.request("https://luau-lsp.pages.dev/globalTypes.None.d.luau", { method = "GET" }).body
)
process.run({
"luau-lsp",
"analyze",
"--sourcemap=sourcemap.json",
"--ignore=**/node_modules/**",
"--base-luaurc=.luaurc",
"--defs=roblox.d.luau",
"packages",
"tests",
"benches",
}, { stdio = "inherit" })
fs.remove("roblox.d.luau")
process.run({ "selene", "packages", "tests", "benches" }, { stdio = "inherit" })
process.run({ "stylua", "--check", "packages", "tests", "benches" }, { stdio = "inherit" })
process.run({ "pnpm", "eslint", "packages" }, { stdio = "inherit" })

1
.lute/test.luau Normal file
View file

@ -0,0 +1 @@
(require)("../tests/run.server")

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
mkdir build
rojo build build.project.json -o build/charm.rbxm

View file

@ -1,19 +0,0 @@
curl -o bin/roblox.d.luau https://raw.githubusercontent.com/JohnnyMorganz/luau-lsp/main/scripts/globalTypes.d.luau
rojo sourcemap -o sourcemap.json
luau-lsp analyze \
--defs=bin/roblox.d.luau \
--flag:LuauFixIndexerSubtypingOrdering=true \
--flag:LuauInstantiateInSubtyping=true \
--sourcemap=sourcemap.json \
--ignore="**/node_modules/**" \
packages test benches
selene packages test benches
stylua --check packages test benches
pnpm eslint packages
rm bin/roblox.d.luau

View file

@ -43,8 +43,8 @@
"@rbxts-js": { "@rbxts-js": {
"$path": "node_modules/@rbxts-js" "$path": "node_modules/@rbxts-js"
}, },
"test": { "tests": {
"$path": "test" "$path": "tests"
} }
} }
} }

View file

@ -1,9 +1,9 @@
{ {
"private": true, "private": true,
"scripts": { "scripts": {
"test": "lune run test/spec.server.luau", "test": "lute run test",
"build": "sh bin/build.sh", "build": "lute run build",
"check": "sh bin/check.sh", "check": "lute run check",
"publish:npm": "pnpm publish -r --access public", "publish:npm": "pnpm publish -r --access public",
"publish:wally": "pnpm -r --workspace-concurrency 1 publish:wally" "publish:wally": "pnpm -r --workspace-concurrency 1 publish:wally"
}, },

View file

@ -1,11 +1,8 @@
local Charm = require("../../Charm") local Charm = require("../../Charm")
local client = require("../client") local client = require("../client")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local test = suite.test test.afterEach(function()
local afterEach = suite.afterEach
afterEach(function()
client.removeAllSignals() client.removeAllSignals()
end) end)

View file

@ -2,12 +2,9 @@ local Charm = require("../../Charm")
local client = require("../client") local client = require("../client")
local config = require("../config") local config = require("../config")
local server = require("../server") local server = require("../server")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local afterEach = suite.afterEach test.afterEach(function()
local test = suite.test
afterEach(function()
server.reset() server.reset()
client.removeAllSignals() client.removeAllSignals()
config.preserveHistory = false config.preserveHistory = false

View file

@ -0,0 +1,23 @@
local test = require("../../../tests/test")
test.describe("client", function()
require("@self/client.test")
end)
test.describe("e2e", function()
require("@self/e2e.test")
end)
test.describe("utils", function()
require("@self/utils.test")
end)
test.describe("patch", function()
require("@self/patch.test")
end)
test.describe("server", function()
require("@self/server.test")
end)
return {}

View file

@ -1,9 +1,6 @@
local config = require("../config") local config = require("../config")
local patch = require("../patch") local patch = require("../patch")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local test = suite.test
local afterEach = suite.afterEach
local function mockArraySerdes(object: {}): {} local function mockArraySerdes(object: {}): {}
if object[1] then if object[1] then
@ -23,7 +20,7 @@ local function mockArraySerdes(object: {}): {}
end end
end end
afterEach(function() test.afterEach(function()
config.fixArrays = true config.fixArrays = true
config.validatePatches = true config.validatePatches = true
end) end)

View file

@ -2,14 +2,9 @@ local Charm = require("../../Charm")
local config = require("../config") local config = require("../config")
local patch = require("../patch") local patch = require("../patch")
local server = require("../server") local server = require("../server")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local afterEach = suite.afterEach test.afterEach(function()
local beforeEach = suite.beforeEach
local describe = suite.describe
local test = suite.test
afterEach(function()
server.reset() server.reset()
end) end)
@ -252,12 +247,12 @@ test("should not send unchanged state", function()
assert(#payloads == 0, "Expected no payloads to be sent for unchanged state") assert(#payloads == 0, "Expected no payloads to be sent for unchanged state")
end) end)
describe("historical", function() test.describe("historical", function()
beforeEach(function() test.beforeEach(function()
config.preserveHistory = true config.preserveHistory = true
end) end)
afterEach(function() test.afterEach(function()
config.preserveHistory = false config.preserveHistory = false
end) end)

View file

@ -1,23 +0,0 @@
local suite = require("../../../../test/suite")
suite.describe("client", function()
require("./client.spec")
end)
suite.describe("e2e", function()
require("./e2e.spec")
end)
suite.describe("utils", function()
require("./utils.spec")
end)
suite.describe("patch", function()
require("./patch.spec")
end)
suite.describe("server", function()
require("./server.spec")
end)
return {}

View file

@ -1,9 +1,7 @@
local Charm = require("../../Charm") local Charm = require("../../Charm")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local utils = require("../utils") local utils = require("../utils")
local test = suite.test
test("should flatten functions", function() test("should flatten functions", function()
local input = { local input = {
a = Charm.atom(0), a = Charm.atom(0),

View file

@ -1,10 +1,9 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local signal = Charm.signal local signal = Charm.signal
local test = suite.test
test("should correctly propagate changes through computed core", function() test("should correctly propagate changes through computed core", function()
local src, setSrc = signal(0) local src, setSrc = signal(0)

View file

@ -1,5 +1,5 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
@ -10,7 +10,6 @@ local recursive = Charm.recursive
local setActiveSub = Charm.setActiveSub local setActiveSub = Charm.setActiveSub
local signal = Charm.signal local signal = Charm.signal
local startBatch = Charm.startBatch local startBatch = Charm.startBatch
local test = suite.test
test("should clear subscriptions when untracked by all subscribers", function() test("should clear subscriptions when untracked by all subscribers", function()
local bRunTimes = 0 local bRunTimes = 0

View file

@ -1,11 +1,10 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local effect = Charm.effect local effect = Charm.effect
local effectScope = Charm.effectScope local effectScope = Charm.effectScope
local signal = Charm.signal local signal = Charm.signal
local onCleanup = Charm.onCleanup local onCleanup = Charm.onCleanup
local test = suite.test
test("should not trigger after stop", function() test("should not trigger after stop", function()
local count, setCount = signal(1) local count, setCount = signal(1)

View file

@ -1,5 +1,5 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
type ReactiveProxy<T = any> = Charm.ReactiveProxy<T> type ReactiveProxy<T = any> = Charm.ReactiveProxy<T>
@ -8,7 +8,6 @@ local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local effectScope = Charm.effectScope local effectScope = Charm.effectScope
local reactive = Charm.reactive local reactive = Charm.reactive
local test = suite.test
local function weakRef<T>(value: T): { value: T? } local function weakRef<T>(value: T): { value: T? }
return setmetatable({ value = value }, { __mode = "v" }) :: any return setmetatable({ value = value }, { __mode = "v" }) :: any

View file

@ -0,0 +1,26 @@
local test = require("../../../tests/test")
local tests = {
"computed",
"effect",
"effectScope",
"gc",
"listen",
"mapped",
"observe",
"peek",
"reactive",
"signal",
"subscribe",
"topology",
"trigger",
"untracked",
}
for _, name in tests do
test.describe(name, function()
(require)(`@self/{name}.test`)
end)
end
return {}

View file

@ -1,10 +1,9 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local listen = Charm.listen local listen = Charm.listen
local effect = Charm.effect local effect = Charm.effect
local test = suite.test
test("should listen to selector", function() test("should listen to selector", function()
local source, setSource = signal(0) local source, setSource = signal(0)

View file

@ -1,9 +1,8 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local mapped = Charm.mapped local mapped = Charm.mapped
local test = suite.test
test("should map state", function() test("should map state", function()
local src, setSrc = signal({ 1, 2, 3 }) local src, setSrc = signal({ 1, 2, 3 })

View file

@ -1,12 +1,11 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local effectScope = Charm.effectScope local effectScope = Charm.effectScope
local observe = Charm.observe local observe = Charm.observe
local test = suite.test
test("should observe items", function() test("should observe items", function()
local items, setItems = signal({ 0, 0, 0 }) local items, setItems = signal({ 0, 0, 0 })

View file

@ -1,11 +1,10 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local peek = Charm.peek local peek = Charm.peek
local test = suite.test
test("should not run detached", function() test("should not run detached", function()
local a, setA = signal(1) local a, setA = signal(1)

View file

@ -1,10 +1,9 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local effect = Charm.effect local effect = Charm.effect
local reactive = Charm.reactive local reactive = Charm.reactive
local toRaw = Charm.toRaw local toRaw = Charm.toRaw
local test = suite.test
test("should track nested properties", function() test("should track nested properties", function()
local src, setSrc = reactive({ a = { b = { c = 0 } } }) local src, setSrc = reactive({ a = { b = { c = 0 } } })

View file

@ -1,9 +1,8 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local effect = Charm.effect local effect = Charm.effect
local test = suite.test
test("should accept equality function", function() test("should accept equality function", function()
local calls = {} local calls = {}

View file

@ -1,46 +0,0 @@
local suite = require("../../../../test/suite")
suite.describe("computed", function()
require("./computed.spec")
end)
suite.describe("effect", function()
require("./effect.spec")
end)
suite.describe("effectScope", function()
require("./effectScope.spec")
end)
suite.describe("gc", function()
require("./gc.spec")
end)
suite.describe("listen", function()
require("./listen.spec")
end)
suite.describe("mapped", function()
require("./mapped.spec")
end)
suite.describe("observe", function()
require("./observe.spec")
end)
suite.describe("peek", function()
require("./peek.spec")
end)
suite.describe("reactive", function()
require("./reactive.spec")
end)
suite.describe("signal", function()
require("./signal.spec")
end)
suite.describe("subscribe", function()
require("./subscribe.spec")
end)
suite.describe("topology", function()
require("./topology.spec")
end)
suite.describe("trigger", function()
require("./trigger.spec")
end)
suite.describe("untracked", function()
require("./untracked.spec")
end)
return {}

View file

@ -1,12 +1,11 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local computed = Charm.computed local computed = Charm.computed
local subscribe = Charm.subscribe local subscribe = Charm.subscribe
local listen = Charm.listen local listen = Charm.listen
local effect = Charm.effect local effect = Charm.effect
local test = suite.test
test("should subscribe to selector", function() test("should subscribe to selector", function()
local source, setSource = signal(0) local source, setSource = signal(0)

View file

@ -1,11 +1,9 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local atom = Charm.atom local atom = Charm.atom
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local describe = suite.describe
local test = suite.test
--[[ --[[
Tests adopted with thanks from preact-core implementation at Tests adopted with thanks from preact-core implementation at
@ -34,7 +32,7 @@ local test = suite.test
SOFTWARE SOFTWARE
]] ]]
describe("graph updates", function() test.describe("graph updates", function()
test("should drop A->B->A updates", function() test("should drop A->B->A updates", function()
-- A -- A
-- / | -- / |
@ -441,7 +439,7 @@ describe("graph updates", function()
end) end)
end) end)
describe("error handling", function() test.describe("error handling", function()
test("should keep graph consistent on errors during activation", function() test("should keep graph consistent on errors during activation", function()
local a = atom(0) local a = atom(0)
local b = computed(function() local b = computed(function()

View file

@ -1,20 +1,17 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local signal = Charm.signal local signal = Charm.signal
local subscribe = Charm.subscribe local subscribe = Charm.subscribe
local trigger = Charm.trigger local trigger = Charm.trigger
local test = suite.test
local beforeEach = suite.beforeEach
local afterEach = suite.afterEach
beforeEach(function() test.beforeEach(function()
Charm.flags.frozen = false Charm.flags.frozen = false
end) end)
afterEach(function() test.afterEach(function()
Charm.flags.frozen = true Charm.flags.frozen = true
end) end)

View file

@ -1,12 +1,11 @@
local Charm = require("../") local Charm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local signal = Charm.signal local signal = Charm.signal
local computed = Charm.computed local computed = Charm.computed
local effect = Charm.effect local effect = Charm.effect
local effectScope = Charm.effectScope local effectScope = Charm.effectScope
local untracked = Charm.untracked local untracked = Charm.untracked
local test = suite.test
test("should run detached from effect", function() test("should run detached from effect", function()
local a, setA = signal(1) local a, setA = signal(1)

View file

@ -0,0 +1,11 @@
local test = require("../../../tests/test")
test.describe("useSignalState", function()
require("@self/useSignalState.test")
end)
test.describe("useSignalBinding", function()
require("@self/useSignalBinding.test")
end)
return {}

View file

@ -1,11 +0,0 @@
local suite = require("../../../../test/suite")
suite.describe("useSignalState", function()
require("./useSignalState.spec")
end)
suite.describe("useSignalBinding", function()
require("./useSignalBinding.spec")
end)
return {}

View file

@ -1,9 +1,7 @@
local Charm = require("../../Charm") local Charm = require("../../Charm")
local ReactCharm = require("../") local ReactCharm = require("../")
local renderHook = require("./helpers/renderHook") local renderHook = require("./helpers/renderHook")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local test = suite.test
test("tracks signal state", function() test("tracks signal state", function()
local getState, setState = Charm.signal(0) local getState, setState = Charm.signal(0)

View file

@ -1,9 +1,7 @@
local Charm = require("../../Charm") local Charm = require("../../Charm")
local ReactCharm = require("../") local ReactCharm = require("../")
local renderHook = require("./helpers/renderHook") local renderHook = require("./helpers/renderHook")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local test = suite.test
test("tracks signal state", function() test("tracks signal state", function()
local getState, setState = Charm.signal(0) local getState, setState = Charm.signal(0)

View file

@ -0,0 +1,7 @@
local test = require("../../../tests/test")
test.describe("useSignalState", function()
require("@self/useSignalState.test")
end)
return {}

View file

@ -1,7 +0,0 @@
local suite = require("../../../../test/suite")
suite.describe("useSignalState", function()
require("./useSignalState.spec")
end)
return {}

View file

@ -1,9 +1,7 @@
local Charm = require("../../Charm") local Charm = require("../../Charm")
local Vide = require("../../Vide") local Vide = require("../../Vide")
local VideCharm = require("../") local VideCharm = require("../")
local suite = require("../../../../test/suite") local test = require("../../../../tests/test")
local test = suite.test
test("tracks signal state", function() test("tracks signal state", function()
local getState, setState = Charm.signal(0) local getState, setState = Charm.signal(0)

View file

@ -1,13 +1,7 @@
# This file lists tools managed by Rokit, a toolchain manager for Roblox projects.
# For more information, see https://github.com/rojo-rbx/rokit
# New tools can be added by running `rokit add <tool>` in a terminal.
[tools] [tools]
wally = "UpliftGames/wally@0.3.2" wally = "UpliftGames/wally@0.3.2"
rojo = "rojo-rbx/rojo@7.6.1" rojo = "rojo-rbx/rojo@7.6.1"
stylua = "johnnymorganz/stylua@2.3.1" stylua = "johnnymorganz/stylua@2.3.1"
selene = "Kampfkarren/selene@0.29.0" selene = "Kampfkarren/selene@0.29.0"
luau-lsp = "johnnymorganz/luau-lsp@1.56.2" luau-lsp = "johnnymorganz/luau-lsp@1.57.1"
lune = "lune-org/lune@0.10.4" lute = "luau-lang/lute@0.1.0-nightly.20251127"
lute = "luau-lang/lute@0.1.0-nightly.20251119"

View file

@ -1,6 +1,7 @@
std = "selene_defs" std = "roblox"
exclude = ["*/node_modules/*"] exclude = ["*/node_modules/*"]
[lints] [lints]
global_usage = "allow" global_usage = "allow"
shadowing = "allow" shadowing = "allow"
incorrect_standard_library_use = "allow"

View file

@ -1,6 +0,0 @@
base: roblox
name: selene_defs
globals:
require:
args:
- type: string

View file

@ -1,23 +0,0 @@
local Charm = require("../packages/charm/src")
local suite = require("./suite")
Charm.flags.strict = true
Charm.flags.frozen = true
suite.describe("charm", function()
require("../packages/charm/src/__tests__/spec")
end)
suite.describe("charm-sync", function()
require("../packages/charm-sync/src/__tests__/spec")
end)
suite.describe.ingame("react-charm", function()
require("../packages/react-charm/src/__tests__/spec")
end)
suite.describe.ingame("vide-charm", function()
require("../packages/vide-charm/src/__tests__/spec")
end)
suite.finish()

@ -1 +0,0 @@
Subproject commit eb95781a86e505cb6bff83ca568a67c7295ebb38

29
tests/run.server.luau Normal file
View file

@ -0,0 +1,29 @@
local Charm = require("../packages/charm/src")
local test = require("./test")
Charm.flags.strict = true
Charm.flags.frozen = true
local describeInRoblox = test.describeIf(function()
return game :: any ~= nil
end)
test.describe("charm", function()
require("../packages/charm/src/__tests__")
end)
test.describe("charm-sync", function()
require("../packages/charm-sync/src/__tests__")
end)
describeInRoblox("react-charm", function()
require("../packages/react-charm/src/__tests__")
end)
describeInRoblox("vide-charm", function()
require("../packages/vide-charm/src/__tests__")
end)
test.finish()
return {}

1
tests/test Submodule

@ -0,0 +1 @@
Subproject commit 7ef2b88191af884d543e7392d50c7e2adc484e32