Skip to content

Testing

shiva-test is a lightweight test runner for Shiva modules. Tests run with stock lua5.4 — no live FiveM server required.

Install

bash
npm install -g @shiva-fw/cli
shiva make:test my-module

Or manually:

bash
luarocks install shiva-test

Setup

Each test file calls Test.setup() before writing any tests.

lua
-- spec/FishingService_spec.lua
Test.setup({
    mode      = 'server',              -- 'server' | 'client'
    framework = 'shiva',               -- 'shiva' | 'qbcore' | 'esx' | 'ox' | 'none'
})

Writing Tests

lua
Test.describe('FishingService', function()

    Test.beforeEach(function()
        Test.db.reset()
    end)

    Test.it('awards fish on successful catch', function()
        Test.db.execute([[
            INSERT INTO players (id, name) VALUES (1, 'TestPlayer')
        ]])

        local service = FishingService.new()
        service:catch(1, 'tuna')

        local row = Test.db.single('SELECT * FROM fishing_log WHERE player_id = 1')
        Test.expect(row).not_:toBeNil()
        Test.expect(row.fish_type):toBe('tuna')
    end)

    Test.it('fires the fishing:caught event', function()
        local service = FishingService.new()
        service:catch(1, 'salmon')

        Test.assertEventFired('fishing:caught', function(payload)
            return payload.playerId == 1 and payload.fish == 'salmon'
        end)
    end)

end)

Test.expect Assertions

lua
Test.expect(value):toBe(expected)         -- strict equality (==)
Test.expect(value):toEqual(expected)      -- deep equality
Test.expect(value):toBeNil()
Test.expect(value):not_:toBeNil()
Test.expect(value):toBeTrue()
Test.expect(value):toBeFalse()
Test.expect(value):toContain(item)        -- table contains item
Test.expect(value):toMatch(pattern)       -- string matches Lua pattern
Test.expect(fn):toThrow(msg?)             -- function throws an error

Database Helpers

Test.db wraps a local SQLite database that resets between tests.

lua
Test.db.execute(sql, params?)     -- run a statement
Test.db.query(sql, params?)       -- return multiple rows
Test.db.single(sql, params?)      -- return one row or nil
Test.db.reset()                   -- clear all tables

Event Assertions

lua
-- Assert an event was fired (optionally matching a payload predicate)
Test.assertEventFired('fishing:caught')
Test.assertEventFired('fishing:caught', function(payload)
    return payload.playerId == 42
end)

-- Assert an event was NOT fired
Test.assertEventNotFired('fishing:caught')

Mocking Exports

lua
Test.mockExport('shiva-inventory', 'addItem', function(playerId, item, amount)
    return true
end)

Running Tests

bash
shiva test                      # all modules
shiva test my-module            # single module
lua5.4 spec/FishingService_spec.lua   # direct run

shiva test --watch              # re-run on file change
shiva test --coverage           # generate coverage report

CI Integration

Tests run automatically in CI via the shiva test command. See .github/workflows/ for the workflow configuration.

See Also

Released under the MIT License.