return function()local Y=require(script.Parent.Parent.assertDeepEqual)local i=require(script.Parent.Parent.createElement)local h=require(script.Parent.Parent.createReconciler)local x=require(script.Parent.Parent.createSpy)local C=require(script.Parent.Parent.NoopRenderer)local P=require(script.Parent.Parent.Type)local R=require(script.Parent.Parent.Component)local K=h(C)it("\115\104\111\117\108\100 \116\104\114\111\119 \111\110 \109\111\117\110\116 \105\102 \110\111\116 \111\118\101\114\114\105\100\100\101\110",function()local Y=R:extend("\077\121\067\111\109\112\111\110\101\110\116")local h=i(Y)local x=nil local C="\084\101\115\116"local P,A=pcall(function()K.mountVirtualNode(h,x,C)end);(expect(P)).to.equal(false);(expect(A:match("\077\121\067\111\109\112\111\110\101\110\116"))).to.be.ok();(expect(A:match("\114\101\110\100\101\114"))).to.be.ok()end)it("\115\104\111\117\108\100 \098\101 \105\110\118\111\107\101\100 \119\104\101\110 \097 \099\111\109\112\111\110\101\110\116 \105\115 \109\111\117\110\116\101\100",function()local h=R:extend("\070\111\111")local C local A local q=x(function(Y)C=Y.props A=Y.state end)h.render=q.value local k=i(h)local H=nil local D="\070\111\111 \084\101\115\116"K.mountVirtualNode(k,H,D);(expect(q.callCount)).to.equal(1)local N=q:captureValues("\115\101\108\102");(expect(P.of(N.self))).to.equal(P.StatefulComponentInstance)Y(C,{})Y(A,{})end)it("\115\104\111\117\108\100 \098\101 \105\110\118\111\107\101\100 \119\104\101\110 \097 \099\111\109\112\111\110\101\110\116 \105\115 \117\112\100\097\116\101\100 \118\105\097 \112\114\111\112\115",function()local h=R:extend("\070\111\111")local C local A local q=x(function(Y)C=Y.props A=Y.state end)h.render=q.value local k={a=2}local H=i(h,k)local D=nil local N="\070\111\111 \084\101\115\116"local Z=K.mountVirtualNode(H,D,N);(expect(q.callCount)).to.equal(1)local J=q:captureValues("\115\101\108\102")local V=C local X=A;(expect(P.of(J.self))).to.equal(P.StatefulComponentInstance)Y(V,k)Y(X,{})local p={a=3}local F=i(h,p)K.updateVirtualNode(Z,F);(expect(q.callCount)).to.equal(2)local M=q:captureValues("\115\101\108\102")local U=C local s=A;(expect(P.of(M.self))).to.equal(P.StatefulComponentInstance);(expect(U)).never.to.equal(V)Y(U,p);(expect(s)).to.equal(X)end)it("\115\104\111\117\108\100 \098\101 \105\110\118\111\107\101\100 \119\104\101\110 \097 \099\111\109\112\111\110\101\110\116 \105\115 \117\112\100\097\116\101\100 \118\105\097 \115\116\097\116\101",function()local Y=R:extend("\070\111\111")local h function Y.init(Y)h=function(...)return Y:setState(...)end end local C local A local q=x(function(Y)C=Y.props A=Y.state end)Y.render=q.value local k=i(Y)local H=nil local D="\070\111\111 \084\101\115\116"K.mountVirtualNode(k,H,D);(expect(q.callCount)).to.equal(1)local N=q:captureValues("\115\101\108\102")local Z=C local J=A;(expect(P.of(N.self))).to.equal(P.StatefulComponentInstance)h({});(expect(q.callCount)).to.equal(2)local V=q:captureValues("\115\101\108\102");(expect(P.of(V.self))).to.equal(P.StatefulComponentInstance);(expect(C)).to.equal(Z);(expect(A)).never.to.equal(J)end)itSKIP("\084\101\115\116 \100\101\102\097\117\108\116\080\114\111\112\115 \111\110 \105\110\105\116\105\097\108 \114\101\110\100\101\114",function() end)itSKIP("\084\101\115\116 \100\101\102\097\117\108\116\080\114\111\112\115 \111\110 \112\114\111\112 \117\112\100\097\116\101",function() end)itSKIP("\084\101\115\116 \100\101\102\097\117\108\116\080\114\111\112\115 \111\110 \115\116\097\116\101 \117\112\100\097\116\101",function() end)end
return function()
	local assertDeepEqual = require(script.Parent.Parent.assertDeepEqual)
	local createElement = require(script.Parent.Parent.createElement)
	local createReconciler = require(script.Parent.Parent.createReconciler)
	local createSpy = require(script.Parent.Parent.createSpy)
	local NoopRenderer = require(script.Parent.Parent.NoopRenderer)
	local Type = require(script.Parent.Parent.Type)

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

	local noopReconciler = createReconciler(NoopRenderer)

	it("should throw on mount if not overridden", function()
		local MyComponent = Component:extend("MyComponent")

		local element = createElement(MyComponent)
		local hostParent = nil
		local key = "Test"

		local success, result = pcall(function()
			noopReconciler.mountVirtualNode(element, hostParent, key)
		end)

		expect(success).to.equal(false)
		expect(result:match("MyComponent")).to.be.ok()
		expect(result:match("render")).to.be.ok()
	end)

	it("should be invoked when a component is mounted", function()
		local Foo = Component:extend("Foo")

		local capturedProps
		local capturedState
		local renderSpy = createSpy(function(self)
			capturedProps = self.props
			capturedState = self.state
		end)
		Foo.render = renderSpy.value

		local element = createElement(Foo)
		local hostParent = nil
		local key = "Foo Test"

		noopReconciler.mountVirtualNode(element, hostParent, key)

		expect(renderSpy.callCount).to.equal(1)

		local renderArguments = renderSpy:captureValues("self")

		expect(Type.of(renderArguments.self)).to.equal(Type.StatefulComponentInstance)
		assertDeepEqual(capturedProps, {})
		assertDeepEqual(capturedState, {})
	end)

	it("should be invoked when a component is updated via props", function()
		local Foo = Component:extend("Foo")

		local capturedProps
		local capturedState
		local renderSpy = createSpy(function(self)
			capturedProps = self.props
			capturedState = self.state
		end)
		Foo.render = renderSpy.value

		local initialProps = {
			a = 2,
		}
		local element = createElement(Foo, initialProps)
		local hostParent = nil
		local key = "Foo Test"

		local node = noopReconciler.mountVirtualNode(element, hostParent, key)

		expect(renderSpy.callCount).to.equal(1)

		local firstRenderArguments = renderSpy:captureValues("self")
		local firstProps = capturedProps
		local firstState = capturedState

		expect(Type.of(firstRenderArguments.self)).to.equal(Type.StatefulComponentInstance)
		assertDeepEqual(firstProps, initialProps)
		assertDeepEqual(firstState, {})

		local updatedProps = {
			a = 3,
		}
		local newElement = createElement(Foo, updatedProps)

		noopReconciler.updateVirtualNode(node, newElement)

		expect(renderSpy.callCount).to.equal(2)

		local secondRenderArguments = renderSpy:captureValues("self")
		local secondProps = capturedProps
		local secondState = capturedState

		expect(Type.of(secondRenderArguments.self)).to.equal(Type.StatefulComponentInstance)
		expect(secondProps).never.to.equal(firstProps)
		assertDeepEqual(secondProps, updatedProps)
		expect(secondState).to.equal(firstState)
	end)

	it("should be invoked when a component is updated via state", function()
		local Foo = Component:extend("Foo")

		local setState
		function Foo:init()
			setState = function(...)
				return self:setState(...)
			end
		end

		local capturedProps
		local capturedState
		local renderSpy = createSpy(function(self)
			capturedProps = self.props
			capturedState = self.state
		end)
		Foo.render = renderSpy.value

		local element = createElement(Foo)
		local hostParent = nil
		local key = "Foo Test"

		noopReconciler.mountVirtualNode(element, hostParent, key)

		expect(renderSpy.callCount).to.equal(1)

		local firstRenderArguments = renderSpy:captureValues("self")
		local firstProps = capturedProps
		local firstState = capturedState

		expect(Type.of(firstRenderArguments.self)).to.equal(Type.StatefulComponentInstance)

		setState({})

		expect(renderSpy.callCount).to.equal(2)

		local renderArguments = renderSpy:captureValues("self")

		expect(Type.of(renderArguments.self)).to.equal(Type.StatefulComponentInstance)
		expect(capturedProps).to.equal(firstProps)
		expect(capturedState).never.to.equal(firstState)
	end)

	itSKIP("Test defaultProps on initial render", function() end)
	itSKIP("Test defaultProps on prop update", function() end)
	itSKIP("Test defaultProps on state update", function() end)
end
