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

Commit

Permalink
Merge pull request #119 from MagiMaster/context2
Browse files Browse the repository at this point in the history
Add Context object to lifecycle hooks and it blocks
  • Loading branch information
MagiMaster authored Jun 23, 2020
2 parents 7a4f7b8 + 602f1f6 commit cb2a713
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* `beforeAll` now runs on entering the block, rather than on the first `it` encountered after entering the block. The major difference for the moment is that a `beforeAll` will now run even if there are no `it` blocks under it, which is now consistent with how `afterAll` worked.
* `beforeAll` and `afterAll` now report errors by creating a dummy node in the results to contain the error. Previously, errors in `afterAll` were not reported.
* A failure in a `beforeAll` block will now halt all further test execution within its enclosing `describe` block except for any remaining `beforeAll` blocks and any `afterAll` blocks. Multiple `beforeAll` or `afterAll` blocks within one `describe` block should not count on running in any specific order. `afterAll` blocks should account for the possibility of a partially setup state when cleaning up.
* Add a context object visible from lifecycle hooks and `it` blocks. This is a write-once store for whatever you need to communicate between hooks and tests. It can be ignored until you need it.
* In particular, you can usually just use upvalues to comminucate between hooks and tests, but that won't work if your hooks are in a separate file (e.g. `init.spec.lua`).
* Also, this provides a cleaner alternative to extraEnvironment for passing along helper functions to large numbers of tests as the context can be scoped to particular directories as needed.

## 0.3.0 (2020-06-12)
* Remove the `try` node type.
Expand Down
13 changes: 10 additions & 3 deletions src/TestRunner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,16 @@ function TestRunner.runPlanNode(session, planNode, lifecycleHooks)
errorMessage = messagePrefix .. message .. "\n" .. debug.traceback()
end

local nodeSuccess, nodeResult = xpcall(callback, function(message)
return messagePrefix .. message .. "\n" .. debug.traceback()
end)
local context = session:getContext()

local nodeSuccess, nodeResult = xpcall(
function()
callback(context)
end,
function(message)
return messagePrefix .. message .. "\n" .. debug.traceback()
end
)

-- If a node threw an error, we prefer to use that message over
-- one created by fail() if it was set.
Expand Down
19 changes: 17 additions & 2 deletions src/TestSession.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

local TestEnum = require(script.Parent.TestEnum)
local TestResults = require(script.Parent.TestResults)
local Context = require(script.Parent.Context)

local TestSession = {}

Expand All @@ -23,6 +24,7 @@ function TestSession.new(plan)
local self = {
results = TestResults.new(plan),
nodeStack = {},
contextStack = {},
hasFocusNodes = false
}

Expand Down Expand Up @@ -95,11 +97,13 @@ end
]]
function TestSession:pushNode(planNode)
local node = TestResults.createNode(planNode)

local lastNode = self.nodeStack[#self.nodeStack] or self.results
local lastContext = self.contextStack[#self.contextStack]
local context = Context.new(lastContext)

table.insert(lastNode.children, node)
table.insert(self.nodeStack, node)
table.insert(self.contextStack, context)
end

--[[
Expand All @@ -108,6 +112,15 @@ end
function TestSession:popNode()
assert(#self.nodeStack > 0, "Tried to pop from an empty node stack!")
table.remove(self.nodeStack, #self.nodeStack)
table.remove(self.contextStack, #self.contextStack)
end

--[[
Gets the Context object for the current node.
]]
function TestSession:getContext()
assert(#self.contextStack > 0, "Tried to get context from an empty stack!")
return self.contextStack[#self.contextStack]
end

--[[
Expand Down Expand Up @@ -172,7 +185,9 @@ function TestSession:setError(message)
end

--[[
Add a dummy node below the current one to hold an error message.
Add a dummy child node to the current node to hold the given error. This
allows an otherwise empty describe node to report an error in a more natural
way.
]]
function TestSession:addDummyError(phrase, message)
self:pushNode({type = TestEnum.NodeType.It, phrase = phrase})
Expand Down
27 changes: 27 additions & 0 deletions tests/passing/context.spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-- luacheck: globals describe beforeAll beforeEach it expect afterEach afterAll

return function()
describe("context is passed between lifecycle hooks and it blocks", function()
beforeAll(function(context)
context.a = 1
end)

beforeEach(function(context)
context.b = 1
end)

it("before hooks should run", function(context)
expect(context.a).to.equal(1)
expect(context.b).to.equal(1)
end)

afterEach(function(context)
expect(context.b).to.equal(1)
end)

afterAll(function(context)
-- Failures in afterAll aren't reported.
expect(context.a).to.equal(1)
end)
end)
end
7 changes: 7 additions & 0 deletions tests/passing/describeAndContext.spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- luacheck: globals describe expect

return function()
describe("this shouldn't be able to access context", function(context)
expect(context).to.never.be.ok()
end)
end
25 changes: 25 additions & 0 deletions tests/passing/nestedContext.spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- luacheck: globals describe beforeAll it expect

return function()
describe("setting context here", function()
beforeAll(function(context)
context.a = 1
end)

describe("should apply here", function()
beforeAll(function(context)
context.b = context.a + 1
end)

it("should see a and b", function(context)
expect(context.a).to.equal(1)
expect(context.b).to.equal(2)
end)
end)

it("should not see b here", function(context)
expect(context.a).to.equal(1)
expect(context.b).to.never.be.ok()
end)
end)
end

0 comments on commit cb2a713

Please sign in to comment.