Skip to content
This repository has been archived by the owner on Sep 14, 2024. It is now read-only.

Added beforeAll, beforeEach, afterEach, afterAll lifecycle hooks for testing #57

Merged
merged 24 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e26ec2b
Rough implementation of lifecycle hooks (before/after (each))
inversion Apr 18, 2019
6850da6
always run after hooks
inversion Apr 30, 2019
dc1ea45
Merge branch 'master' of https://github.com/Roblox/testez into revive…
benbrimeyer Jan 14, 2020
1a4efbf
tests are failing, but we have a new test now
benbrimeyer Jan 15, 2020
3fac9b0
its functional with basic tests passing
benbrimeyer Jan 15, 2020
bd3d2b8
refactored lifecycle hooks to use runTestPlan helper function
benbrimeyer Jan 15, 2020
958c064
update luacheckrc to accept testEZ globals
benbrimeyer Jan 15, 2020
4ab1007
clean up lifecycleHooks.lua some more
benbrimeyer Jan 15, 2020
1d584f0
beforeAll, beforeEach, and afterEach throwing will fail test node
benbrimeyer Jan 15, 2020
a3fbe15
fixed single quotes to double quotes
benbrimeyer Jan 15, 2020
2469f65
reorganized LifecycleHooks.lua
benbrimeyer Jan 15, 2020
10d5182
link to jest spec test
benbrimeyer Jan 15, 2020
ced703f
formatting in TestRunner
benbrimeyer Jan 15, 2020
dfc44bd
moves lifecycleHooks error tests to end
benbrimeyer Jan 15, 2020
fa8e9c5
Added entry to CHANGELOG.md
benbrimeyer Jan 15, 2020
3f3f069
Cleans up formatting with single to double quotes
benbrimeyer Jan 15, 2020
7db7e85
comment on intentially missing afterAll
benbrimeyer Jan 16, 2020
1cdd1b6
Consistent hook prefix
benbrimeyer Jan 16, 2020
c698915
updated luacheckrc to focus testez globals on lifecycleHooks.lua only
benbrimeyer Jan 16, 2020
6810ffe
remove extra new line at end of files
benbrimeyer Jan 16, 2020
7730555
remove stack from lifecycleHooks.lua
benbrimeyer Jan 18, 2020
960e2d7
add runNode function in TestRunner to simplify statement and add earl…
benbrimeyer Jan 18, 2020
0e16e7b
changed assertion into error for string formatting reasons
benbrimeyer Jan 18, 2020
a16bbfe
Merge branch 'master' into revive-lifecycle
benbrimeyer Jan 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/luacov.*
/site
/site
/lua_install
10 changes: 10 additions & 0 deletions .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,18 @@ stds.roblox = {
}
}

stds.testez = {
read_globals = {
"it", "describe", "beforeAll", "beforeEach", "afterAll", "afterEach",
},
}

std = "lua51+roblox"

ignore = {
"212", -- Unused argument, which triggers on unused 'self' too
}

files["tests/lifecycleHooks.lua"] = {
std = "+testez",
}
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# TestEZ Changelog

