API Reference
Inside Tests¶
describe¶
describe(phrase: string, callback(context: table))
This function creates a new describe block. These blocks correspond to the things that are being tested.
Put it blocks inside of describe blocks to describe what behavior should be correct.
For example:
describe("This cheese", function()
it("should be moldy", function()
expect(cheese.moldy).to.equal(true)
end)
end)
it¶
it(phrase: string, callback(context: table))
This function creates a new 'it' block. These blocks correspond to the behaviors that should be expected of the thing you're testing.
For example:
it("should add 1 and 1", function()
expect(1 + 1).to.equal(2)
end)
expect¶
expect(value: any)
Creates a new Expectation, used for testing the properties of the given value.
Expectations are intended to be read like English assertions. These are all true:
-- Equality
expect(1).to.equal(1)
expect(1).never.to.equal(2)
-- Approximate equality
expect(5).to.be.near(5 + 1e-8)
expect(5).to.be.near(5 - 1e-8)
expect(math.pi).never.to.be.near(3)
-- Optional limit parameter
expect(math.pi).to.be.near(3, 0.2)
-- Nil checking
expect(1).to.be.ok()
expect(false).to.be.ok()
expect(nil).never.to.be.ok()
-- Type checking
expect(1).to.be.a("number")
expect(newproxy(true)).to.be.a("userdata")
-- Function throwing
expect(function()
error("nope")
end).to.throw()
expect(function()
-- I don't throw!
end).never.to.throw()
expect(function()
error("nope")
end).to.throw("nope")
expect(function()
error("foo")
end).never.to.throw("bar")
Lifecycle hooks¶
The lifecycle hooks are a collection of blocks similar to it blocks. They
can be used to collect setup and teardown code into a common place.
When placed in an init.spec.lua file, these hooks will run for all tests
within that folder.
Note
The callbacks in the lifecycle hooks are run after all describe blocks'
callbacks. Be careful not to count on setup or teardown code applying to
code not inside an it block.
afterAll¶
afterAll(callback(context: table))
Returns a function after all the tests within its scope run. This is useful if you want to clean up some global state that is used by other tests within its scope.
For example:
local DEFAULT_STATE = {
hello = "world",
}
local globalState = DEFAULT_STATE
afterAll(function()
globalState = DEFAULT_STATE
end)
it("SHOULD read globalState", function()
expect(globalState.hello).to.equal("world")
end)
it("SHOULD insert globalState", function()
globalState.foo = "bar"
expect(globalState.foo).to.equal("bar")
end)
Note
If you want to run some cleanup after every test instead of all tests, use afterEach instead.
afterEach¶
afterEach(callback(context: table))
Returns a function after each of the tests within its scope. This is useful if you want to cleanup some temporary state that is created by each test. It is always ran regardless of if the test failed or not.
local DEFAULT_STATE = {
hello = "world",
}
local globalState = DEFAULT_STATE
afterEach(function()
globalState = DEFAULT_STATE
end)
it("SHOULD insert globalState", function()
globalState.foo = "bar"
expect(globalState.foo).to.equal("bar")
end)
it("SHOULD read globalState", function()
expect(globalState.hello).to.equal("world")
end)
beforeAll¶
beforeAll(callback(context: table))
For example:
local globalState = {}
beforeAll(function()
globalState.foo = "bar"
end)
it("SHOULD have access to globalState", function()
expect(globalState.foo).to.equal("bar")
end)
Note
If you want to run a function before each test instead of before all tests, use beforeEach instead.
beforeEach¶
beforeEach(callback(context: table))
Runs a function before each of the tests within its scope. This is useful if you want to reset global state that will be used by other tests within its scope.
For example:
local globalState = {}
beforeEach(function()
globalState.foo = 100
end)
it("SHOULD be able to read foo", function()
expect(globalState.foo).to.equal(100)
end)
it("SHOULD be able to write foo", function()
globalState.foo = globalState.foo / 2
expect(globalState.foo).to.equal(50)
end)
Note
If you only need to run some setup code once, before any tests run, use beforeAll instead.
Maintenance and Debugging¶
FIXME¶
FIXME(optionalMessage: string)
When called inside a describe block, FIXME is used to identify broken tests and marks the block as skipped.
Note
FIXME does not work inside an it block. The bodies of these blocks aren't executed until the tests run, which is too late to change which tests will run.
FOCUS¶
FOCUS()
When called inside a describe block, FOCUS() marks that block as focused. If there are any focused blocks inside your test tree, only focused blocks will be executed, and all other tests will be skipped.
When you're writing a new set of tests as part of a larger codebase, use FOCUS() while debugging them to reduce the amount of noise you need to scroll through.
For example:
describe("Secret Feature X", function()
FOCUS()
it("should do something", function()
end)
end)
describe("Secret Feature Y", function()
it("should do nothing", function()
-- This code will not run!
end)
end)
Note
FOCUS does not work inside an it block. The bodies of these blocks aren't executed until the tests run, which is too late to change which tests will run.
SKIP¶
SKIP()
This function works similarly to FOCUS(), except instead of marking a block as focused, it will mark a block as skipped, which stops any of the test assertions in the block from being executed.
Note
SKIP does not work inside an it block. The bodies of these blocks aren't executed until the tests run, which is too late to change which tests will run.
describeFOCUS and describeSKIP¶
describeFOCUS(phrase: string)
describeSKIP(phrase: string)
These methods are special versions of describe that automatically mark the describe block as focused or skipped.
Note
fdescribe is an alias for describeFOCUS.
xdescribe is an alias for describeSKIP.
itFOCUS, itSKIP, and itFIXME¶
itFOCUS(phrase: string, callback(context: table))
itSKIP(phrase: string, callback(context: table))
itFIXME(phrase: string, callback(context: table))
These methods are special versions of it that automatically mark the it block as focused or skipped. They're necessary because FOCUS, SKIP, and FIXME can't be called inside it blocks!
Note
fit is an alias for itFOCUS.
xit is an alias for itSKIP.
init.spec.lua¶
When loading a spec file, TestEZ creates a new describe block for each file
and for each folder those files are in. If the file is called init.spec.lua,
TestEZ will not create a new describe block for it and instead attach any code
inside to the folder's describe block. For more on one situation when this
would be useful, see the section on lifecycle hooks.
Context¶
As mentioned, init.spec.lua allows code to be run as part of a directory's
otherwise-implicit block, and the lifecycle hooks allow setup and teardown code
to be run for all tests within a block. This does indeed mean that a hook inside
an init file will run for all tests in that directory. While hooks within the
same file can pass extra information along to tests via upvalues, hooks in an
init file must use the context.
context is a write-once table that is passed in to the callbacks for lifecycle
hooks and it blocks. Entries in this table are only available to blocks within
the current describe block. This means it's safe to add entries without
worrying about influencing tests elsewhere in the tree.
-- init.spec.lua
return function()
beforeAll(function(context)
context.helpers = require(script.Parent.helpers)
end)
end
-- test.spec.lua
return function()
it("a test using a helper", function(context)
local user = context.helpers.makeUser(123)
-- ...
end)
end
Note
Context is not available to describe blocks since they run before any
lifecycle hooks or it blocks.