mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 06:14:59 +00:00
Lua Test Package
A unit testing framework for Lua scripts in MetaBuilder packages.
Features
- BDD-style syntax:
describe/itblocks for organizing tests - Rich assertions:
expect()with chainable matchers - Mocks and spies: Track function calls and replace implementations
- Lifecycle hooks:
beforeAll,afterAll,beforeEach,afterEach - Test filtering: Run specific tests with
.onlyor name filters - Detailed reporting: Text and JSON output formats
Package Integration
To use lua_test in your package, add it as a devDependency and declare your test files in metadata.json:
{
"packageId": "my_package",
"name": "My Package",
"version": "1.0.0",
"dependencies": ["ui_permissions"],
"devDependencies": ["lua_test"],
"exports": {
"scripts": ["my_script"]
},
"tests": {
"scripts": [
"tests/my_script.test.lua"
]
}
}
Place your test files in seed/scripts/tests/:
packages/my_package/
├── seed/
│ ├── metadata.json
│ └── scripts/
│ ├── my_script.lua
│ └── tests/
│ └── my_script.test.lua
Quick Start
local framework = require("lua_test/framework")
local assertions = require("lua_test/assertions")
local describe = framework.describe
local it = framework.it
local expect = assertions.expect
describe("My Module", function()
it("should do something", function()
expect(1 + 1).toBe(2)
end)
it("should handle strings", function()
expect("hello").toContain("ell")
expect("hello").toHaveLength(5)
end)
end)
Assertions
Basic Matchers
expect(value).toBe(expected) -- Strict equality (==)
expect(value).toEqual(expected) -- Deep equality for tables
expect(value).toBeNil() -- Check for nil
expect(value).toBeTruthy() -- Truthy check
expect(value).toBeFalsy() -- Falsy check
expect(value).toBeType("string") -- Type check
Comparison Matchers
expect(num).toBeGreaterThan(5)
expect(num).toBeLessThan(10)
expect(3.14159).toBeCloseTo(3.14, 2) -- Floating point comparison
String Matchers
expect(str).toContain("substring")
expect(str).toMatch("^pattern") -- Lua pattern matching
expect(str).toHaveLength(5)
Collection Matchers
expect(table).toContain(element)
expect(table).toHaveLength(3)
expect(table).toHaveProperty("key")
expect(table).toHaveProperty("key", value)
Error Matchers
expect(function() error("boom") end).toThrow()
expect(function() error("boom") end).toThrow("boom")
Negation
Use .never to negate any matcher:
expect(5).never.toBe(10)
expect("hello").never.toContain("world")
Mocks
Mock Functions
local mocks = require("lua_test/mocks")
local mockFn = mocks.fn(function(x) return x * 2 end)
mockFn(5)
mockFn(10)
mockFn.getCallCount() -- 2
mockFn.wasCalled() -- true
mockFn.wasCalledWith(5) -- true
mockFn.getLastCall() -- {10}
mockFn.getCalls() -- {{5}, {10}}
Mock Return Values
local mockFn = mocks.fn()
mockFn.mockReturnValue(42)
mockFn() -- 42
mockFn() -- 42
-- Or return different values
mockFn.mockReturnValueOnce(1)
mockFn.mockReturnValueOnce(2)
mockFn() -- 1
mockFn() -- 2
mockFn() -- nil (or previous mockReturnValue)
Spies
local myModule = { calculate = function(x) return x * 2 end }
local spy = mocks.spyOn(myModule, "calculate")
myModule.calculate(5)
spy.getCallCount() -- 1
spy.wasCalledWith(5) -- true
spy.mockRestore() -- Restore original function
Lifecycle Hooks
describe("My Suite", function()
beforeAll(function()
-- Run once before all tests in this suite
end)
afterAll(function()
-- Run once after all tests in this suite
end)
beforeEach(function()
-- Run before each test
end)
afterEach(function()
-- Run after each test
end)
it("test 1", function() end)
it("test 2", function() end)
end)
Test Filtering
Skip Tests
xit("this test is skipped", function()
-- Won't run
end)
Focus Tests
fit("only this test runs", function()
-- Other tests in the suite are skipped
end)
Filter by Name
framework.configure({ filter = "validation" })
-- Only tests with "validation" in their name will run
Running Tests
local runner = require("lua_test/runner")
local framework = require("lua_test/framework")
-- Define your tests with describe/it
-- ...
-- Run all suites
local results = runner.runAll(framework.getSuites())
-- Print report
print(runner.formatReport(results))
-- Or get JSON for programmatic use
local json = runner.formatJSON(results)
Helpers
local helpers = require("lua_test/helpers")
-- Generate test data
local users = helpers.generateTestData({
id = "$index",
name = function(i) return "User " .. i end,
score = "$random"
}, 10)
-- Table utilities
helpers.table.clone(t)
helpers.table.merge(t1, t2)
helpers.table.keys(t)
helpers.table.values(t)
helpers.table.size(t)
-- String utilities
helpers.string.trim(s)
helpers.string.split(s, delimiter)
helpers.string.startsWith(s, prefix)
helpers.string.endsWith(s, suffix)
-- Create test context
local ctx = helpers.createContext({ user = nil })
ctx.set("user", { name = "Alice" })
ctx.get("user")
ctx.reset()
Example: Testing a Package
-- tests/validate.test.lua
local framework = require("lua_test/framework")
local assertions = require("lua_test/assertions")
local runner = require("lua_test/runner")
local describe = framework.describe
local it = framework.it
local beforeEach = framework.beforeEach
local expect = assertions.expect
-- Import the module to test
local validate = require("ui_login/validate")
describe("ui_login validation", function()
describe("login", function()
it("should reject empty username", function()
local result = validate.login({ username = "", password = "password123" })
expect(result.valid).toBe(false)
expect(result.errors[1].field).toBe("username")
end)
it("should accept valid credentials", function()
local result = validate.login({ username = "user", password = "password123" })
expect(result.valid).toBe(true)
end)
end)
end)
-- Run and report
local results = runner.runAll(framework.getSuites())
print(runner.formatReport(results))
Output Example
═══════════════════════════════════════
TEST RESULTS REPORT
═══════════════════════════════════════
📦 ui_login validation
📦 login
✅ should reject empty username (0.12ms)
✅ should accept valid credentials (0.08ms)
📦 register
✅ should reject invalid email (0.15ms)
✅ should accept valid registration (0.10ms)
───────────────────────────────────────
Summary:
Total: 4 tests
Passed: 4 ✅
Failed: 0 ❌
Skipped: 0 ⏭️
Duration: 0.45ms
🎉 All tests passed!
═══════════════════════════════════════