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.