local q=script.Parent.Parent.Parent local O=require(q.Dev.JestGlobals)local S=O.jest local Y=O.it local u=O.expect local z=require(script.Parent.Parent.createSignal)Y("\115\104\111\117\108\100 \102\105\114\101 \115\117\098\115\099\114\105\098\101\114\115 \097\110\100 \100\105\115\099\111\110\110\101\099\116 \116\104\101\109",function()local q,O=z()local Y,g=S.fn()local j=q:subscribe(g);(u(Y)).never.toBeCalled()O(1)O({foo="\098\097\114"})O("\104\101\108\108\111");(u(Y)).toHaveBeenCalledTimes(3);(u(Y)).toHaveBeenNthCalledWith(1,1);(u(Y)).toHaveBeenNthCalledWith(2,{foo="\098\097\114"});(u(Y)).toHaveBeenNthCalledWith(3,"\104\101\108\108\111")j:unsubscribe()O(99);(u(Y)).toHaveBeenCalledTimes(3)end)Y("\115\104\111\117\108\100 \104\097\110\100\108\101 \109\117\108\116\105\112\108\101 \115\117\098\115\099\114\105\098\101\114\115",function()local q,O=z()local Y,g=S.fn()local j,e=S.fn()local Q=q:subscribe(g)local A=q:subscribe(e);(u(Y)).never.toHaveBeenCalled();(u(j)).never.toHaveBeenCalled()O({})O(67);(u(Y)).toHaveBeenCalledTimes(2);(u(Y)).toHaveBeenNthCalledWith(1,{});(u(Y)).toHaveBeenNthCalledWith(2,67);(u(j)).toHaveBeenCalledTimes(2);(u(j)).toHaveBeenNthCalledWith(1,{});(u(j)).toHaveBeenNthCalledWith(2,67)Q:unsubscribe()O(67)O({});(u(Y)).toBeCalledTimes(2);(u(j)).toBeCalledTimes(4);(u(j)).toHaveBeenNthCalledWith(3,67);(u(j)).toHaveBeenNthCalledWith(4,{})A:unsubscribe()end)Y("\115\104\111\117\108\100 \115\116\111\112 \102\105\114\105\110\103 \097 \099\111\110\110\101\099\116\105\111\110 \105\102 \100\105\115\099\111\110\110\101\099\116\101\100 \109\105\100-\102\105\114\101",function()local q,O=z()local Y local g local j,e=S.fn(function()g:unsubscribe()end)local Q,A=S.fn(function()Y:unsubscribe()end)Y=q:subscribe(e)g=q:subscribe(A)O("\102\111\111");(u(#j.mock.calls+#Q.mock.calls)).toBe(1)end)Y("\097\108\108\111\119\115 \110\101\119 \115\117\098\115\099\114\105\112\116\105\111\110\115 \100\117\114\105\110\103 \102\105\114\105\110\103\044 \111\110\108\121 \117\112\100\097\116\101\115 \116\104\101\109 \111\110 \115\117\098\115\101\113\117\101\110\116 \102\105\114\101\115",function()local q,O=z()local Y local g,j=S.fn()local e,Q=S.fn()local A=q:subscribe(function(O)Q(O)if not Y then Y=q:subscribe(j)end end)O(1);(u(e)).toHaveBeenCalledTimes(1);(u(g)).toHaveBeenCalledTimes(0)O(2);(u(e)).toHaveBeenCalledTimes(2);(u(g)).toHaveBeenCalledTimes(1)A:unsubscribe()O(3);(u(e)).toHaveBeenCalledTimes(2);(u(g)).toHaveBeenCalledTimes(2);(u(e)).toHaveBeenLastCalledWith(2);(u(g)).toHaveBeenLastCalledWith(3)Y:unsubscribe()O(4);(u(e)).toHaveBeenCalledTimes(2);(u(g)).toHaveBeenCalledTimes(2)end)
--!strict
local Packages = script.Parent.Parent.Parent
local JestGlobals = require(Packages.Dev.JestGlobals)
local jest = JestGlobals.jest
local it = JestGlobals.it
local expect = JestGlobals.expect

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

it("should fire subscribers and disconnect them", function()
	local signal, fire = createSignal()

	local spy, spyFn = jest.fn()
	local subscription = signal:subscribe(spyFn)

	expect(spy).never.toBeCalled()

	fire(1)
	fire({ foo = "bar" })
	fire("hello")

	expect(spy).toHaveBeenCalledTimes(3)
	expect(spy).toHaveBeenNthCalledWith(1, 1)
	expect(spy).toHaveBeenNthCalledWith(2, { foo = "bar" })
	expect(spy).toHaveBeenNthCalledWith(3, "hello")

	subscription:unsubscribe()

	fire(99)

	expect(spy).toHaveBeenCalledTimes(3)
end)

it("should handle multiple subscribers", function()
	local signal, fire = createSignal()

	local spyA, spyAFn = jest.fn()
	local spyB, spyBFn = jest.fn()

	local subscriptionA = signal:subscribe(spyAFn)
	local subscriptionB = signal:subscribe(spyBFn)

	expect(spyA).never.toHaveBeenCalled()
	expect(spyB).never.toHaveBeenCalled()

	fire({})
	fire(67)

	expect(spyA).toHaveBeenCalledTimes(2)
	expect(spyA).toHaveBeenNthCalledWith(1, {})
	expect(spyA).toHaveBeenNthCalledWith(2, 67)

	expect(spyB).toHaveBeenCalledTimes(2)
	expect(spyB).toHaveBeenNthCalledWith(1, {})
	expect(spyB).toHaveBeenNthCalledWith(2, 67)

	subscriptionA:unsubscribe()

	fire(67)
	fire({})

	expect(spyA).toBeCalledTimes(2)

	expect(spyB).toBeCalledTimes(4)
	expect(spyB).toHaveBeenNthCalledWith(3, 67)
	expect(spyB).toHaveBeenNthCalledWith(4, {})

	subscriptionB:unsubscribe()
end)

it("should stop firing a connection if disconnected mid-fire", function()
	local signal, fire = createSignal()

	-- In this test, we'll connect two listeners that each try to disconnect
	-- the other. Because the order of listeners firing isn't defined, we
	-- have to be careful to handle either case.

	local subscriptionA
	local subscriptionB

	local spyA, spyAFn = jest.fn(function()
		subscriptionB:unsubscribe()
	end)

	local spyB, spyBFn = jest.fn(function()
		subscriptionA:unsubscribe()
	end)

	subscriptionA = signal:subscribe(spyAFn)
	subscriptionB = signal:subscribe(spyBFn)

	fire("foo")

	expect(#spyA.mock.calls + #spyB.mock.calls).toBe(1)
end)

it("allows new subscriptions during firing, only updates them on subsequent fires", function()
	local signal, fire = createSignal()
	local innerSubscription
	local innerSub, innerSubFn = jest.fn()
	local outerSub, outerSubFn = jest.fn()
	local outerSubscription = signal:subscribe(function(value)
		outerSubFn(value)
		if not innerSubscription then
			innerSubscription = signal:subscribe(innerSubFn)
		end
	end)

	fire(1)
	expect(outerSub).toHaveBeenCalledTimes(1)
	expect(innerSub).toHaveBeenCalledTimes(0)

	fire(2)
	expect(outerSub).toHaveBeenCalledTimes(2)
	expect(innerSub).toHaveBeenCalledTimes(1)

	outerSubscription:unsubscribe()
	fire(3)
	expect(outerSub).toHaveBeenCalledTimes(2)
	expect(innerSub).toHaveBeenCalledTimes(2)

	expect(outerSub).toHaveBeenLastCalledWith(2)
	expect(innerSub).toHaveBeenLastCalledWith(3)

	innerSubscription:unsubscribe()
	fire(4)

	expect(outerSub).toHaveBeenCalledTimes(2)
	expect(innerSub).toHaveBeenCalledTimes(2)
end)
