Test your QBCore scripts without spinning up a FiveM server.
Full QBCore framework mocks • 2,000+ FiveM natives • Zero dependencies • Pure Lua
Every QBCore developer knows the pain:
- Write some code
- Restart the server
- Wait for it to load
- Join with your test character
- Realize you made a typo
- Repeat
LuaGround eliminates this cycle entirely.
Run your QBCore resource logic locally. Test player functions, jobs, inventory, money, gangs, and events - all without touching a FiveM server.
- Full QBCore Mock Framework - Player objects, Functions, Jobs, Gangs, Items, Metadata
- 2,000+ FiveM Native Mocks - Auto-generated from official FiveM documentation (January 2026)
- Complete Event System -
TriggerEvent,TriggerServerEvent,TriggerClientEventwith tracking - Built-in Test Runner - BDD-style
describe/itsyntax with assertions - MySQL Mocks - oxmysql and mysql-async compatible
- Zero Dependencies - Pure Lua, runs anywhere Lua runs
- Callback System - Mock QBCore callbacks with custom return values
git clone https://github.com/YOUR_USERNAME/luaground.git
cd luagroundMake sure you have Lua or LuaJIT installed:
# Windows (scoop)
scoop install lua
# Ubuntu/Debian
sudo apt install lua5.4
# macOS
brew install luadofile('init.lua')That's it. You now have access to the full QBCore mock environment.
dofile('init.lua')
-- Create a player with default values
local player = QBCore.Player.CreateMockPlayer(1)
-- Or customize the player data
local player = QBCore.Player.CreateMockPlayer(1, {
citizenid = 'ABC12345',
charinfo = {
firstname = 'John',
lastname = 'Doe',
birthdate = '1990-01-15',
gender = 0,
phone = '555-0100'
},
money = {
cash = 1000,
bank = 50000,
crypto = 5
}
})-- Set a player's job
player.Functions.SetJob('police', 3)
-- Check job info
print(player.PlayerData.job.name) -- 'police'
print(player.PlayerData.job.label) -- 'Police'
print(player.PlayerData.job.grade.name) -- 'Sergeant'
-- Check on-duty status
player.Functions.SetJobDuty(true)
print(player.PlayerData.job.onduty) -- true-- Set a player's gang
player.Functions.SetGang('ballas', 2)
-- Check gang info
print(player.PlayerData.gang.name) -- 'ballas'
print(player.PlayerData.gang.label) -- 'Ballas'
print(player.PlayerData.gang.grade.name) -- 'OG'-- Add money
player.Functions.AddMoney('cash', 500, 'sold-item')
player.Functions.AddMoney('bank', 1000, 'paycheck')
-- Remove money
player.Functions.RemoveMoney('cash', 100, 'purchase')
-- Check balance
print(player.Functions.GetMoney('cash')) -- 1400
print(player.Functions.GetMoney('bank')) -- 51000-- Add items
player.Functions.AddItem('water', 5)
player.Functions.AddItem('lockpick', 1, nil, { quality = 100 })
-- Remove items
player.Functions.RemoveItem('water', 2)
-- Check inventory
local item = player.Functions.GetItemByName('water')
print(item.amount) -- 3
-- Check if player has item
local hasItem = player.Functions.HasItem('lockpick')
print(hasItem) -- true-- Set metadata
player.Functions.SetMetaData('hunger', 80)
player.Functions.SetMetaData('thirst', 65)
player.Functions.SetMetaData('stress', 10)
-- Get metadata
print(player.Functions.GetMetaData('hunger')) -- 80-- Trigger events
TriggerServerEvent('myresource:sellItem', 'water', 5)
TriggerClientEvent('myresource:notify', 1, 'Item sold!')
-- Check if events were fired
if TestHelper.wasEventTriggered('myresource:sellItem') then
local args = TestHelper.getEventArgs('myresource:sellItem')
print(args[1]) -- 'water'
print(args[2]) -- 5
end-- Mock native returns
MockReturnValue['GetEntityCoords'] = vector3(100.0, 200.0, 30.0)
MockReturnValue['GetPlayerPed'] = 12345
MockReturnValue['IsEntityDead'] = false
-- Mock callback returns
MockReturnValue['Callback:qb-inventory:server:GetItemList'] = {
{ name = 'water', amount = 5 },
{ name = 'bread', amount = 3 }
}
-- Mock MySQL returns
MockReturnValue['MySQL:SELECT * FROM players WHERE citizenid = ?'] = {
{ citizenid = 'ABC123', name = 'John Doe' }
}LuaGround includes a full test runner with BDD-style syntax.
dofile('init.lua')
dofile('tests/test_helper.lua')
TestHelper.run(function()
describe('My Resource Tests', function()
it('should pay player for completing delivery', function()
TestHelper.reset()
local player = TestHelper.createMockPlayer(1)
player.Functions.SetJob('trucker', 0)
-- Your resource logic
local payment = 150
player.Functions.AddMoney('bank', payment, 'delivery-complete')
-- Assertions
assert_equal(5150, player.Functions.GetMoney('bank'))
end)
it('should remove item when used', function()
TestHelper.reset()
local player = TestHelper.createMockPlayer(1)
player.Functions.AddItem('bandage', 3)
-- Simulate using item
player.Functions.RemoveItem('bandage', 1)
local item = player.Functions.GetItemByName('bandage')
assert_equal(2, item.amount)
end)
it('should fire correct events', function()
TestHelper.reset()
TriggerServerEvent('myresource:requestData', 'player_stats')
assert_true(TestHelper.wasEventTriggered('myresource:requestData'))
local args = TestHelper.getEventArgs('myresource:requestData')
assert_equal('player_stats', args[1])
end)
end)
end)| Assertion | Description |
|---|---|
assert_equal(expected, actual, msg) |
Check equality |
assert_not_equal(expected, actual, msg) |
Check inequality |
assert_true(value, msg) |
Check truthy |
assert_false(value, msg) |
Check falsy |
assert_nil(value, msg) |
Check nil |
assert_not_nil(value, msg) |
Check not nil |
assert_type(type, value, msg) |
Check type |
assert_contains(haystack, needle, msg) |
Check contains |
assert_throws(fn, msg) |
Check throws error |
lua tests/example_test.luaOr with LuaJIT for better performance:
luajit tests/example_test.lualuaground/
├── init.lua # Main loader - start here
├── builder/
│ └── fetch_fivem.js # Native generator (Node.js)
├── client/
│ ├── natives.lua # GTA V natives (~18,000 lines)
│ └── cfx.lua # CFX client natives
├── server/
│ └── cfx.lua # CFX server natives
├── fivem/
│ ├── globals.lua # Vectors, JSON, MySQL, Convars
│ └── events.lua # Event system mock
├── qbcore/
│ ├── init.lua # QBCore initialization
│ ├── player.lua # Player object mock
│ ├── functions_client.lua # Client-side QBCore.Functions
│ └── functions_server.lua # Server-side QBCore.Functions
└── tests/
├── test_helper.lua # Test utilities & assertions
└── example_test.lua # Example test suite
The native mocks are auto-generated from FiveM's official documentation. To pull the latest:
cd builder
node fetch_fivem.jsThis fetches from:
https://runtime.fivem.net/doc/natives.json- GTA V nativeshttps://runtime.fivem.net/doc/natives_cfx.json- CFX natives
The framework ships with common QBCore jobs and gangs:
Jobs: unemployed, police, ambulance
Gangs: none, ballas, vagos
Add more in qbcore/init.lua:
QBCore.Shared.Jobs['mechanic'] = {
label = 'Mechanic',
defaultDuty = true,
offDutyPay = false,
grades = {
['0'] = { name = 'Trainee', payment = 50 },
['1'] = { name = 'Mechanic', payment = 75 },
['2'] = { name = 'Senior Mechanic', payment = 100 },
['3'] = { name = 'Manager', payment = 150 }
}
}- Unit test your resources before deploying to production
- CI/CD pipelines - run tests on every commit
- Rapid prototyping - test logic without server restarts
- Debug complex systems - isolate and test specific functions
- Onboard new developers - let them experiment safely
- Fork the repository
- Create your feature branch (
git checkout -b feature/sick-feature) - Commit your changes (
git commit -m 'Add sick feature') - Push to the branch (
git push origin feature/sick-feature) - Open a Pull Request
MIT License - see LICENSE for details.
Created by viscosity on behalf of the Black Mesa RP Community
Built with respect for the QBCore Framework and FiveM communities.