## Current master
* No changes
* Added beforeAll, beforeEach, afterEach, afterAll lifecycle hooks for testing
* The setup and teardown behavior of these hooks attempt to reach feature parity with [jest](https://jestjs.io/docs/en/setup-teardown).


## 0.1.0 (2019-11-01)
* Initial release.
* Initial release.
169 changes: 169 additions & 0 deletions lib/LifecycleHooks.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
local TestEnum = require(script.Parent.TestEnum)

local LifecycleHooks = {}
LifecycleHooks.__index = LifecycleHooks

function LifecycleHooks.new()
local self = {
_stack = {},
}
setmetatable(self, LifecycleHooks)
return self
benbrimeyer marked this conversation as resolved.
Show resolved Hide resolved
end

--[[
Returns an array of `beforeEach` hooks in FIFO order
]]
function LifecycleHooks:getBeforeEachHooks()
local key = TestEnum.NodeType.BeforeEach
local hooks = {}

for _, level in ipairs(self._stack) do
for _, hook in ipairs(level[key]) do
table.insert(hooks, hook)
end
end

return hooks
end

--[[
Returns an array of `afterEach` hooks in FILO order
]]
function LifecycleHooks:getAfterEachHooks()
local key = TestEnum.NodeType.AfterEach
local hooks = {}
for _, level in ipairs(self._stack) do
for _, hook in ipairs(level[key]) do
table.insert(hooks, 1, hook)
end
end

return hooks
end

--[[
Pushes uncalled beforeAll and afterAll hooks back up the stack
]]
function LifecycleHooks:popHooks()
local popped = self._stack[#self._stack]
table.remove(self._stack, #self._stack)

local function pushHooksUp(type)

local back = self:_getBackOfStack()

if not back then
return
end

back[type] = popped[type]
end

pushHooksUp(TestEnum.NodeType.BeforeAll)
pushHooksUp(TestEnum.NodeType.AfterAll)
end

function LifecycleHooks:pushHooksFrom(planNode)
assert(planNode ~= nil)

table.insert(self._stack, {
[TestEnum.NodeType.BeforeAll] = self:_getBeforeAllHooksUncalledAtCurrentLevel(planNode.children),
[TestEnum.NodeType.AfterAll] = self:_getAfterAllHooksUncalledAtCurrentLevel(planNode.children),
[TestEnum.NodeType.BeforeEach] = self:_getHooksOfType(planNode.children, TestEnum.NodeType.BeforeEach),
[TestEnum.NodeType.AfterEach] = self:_getHooksOfType(planNode.children, TestEnum.NodeType.AfterEach),
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a mouthful!

end

function LifecycleHooks:getPendingBeforeAllHooks()
return self:_getAndClearPendingHooks(TestEnum.NodeType.BeforeAll)
end

function LifecycleHooks:getAfterAllHooks()
if #self._stack > 0 then
return self:_getAndClearPendingHooks(TestEnum.NodeType.AfterAll)
else
return {}
end
end

--[[
Return any hooks that have not yet been returned for this key and clear those hooks
]]
function LifecycleHooks:_getAndClearPendingHooks(key)
assert(key ~= nil)

if #self._stack > 0 then

local back = self._stack[#self._stack]

local hooks = back[key]

back[key] = {}

return hooks
else
return {}
end
benbrimeyer marked this conversation as resolved.
Show resolved Hide resolved
end

--[[
Transfers uncalled beforeAll and afterAll hooks down the stack
]]
function LifecycleHooks:_getBeforeAllHooksUncalledAtCurrentLevel(childNodes)
local hookType = TestEnum.NodeType.BeforeAll
local hooks = self:_getHooksOfTypeFromBackOfStack(hookType)

for _, hook in pairs(self:_getHooksOfType(childNodes, hookType)) do
table.insert(hooks, hook)
end

return hooks
end

function LifecycleHooks:_getAfterAllHooksUncalledAtCurrentLevel(childNodes)
local hookType = TestEnum.NodeType.AfterAll
local hooks = self:_getHooksOfTypeFromBackOfStack(hookType)

for _, hook in pairs(self:_getHooksOfType(childNodes, hookType)) do
table.insert(hooks, 1, hook)
end

return hooks
end

function LifecycleHooks:_getHooksOfTypeFromBackOfStack(hookType)
assert(hookType, "Expected hookType to be an argument")

local currentBack = self:_getBackOfStack()

local hooks = {}

if currentBack then
for _, hook in pairs(currentBack[hookType]) do
table.insert(hooks, hook)
end

currentBack[hookType] = {}
end

return hooks
end

function LifecycleHooks:_getBackOfStack()
return self._stack[#self._stack] or nil
end
benbrimeyer marked this conversation as resolved.
Show resolved Hide resolved

function LifecycleHooks:_getHooksOfType(nodes, type)
local hooks = {}

for _, node in pairs(nodes) do
if node.type == type then
table.insert(hooks, node.callback)
end
end

return hooks
end

return LifecycleHooks
6 changes: 5 additions & 1 deletion lib/TestEnum.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ TestEnum.TestStatus = {
TestEnum.NodeType = {
Try = "Try",
Describe = "Describe",
It = "It"
It = "It",
BeforeAll = "BeforeAll",
AfterAll = "AfterAll",
BeforeEach = "BeforeEach",
AfterEach = "AfterEach"
}

TestEnum.NodeModifier = {
Expand Down
21 changes: 21 additions & 0 deletions lib/TestPlanner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,27 @@ function TestPlanner.createEnvironment(builder, extraEnvironment)
builder:popNode()
end

-- Incrementing counter used to ensure that beforeAll, afterAll, beforeEach, afterEach have unique phrases
local lifecyclePhaseId = 0

local lifecycleHooks = {
[TestEnum.NodeType.BeforeAll] = "beforeAll",
[TestEnum.NodeType.AfterAll] = "afterAll",
[TestEnum.NodeType.BeforeEach] = "beforeEach",
[TestEnum.NodeType.AfterEach] = "afterEach"
}

for nodeType, name in pairs(lifecycleHooks) do
env[name] = function(callback)
local node = builder:pushNode(name .. "_" .. tostring(lifecyclePhaseId), nodeType)
lifecyclePhaseId = lifecyclePhaseId + 1

node.callback = callback

builder:popNode()
end
end

function env.itFOCUS(phrase, callback)
local node = builder:pushNode(phrase, TestEnum.NodeType.It, TestEnum.NodeModifier.Focus)

Expand Down
4 changes: 2 additions & 2 deletions lib/TestResults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ function TestResults:visualize(root, level)
child.planNode.phrase
)

if #child.messages > 0 then
if child.messages and #child.messages > 0 then
str = str .. "\n " .. (" "):rep(3 * level) .. table.concat(child.messages, "\n " .. (" "):rep(3 * level))
end

table.insert(buffer, str)
else
local str = ("%s%s"):format(
(" "):rep(3 * level),
child.planNode.phrase
child.planNode.phrase or ""
)

if child.status then
Expand Down
Loading