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
- name: Check code quality
run: sh bin/check.sh
run: pnpm check
- name: Run tests
run: lune run test/spec.server.luau
run: pnpm test
- name: Build models
run: sh bin/build.sh
run: pnpm build

4
.gitmodules vendored
View file

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

14
.luaurc
View file

@ -1,6 +1,10 @@
{
"languageMode": "strict",
"lint": {
"LocalShadow": false
}
}
"languageMode": "strict",
"aliases": {
"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": {
"$path": "node_modules/@rbxts-js"
},
"test": {
"$path": "test"
"tests": {
"$path": "tests"
}
}
}

View file

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

View file

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

View file

@ -2,12 +2,9 @@ local Charm = require("../../Charm")
local client = require("../client")
local config = require("../config")
local server = require("../server")
local suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local afterEach = suite.afterEach
local test = suite.test
afterEach(function()
test.afterEach(function()
server.reset()
client.removeAllSignals()
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 patch = require("../patch")
local suite = require("../../../../test/suite")
local test = suite.test
local afterEach = suite.afterEach
local test = require("../../../../tests/test")
local function mockArraySerdes(object: {}): {}
if object[1] then
@ -23,7 +20,7 @@ local function mockArraySerdes(object: {}): {}
end
end
afterEach(function()
test.afterEach(function()
config.fixArrays = true
config.validatePatches = true
end)

View file

@ -2,14 +2,9 @@ local Charm = require("../../Charm")
local config = require("../config")
local patch = require("../patch")
local server = require("../server")
local suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local afterEach = suite.afterEach
local beforeEach = suite.beforeEach
local describe = suite.describe
local test = suite.test
afterEach(function()
test.afterEach(function()
server.reset()
end)
@ -252,12 +247,12 @@ test("should not send unchanged state", function()
assert(#payloads == 0, "Expected no payloads to be sent for unchanged state")
end)
describe("historical", function()
beforeEach(function()
test.describe("historical", function()
test.beforeEach(function()
config.preserveHistory = true
end)
afterEach(function()
test.afterEach(function()
config.preserveHistory = false
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 suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local utils = require("../utils")
local test = suite.test
test("should flatten functions", function()
local input = {
a = Charm.atom(0),

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
local Charm = require("../")
local suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
type ReactiveProxy<T = any> = Charm.ReactiveProxy<T>
@ -8,7 +8,6 @@ local computed = Charm.computed
local effect = Charm.effect
local effectScope = Charm.effectScope
local reactive = Charm.reactive
local test = suite.test
local function weakRef<T>(value: T): { value: T? }
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 suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local signal = Charm.signal
local listen = Charm.listen
local effect = Charm.effect
local test = suite.test
test("should listen to selector", function()
local source, setSource = signal(0)

View file

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

View file

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

View file

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

View file

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

View file

@ -1,9 +1,8 @@
local Charm = require("../")
local suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local signal = Charm.signal
local effect = Charm.effect
local test = suite.test
test("should accept equality function", function()
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 suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local signal = Charm.signal
local computed = Charm.computed
local subscribe = Charm.subscribe
local listen = Charm.listen
local effect = Charm.effect
local test = suite.test
test("should subscribe to selector", function()
local source, setSource = signal(0)

View file

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

View file

@ -1,20 +1,17 @@
local Charm = require("../")
local suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local computed = Charm.computed
local effect = Charm.effect
local signal = Charm.signal
local subscribe = Charm.subscribe
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
end)
afterEach(function()
test.afterEach(function()
Charm.flags.frozen = true
end)

View file

@ -1,12 +1,11 @@
local Charm = require("../")
local suite = require("../../../../test/suite")
local test = require("../../../../tests/test")
local signal = Charm.signal
local computed = Charm.computed
local effect = Charm.effect
local effectScope = Charm.effectScope
local untracked = Charm.untracked
local test = suite.test
test("should run detached from effect", function()
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 ReactCharm = require("../")
local renderHook = require("./helpers/renderHook")
local suite = require("../../../../test/suite")
local test = suite.test
local test = require("../../../../tests/test")
test("tracks signal state", function()
local getState, setState = Charm.signal(0)

View file

@ -1,9 +1,7 @@
local Charm = require("../../Charm")
local ReactCharm = require("../")
local renderHook = require("./helpers/renderHook")
local suite = require("../../../../test/suite")
local test = suite.test
local test = require("../../../../tests/test")
test("tracks signal state", function()
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 Vide = require("../../Vide")
local VideCharm = require("../")
local suite = require("../../../../test/suite")
local test = suite.test
local test = require("../../../../tests/test")
test("tracks signal state", function()
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]
wally = "UpliftGames/wally@0.3.2"
rojo = "rojo-rbx/rojo@7.6.1"
stylua = "johnnymorganz/stylua@2.3.1"
selene = "Kampfkarren/selene@0.29.0"
luau-lsp = "johnnymorganz/luau-lsp@1.56.2"
lune = "lune-org/lune@0.10.4"
lute = "luau-lang/lute@0.1.0-nightly.20251119"
luau-lsp = "johnnymorganz/luau-lsp@1.57.1"
lute = "luau-lang/lute@0.1.0-nightly.20251127"

View file

@ -1,6 +1,7 @@
std = "selene_defs"
std = "roblox"
exclude = ["*/node_modules/*"]
[lints]
global_usage = "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