Skip to content
This repository was archived by the owner on Sep 14, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6c36a86
Collapse TestPlan/TestPlanner/TestPlanBuilder/TestEnvironment
MagiMaster May 7, 2020
a61e327
Merge remote-tracking branch 'origin/master' into masterPlan
MagiMaster May 9, 2020
b7e1877
Fix test name. Now it works as expected the first time
MagiMaster May 9, 2020
ab4a9ac
Add a more explicit check of duplicate nodes
MagiMaster May 9, 2020
7084dad
Merge branch 'fixTest' into masterPlan
MagiMaster May 9, 2020
ff58302
Update tests of duplicate it blocks to match new code
MagiMaster May 9, 2020
79c68b7
Add expectation to environment
MagiMaster May 13, 2020
ed47b2c
Add luacheck globals for new test
MagiMaster May 13, 2020
04afd68
Refactor TestNode to keep a pointer back to plan tree
MagiMaster May 14, 2020
a33e158
Update comments
MagiMaster May 14, 2020
90d935a
Typo
MagiMaster May 14, 2020
5ed50de
Remove odd plan-as-parent pointer since the plan is stored explicitly
MagiMaster May 14, 2020
0a37fb8
Remove reference to TestPlanBuilder
MagiMaster May 14, 2020
e3249cb
Tests for init.spec ordering
MagiMaster May 19, 2020
062408a
Use a finalize function to be sure order is correct
MagiMaster May 19, 2020
5ae438d
Another test to make sure init.spec and afterAll work together
MagiMaster May 19, 2020
e90c1df
Remove debug print
MagiMaster May 19, 2020
4b5a677
Expand test of lifecycle hooks
MagiMaster May 19, 2020
5265c39
Expand test of lifecycle hooks
MagiMaster May 19, 2020
815f0ee
Fix #101, change beforeAll and afterAll hook implementation
MagiMaster May 19, 2020
8bf7e43
Merge remote-tracking branch 'origin/master' into lifecycle
MagiMaster May 19, 2020
b2fc3b8
Merge remote-tracking branch 'origin/master' into expandOrder
MagiMaster May 19, 2020
ae1b2a5
Merge branch 'lifecycle' into expandOrder
MagiMaster May 19, 2020
9060717
Mention change in changelog
MagiMaster May 19, 2020
5b0d20e
Add it blocks for expand test
MagiMaster May 20, 2020
7410e38
Merge remote-tracking branch 'origin/master' into expandOrder
MagiMaster May 27, 2020
2a2a579
First pass at adding loadmodule
MagiMaster Jun 17, 2020
8b1200a
Add recursive require definition
MagiMaster Jun 18, 2020
dac8a70
Remove hooks from session tree
MagiMaster Jul 16, 2020
cd847ee
Stringify errors before processing
MagiMaster Jul 17, 2020
4e9d0c6
Add missing 2s
MagiMaster Jul 17, 2020
5c7c912
Deprecate extraEnvironment
MagiMaster Jul 17, 2020
a8f530a
Merge branch 'object-errors' into feature/loadmodule
MagiMaster Jul 21, 2020
b77d91d
Merge branch 'deprecate-extra-environment' into feature/loadmodule
MagiMaster Jul 21, 2020
a629b2e
Merge branch 'loadModule' into feature/loadmodule
MagiMaster Jul 21, 2020
2babdee
Merge branch 'expandOrder' into feature/loadmodule
MagiMaster Jul 21, 2020
f234a5e
Use a single require cache for each plan tree for now
MagiMaster Jul 22, 2020
afb973e
Removed unused variable
MagiMaster Jul 22, 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# TestEZ Changelog

## Unreleased Changes
* Remove the lifecycle hooks from the session tree. This prevents the `[?]` spam from the reporter not recognizing these nodes.
* Change the way errors are collected to call tostring on them before further processing.
* Luau allows non-string errors, but not concatenating non-strings or passing non-strings to `debug.traceback` as a message, so TestRunner needs to do that step. This is a temporary fix as the better solution would be to retain the error in object form for as long as possible to give the reporter more to work with.
* This also makes a slight change to what's in the traceback to eliminate the unnecessary line mentioning the error collection function.
* Add a deprecation notice for uses of extraEnvironment.
* Guarantee that `init.spec.lua` will run before any `it` or `describe` blocks in the folder under it.

## 0.3.1 (2020-06-22)
* Further simplify `beforeAll` handling.
Expand Down
2 changes: 1 addition & 1 deletion src/TestBootstrap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function TestBootstrap:getModulesImpl(root, modules, current)
current = current or root

if isSpecScript(current) then
local method = require(current)
local method = debug.loadmodule(current)
local path = getPath(current, root)
local pathString = toStringPath(path)

Expand Down
73 changes: 60 additions & 13 deletions src/TestPlan.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@
local TestEnum = require(script.Parent.TestEnum)
local Expectation = require(script.Parent.Expectation)

