343 lines
6.9 KiB
Lua
343 lines
6.9 KiB
Lua
return function()
|
|
local Store = require(script.Parent.Store)
|
|
|
|
describe("new", function()
|
|
it("should instantiate with a reducer", function()
|
|
local store = Store.new(function(state, action)
|
|
return "hello, world"
|
|
end)
|
|
|
|
expect(store).to.be.ok()
|
|
expect(store:getState()).to.equal("hello, world")
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should instantiate with a reducer and an initial state", function()
|
|
local store = Store.new(function(state, action)
|
|
return state
|
|
end, "initial state")
|
|
|
|
expect(store).to.be.ok()
|
|
expect(store:getState()).to.equal("initial state")
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should instantiate with a reducer, initial state, and middlewares", function()
|
|
local store = Store.new(function(state, action)
|
|
return state
|
|
end, "initial state", {})
|
|
|
|
expect(store).to.be.ok()
|
|
expect(store:getState()).to.equal("initial state")
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
itFIXME("should modify the dispatch method when middlewares are passed", function()
|
|
local middlewareInstantiateCount = 0
|
|
local middlewareInvokeCount = 0
|
|
local passedDispatch
|
|
local passedStore
|
|
local passedAction
|
|
|
|
local function reducer(state, action)
|
|
if action.type == "test" then
|
|
return "test state"
|
|
end
|
|
|
|
return state
|
|
end
|
|
|
|
local function testMiddleware(nextDispatch, store)
|
|
middlewareInstantiateCount = middlewareInstantiateCount + 1
|
|
passedDispatch = nextDispatch
|
|
passedStore = store
|
|
|
|
return function(action)
|
|
middlewareInvokeCount = middlewareInvokeCount + 1
|
|
passedAction = action
|
|
|
|
nextDispatch(action)
|
|
end
|
|
end
|
|
|
|
local store = Store.new(reducer, "initial state", { testMiddleware })
|
|
|
|
expect(middlewareInstantiateCount).to.equal(1)
|
|
expect(middlewareInvokeCount).to.equal(0)
|
|
expect(passedDispatch).to.be.a("function")
|
|
expect(passedStore).to.equal(store)
|
|
|
|
store:dispatch({
|
|
type = "test",
|
|
})
|
|
|
|
expect(middlewareInstantiateCount).to.equal(1)
|
|
expect(middlewareInvokeCount).to.equal(1)
|
|
expect(passedAction.type).to.equal("test")
|
|
|
|
store:flush()
|
|
|
|
expect(store:getState()).to.equal("test state")
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
itFIXME("should execute middleware left-to-right", function()
|
|
local events = {}
|
|
|
|
local function reducer(state)
|
|
return state
|
|
end
|
|
|
|
local function middlewareA(nextDispatch, store)
|
|
table.insert(events, "instantiate a")
|
|
return function(action)
|
|
table.insert(events, "execute a")
|
|
return nextDispatch(action)
|
|
end
|
|
end
|
|
|
|
local function middlewareB(nextDispatch, store)
|
|
table.insert(events, "instantiate b")
|
|
return function(action)
|
|
table.insert(events, "execute b")
|
|
return nextDispatch(action)
|
|
end
|
|
end
|
|
|
|
local store = Store.new(reducer, 5, { middlewareA, middlewareB })
|
|
|
|
expect(#events).to.equal(2)
|
|
expect(events[1]).to.equal("instantiate b")
|
|
expect(events[2]).to.equal("instantiate a")
|
|
|
|
store:dispatch({
|
|
type = "test",
|
|
})
|
|
|
|
expect(#events).to.equal(4)
|
|
expect(events[3]).to.equal("execute a")
|
|
expect(events[4]).to.equal("execute b")
|
|
end)
|
|
|
|
it("should send an initial action with a 'type' field", function()
|
|
local lastAction
|
|
local callCount = 0
|
|
|
|
local store = Store.new(function(state, action)
|
|
lastAction = action
|
|
callCount = callCount + 1
|
|
|
|
return state
|
|
end)
|
|
|
|
expect(callCount).to.equal(1)
|
|
expect(lastAction).to.be.a("table")
|
|
expect(lastAction.type).to.be.ok()
|
|
|
|
store:destruct()
|
|
end)
|
|
end)
|
|
|
|
describe("getState", function()
|
|
it("should get the current state", function()
|
|
local store = Store.new(function(state, action)
|
|
return "foo"
|
|
end)
|
|
|
|
local state = store:getState()
|
|
|
|
expect(state).to.equal("foo")
|
|
|
|
store:destruct()
|
|
end)
|
|
end)
|
|
|
|
describe("dispatch", function()
|
|
it("should be sent through the reducer", function()
|
|
local store = Store.new(function(state, action)
|
|
state = state or "foo"
|
|
|
|
if action.type == "act" then
|
|
return "bar"
|
|
end
|
|
|
|
return state
|
|
end)
|
|
|
|
expect(store).to.be.ok()
|
|
expect(store:getState()).to.equal("foo")
|
|
|
|
store:dispatch({
|
|
type = "act",
|
|
})
|
|
|
|
store:flush()
|
|
|
|
expect(store:getState()).to.equal("bar")
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should trigger the changed event after a flush", function()
|
|
local store = Store.new(function(state, action)
|
|
state = state or 0
|
|
|
|
if action.type == "increment" then
|
|
return state + 1
|
|
end
|
|
|
|
return state
|
|
end)
|
|
|
|
local callCount = 0
|
|
|
|
store.changed:connect(function(state, oldState)
|
|
expect(oldState).to.equal(0)
|
|
expect(state).to.equal(1)
|
|
|
|
callCount = callCount + 1
|
|
end)
|
|
|
|
store:dispatch({
|
|
type = "increment",
|
|
})
|
|
|
|
store:flush()
|
|
|
|
expect(callCount).to.equal(1)
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should handle actions dispatched within the changed event", function()
|
|
local store = Store.new(function(state, action)
|
|
state = state or {
|
|
value = 0,
|
|
}
|
|
|
|
if action.type == "increment" then
|
|
return {
|
|
value = state.value + 1,
|
|
}
|
|
elseif action.type == "decrement" then
|
|
return {
|
|
value = state.value - 1,
|
|
}
|
|
end
|
|
|
|
return state
|
|
end)
|
|
|
|
local changeCount = 0
|
|
|
|
store.changed:connect(function(state, oldState)
|
|
expect(state).never.to.equal(oldState)
|
|
|
|
if state.value > 0 then
|
|
store:dispatch({
|
|
type = "decrement",
|
|
})
|
|
end
|
|
|
|
changeCount = changeCount + 1
|
|
end)
|
|
|
|
store:dispatch({
|
|
type = "increment",
|
|
})
|
|
store:flush()
|
|
store:flush()
|
|
|
|
expect(changeCount).to.equal(2)
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should prevent yielding from changed handler", function()
|
|
local preCount = 0
|
|
local postCount = 0
|
|
|
|
local store = Store.new(function(state, action)
|
|
state = state or 0
|
|
return state + 1
|
|
end)
|
|
|
|
store.changed:connect(function(state, oldState)
|
|
preCount = preCount + 1
|
|
wait()
|
|
postCount = postCount + 1
|
|
end)
|
|
|
|
store:dispatch({
|
|
type = "increment",
|
|
})
|
|
|
|
expect(function()
|
|
store:flush()
|
|
end).to.throw()
|
|
|
|
expect(preCount).to.equal(1)
|
|
expect(postCount).to.equal(0)
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should throw if an action is dispatched without a type field", function()
|
|
local store = Store.new(function(state, action)
|
|
return state
|
|
end)
|
|
|
|
expect(function()
|
|
store:dispatch({})
|
|
end).to.throw()
|
|
|
|
store:destruct()
|
|
end)
|
|
|
|
it("should throw if the action is not a function or table", function()
|
|
local store = Store.new(function(state, action)
|
|
return state
|
|
end)
|
|
|
|
expect(function()
|
|
store:dispatch(1)
|
|
end).to.throw()
|
|
|
|
store:destruct()
|
|
end)
|
|
end)
|
|
|
|
describe("flush", function()
|
|
it("should not fire a changed event if there were no dispatches", function()
|
|
local store = Store.new(function()
|
|
end)
|
|
|
|
local count = 0
|
|
store.changed:connect(function()
|
|
count = count + 1
|
|
end)
|
|
|
|
store:flush()
|
|
|
|
expect(count).to.equal(0)
|
|
|
|
store:dispatch({
|
|
type = "increment",
|
|
})
|
|
store:flush()
|
|
|
|
expect(count).to.equal(1)
|
|
|
|
store:flush()
|
|
|
|
expect(count).to.equal(1)
|
|
|
|
store:destruct()
|
|
end)
|
|
end)
|
|
end
|