local function newEnvironment(currentNode, extraEnvironment)
local REQUIRE_CACHE_KEY = {}

local function newEnvironment(parentEnvironment, currentNode, extraEnvironment)
local env = {}

-- All nodes in a tree currently share a cache
local requireCache = parentEnvironment and parentEnvironment[REQUIRE_CACHE_KEY] or {}
env[REQUIRE_CACHE_KEY] = requireCache

if extraEnvironment then
if type(extraEnvironment) ~= "table" then
error(("Bad argument #2 to newEnvironment. Expected table, got %s"):format(
error(("Bad argument #3 to newEnvironment. Expected table, got %s"):format(

typeof(extraEnvironment)), 2)
end

Expand All @@ -25,9 +32,6 @@ local function newEnvironment(currentNode, extraEnvironment)
local function addChild(phrase, callback, nodeType, nodeModifier)
local node = currentNode:addChild(phrase, nodeType, nodeModifier)
node.callback = callback
if nodeType == TestEnum.NodeType.Describe then
node:expand()
end
return node
end

Expand Down Expand Up @@ -107,6 +111,17 @@ local function newEnvironment(currentNode, extraEnvironment)

env.expect = Expectation.new

function env.require(module)
if not requireCache[module] then
local chunk = debug.loadmodule(module)
local originalEnv = getfenv(chunk)
local newEnv = setmetatable({require = env.require}, {__index = originalEnv})
setfenv(chunk, newEnv)
requireCache[module] = chunk()
end
return requireCache[module]
end

return env
end

Expand All @@ -118,7 +133,7 @@ TestNode.__index = TestNode
and the type of node it is are required. The modifier is optional and will
be None if left blank.
]]
function TestNode.new(plan, phrase, nodeType, nodeModifier)
function TestNode.new(parent, plan, phrase, nodeType, nodeModifier)
nodeModifier = nodeModifier or TestEnum.NodeModifier.None

local node = {
Expand All @@ -131,7 +146,8 @@ function TestNode.new(plan, phrase, nodeType, nodeModifier)
parent = nil,
}

node.environment = newEnvironment(node, plan.extraEnvironment)
local parentEnvironment = parent and parent.Environment
node.environment = newEnvironment(parentEnvironment, node, plan.extraEnvironment)
return setmetatable(node, TestNode)
end

Expand All @@ -157,7 +173,7 @@ function TestNode:addChild(phrase, nodeType, nodeModifier)

local childName = self:getFullName() .. " " .. phrase
nodeModifier = getModifier(childName, self.plan.testNamePattern, nodeModifier)
local child = TestNode.new(self.plan, phrase, nodeType, nodeModifier)
local child = self:new(self.plan, phrase, nodeType, nodeModifier)
child.parent = self
table.insert(self.children, child)
return child
Expand All @@ -177,22 +193,35 @@ function TestNode:getFullName()
end

--[[
Expand a node by setting its callback environment and then calling it. Any
further it and describe calls within the callback will be added to the tree.
Expand a node by setting its callback environment and then calling it. Only
expands this one node.
]]
function TestNode:expand()
if not self.callback then
return
end

local originalEnv = getfenv(self.callback)
local callbackEnv = setmetatable({}, { __index = originalEnv })
for key, value in pairs(self.environment) do
callbackEnv[key] = value
end
setfenv(self.callback, callbackEnv)

local success, result = xpcall(self.callback, debug.traceback)
local success, result = xpcall(self.callback, function(message)
return debug.traceback(tostring(message), 2)
end)

if not success then
self.loadError = result
end

if typeof(result) == "function" then
success, result = xpcall(result, debug.traceback)
if not success then
self.loadError = result
end
end
end

local TestPlan = {}
Expand All @@ -202,6 +231,14 @@ TestPlan.__index = TestPlan
Create a new, empty TestPlan.
]]
function TestPlan.new(testNamePattern, extraEnvironment)
if extraEnvironment and next(extraEnvironment) then
warn(
"extraEnvironment is deprecated and will be removed in the near future. " ..
"Please use an init.spec.lua file and the test context to pass in anything " ..
"that is currently in extraEnvironment."
)
end

local plan = {
children = {},
testNamePattern = testNamePattern,
Expand All @@ -216,7 +253,7 @@ end
]]
function TestPlan:addChild(phrase, nodeType, nodeModifier)
nodeModifier = getModifier(phrase, self.testNamePattern, nodeModifier)
local child = TestNode.new(self, phrase, nodeType, nodeModifier)
local child = TestNode.new(nil, self, phrase, nodeType, nodeModifier)
table.insert(self.children, child)
return child
end
Expand Down Expand Up @@ -245,7 +282,17 @@ function TestPlan:addRoot(path, method)
end

curNode.callback = method
curNode:expand()
end

--[[
Expands all describe nodes, leaving the plan in a runnable state.
]]
function TestPlan:finalize()
self:visitAllNodes(function(node)
if node.type == TestEnum.NodeType.Describe then
node:expand()
end
end)
end

--[[
Expand Down
1 change: 1 addition & 0 deletions src/TestPlanner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function TestPlanner.createPlan(modulesList, testNamePattern, extraEnvironment)
plan:addRoot(module.path, module.method)
end

plan:finalize()
return plan
end

Expand Down
12 changes: 6 additions & 6 deletions src/TestRunner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function TestRunner.runPlanNode(session, planNode, lifecycleHooks)
end

success = false
errorMessage = messagePrefix .. message .. "\n" .. debug.traceback()
errorMessage = messagePrefix .. debug.traceback(tostring(message), 2)
end

local context = session:getContext()
Expand All @@ -77,7 +77,7 @@ function TestRunner.runPlanNode(session, planNode, lifecycleHooks)
callback(context)
end,
function(message)
return messagePrefix .. message .. "\n" .. debug.traceback()
return messagePrefix .. debug.traceback(tostring(message), 2)
end
)

Expand Down Expand Up @@ -134,9 +134,8 @@ function TestRunner.runPlanNode(session, planNode, lifecycleHooks)

if not halt then
for _, childPlanNode in ipairs(planNode.children) do
session:pushNode(childPlanNode)

if childPlanNode.type == TestEnum.NodeType.It then
session:pushNode(childPlanNode)
if session:shouldSkip() then
session:setSkipped()
else
Expand All @@ -148,7 +147,9 @@ function TestRunner.runPlanNode(session, planNode, lifecycleHooks)
session:setError(errorMessage)
end
end
session:popNode()
elseif childPlanNode.type == TestEnum.NodeType.Describe then
session:pushNode(childPlanNode)
TestRunner.runPlanNode(session, childPlanNode, lifecycleHooks)

-- Did we have an error trying build a test plan?
Expand All @@ -158,9 +159,8 @@ function TestRunner.runPlanNode(session, planNode, lifecycleHooks)
else
session:setStatusFromChildren()
end
session:popNode()
end

session:popNode()
end
end

Expand Down
88 changes: 88 additions & 0 deletions tests/expandOrder.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
-- luacheck: globals it beforeAll afterAll

local TestEZ = require(script.Parent.Parent.TestEZ)

return {
["init.spec.lua is run before children are expanded"] = function()
local initialized = false

local plan = TestEZ.TestPlanner.createPlan({
{
method = function()
assert(initialized, "init.spec was not called before bar.spec")
end,
path = {'bar.spec', 'foo'},
pathStringForSorting = "foo bar.spec",
},
{
method = function()
initialized = true
end,
path = {'foo'},
pathStringForSorting = "foo",
},
})

local results = TestEZ.TestRunner.runPlan(plan)
assert(#results.errors == 0, "init test failed: " .. tostring(results.errors[1]))
end,
["init.spec.lua afterAll can correctly undo changes"] = function()
local initialized = false

local plan = TestEZ.TestPlanner.createPlan({
{
method = function()
it("A", function()
assert(not initialized, "initialized was true in foo/a.spec")
end)
end,
path = {'a.spec', 'foo'},
pathStringForSorting = "foo a.spec",
},
{
method = function()
it("B", function()
assert(initialized, "initialized was false in foo/bar/b.spec")
end)
end,
path = {'b.spec', 'bar', 'foo'},
pathStringForSorting = "foo bar b.spec",
},
{
method = function()
beforeAll(function()
initialized = true
end)

afterAll(function()
initialized = false
end)
end,
path = {'bar', 'foo'},
pathStringForSorting = "foo bar",
},
{
method = function()
it("C", function()
assert(initialized, "initialized was false in foo/bar/c.spec")
end)
end,
path = {'c.spec', 'bar', 'foo'},
pathStringForSorting = "foor bar c.spec",
},
{
method = function()
it("D", function()
assert(not initialized, "initialized was true in foo/d.spec")
end)
end,
path = {'d.spec', 'foo'},
pathStringForSorting = "foo d.spec",
},
})

local results = TestEZ.TestRunner.runPlan(plan)
assert(#results.errors == 0, "init test failed:\n" ..
table.concat(results.errors, "\n"))
end,
}
3 changes: 3 additions & 0 deletions tests/modules/a.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
local b = require(script.Parent.b)

return b(1) -- 2
3 changes: 3 additions & 0 deletions tests/modules/b.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
return function(x)
return x + 1
end
17 changes: 17 additions & 0 deletions tests/passing/requires.spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- luacheck: globals it expect

return function()
local a = require(script.Parent.Parent.modules.a)
local b = require(script.Parent.Parent.modules.b)

it("requires should work properly", function()
expect(a).to.equal(2)
expect(b(2)).to.equal(3)
end)

it("require cache works under normal circumstances", function()
local b2 = require(script.Parent.Parent.modules.b)

expect(b).to.equal(b2)
end)
end
4 changes: 4 additions & 0 deletions tests/planning/init.spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- This should be added to the "planning" node of the tree instead of creating
-- a new node.
return function()
end