return function()local Y=require(script.Parent.Parent.createElement)local i=require(script.Parent.Parent.createReconciler)local h=require(script.Parent.Parent.createSpy)local x=require(script.Parent.Parent.NoopRenderer)local C=require(script.Parent.Parent.GlobalConfig)local P=require(script.Parent.Parent.Component)local R=i(x)it("\115\104\111\117\108\100 \098\101 \105\110\118\111\107\101\100 \119\104\101\110 \109\111\117\110\116\101\100",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")local x=h(function()return true end)i.validateProps=x.value function i.render(Y)return nil end local C=Y(i)local K=nil local A="\084\101\115\116"R.mountVirtualNode(C,K,A);(expect(x.callCount)).to.equal(1)end)end)it("\115\104\111\117\108\100 \098\101 \105\110\118\111\107\101\100 \119\104\101\110 \112\114\111\112\115 \099\104\097\110\103\101",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")local x=h(function()return true end)i.validateProps=x.value function i.render(Y)return nil end local C=Y(i,{a=1})local K=nil local A="\084\101\115\116"local q=R.mountVirtualNode(C,K,A);(expect(x.callCount)).to.equal(1)x:assertCalledWithDeepEqual({a=1})local k=Y(i,{a=2})R.updateVirtualNode(q,k);(expect(x.callCount)).to.equal(2)x:assertCalledWithDeepEqual({a=2})end)end)it("\115\104\111\117\108\100 \110\111\116 \098\101 \105\110\118\111\107\101\100 \119\104\101\110 \115\116\097\116\101 \099\104\097\110\103\101\115",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")local x=nil local C=h(function()return true end)i.validateProps=C.value function i.init(Y)x=function(i)Y:setState(i)end end function i.render(Y)return nil end local K=Y(i,{a=1})local A=nil local q="\084\101\115\116"R.mountVirtualNode(K,A,q);(expect(C.callCount)).to.equal(1)C:assertCalledWithDeepEqual({a=1})x({b=1});(expect(C.callCount)).to.equal(1)end)end)it("\115\104\111\117\108\100 \116\104\114\111\119 \105\102 \118\097\108\105\100\097\116\101\080\114\111\112\115 \105\115 \110\111\116 \097 \102\117\110\099\116\105\111\110",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")i.validateProps=1 function i.render(Y)return nil end local h=Y(i)local x=nil local C="\084\101\115\116";(expect(function()R.mountVirtualNode(h,x,C)end)).to.throw()end)end)it("\115\104\111\117\108\100 \116\104\114\111\119 \105\102 \118\097\108\105\100\097\116\101\080\114\111\112\115 \114\101\116\117\114\110\115 \102\097\108\115\101",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")i.validateProps=function()return false end function i.render(Y)return nil end local h=Y(i)local x=nil local C="\084\101\115\116";(expect(function()R.mountVirtualNode(h,x,C)end)).to.throw()end)end)it("\115\104\111\117\108\100 \105\110\099\108\117\100\101 \116\104\101 \099\111\109\112\111\110\101\110\116 \110\097\109\101 \105\110 \116\104\101 \101\114\114\111\114 \109\101\115\115\097\103\101",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")i.validateProps=function()return false end function i.render(Y)return nil end local h=Y(i)local x=nil local C="\084\101\115\116"local K,A=pcall(function()R.mountVirtualNode(h,x,C)end);(expect(K)).to.equal(false)local q=A:find("\077\121\067\111\109\112\111\110\101\110\116");(expect(q)).to.be.ok()end)end)it("\115\104\111\117\108\100 \098\101 \105\110\118\111\107\101\100 \097\102\116\101\114 \100\101\102\097\117\108\116\080\114\111\112\115 \097\114\101 \097\112\112\108\105\101\100",function()local i={propValidation=true}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")local x=h(function()return true end)i.validateProps=x.value function i.render(Y)return nil end i.defaultProps={b=2}local C=Y(i,{a=1})local K=nil local A="\084\101\115\116"local q=R.mountVirtualNode(C,K,A);(expect(x.callCount)).to.equal(1)x:assertCalledWithDeepEqual({a=1,b=2})local k=Y(i,{a=2})R.updateVirtualNode(q,k);(expect(x.callCount)).to.equal(2)x:assertCalledWithDeepEqual({a=2,b=2})end)end)it("\115\104\111\117\108\100 \110\111\116 \098\101 \105\110\118\111\107\101\100 \105\102 \116\104\101 \102\108\097\103 \105\115 \111\102\102",function()local i={propValidation=false}C.scoped(i,function()local i=P:extend("\077\121\067\111\109\112\111\110\101\110\116")local x=h(function()return true end)i.validateProps=x.value function i.render(Y)return nil end local C=Y(i,{a=1})local K=nil local A="\084\101\115\116"local q=R.mountVirtualNode(C,K,A);(expect(x.callCount)).to.equal(0)local k=Y(i,{a=2})R.updateVirtualNode(q,k);(expect(x.callCount)).to.equal(0)end)end)end
return function()
	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 GlobalConfig = require(script.Parent.Parent.GlobalConfig)

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

	local noopReconciler = createReconciler(NoopRenderer)

	it("should be invoked when mounted", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")

			local validatePropsSpy = createSpy(function()
				return true
			end)

			MyComponent.validateProps = validatePropsSpy.value

			function MyComponent:render()
				return nil
			end

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

			noopReconciler.mountVirtualNode(element, hostParent, key)
			expect(validatePropsSpy.callCount).to.equal(1)
		end)
	end)

	it("should be invoked when props change", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")

			local validatePropsSpy = createSpy(function()
				return true
			end)

			MyComponent.validateProps = validatePropsSpy.value

			function MyComponent:render()
				return nil
			end

			local element = createElement(MyComponent, { a = 1 })
			local hostParent = nil
			local key = "Test"

			local node = noopReconciler.mountVirtualNode(element, hostParent, key)
			expect(validatePropsSpy.callCount).to.equal(1)
			validatePropsSpy:assertCalledWithDeepEqual({
				a = 1,
			})

			local newElement = createElement(MyComponent, { a = 2 })
			noopReconciler.updateVirtualNode(node, newElement)
			expect(validatePropsSpy.callCount).to.equal(2)
			validatePropsSpy:assertCalledWithDeepEqual({
				a = 2,
			})
		end)
	end)

	it("should not be invoked when state changes", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")

			local setStateCallback = nil
			local validatePropsSpy = createSpy(function()
				return true
			end)

			MyComponent.validateProps = validatePropsSpy.value

			function MyComponent:init()
				setStateCallback = function(newState)
					self:setState(newState)
				end
			end

			function MyComponent:render()
				return nil
			end

			local element = createElement(MyComponent, { a = 1 })
			local hostParent = nil
			local key = "Test"

			noopReconciler.mountVirtualNode(element, hostParent, key)
			expect(validatePropsSpy.callCount).to.equal(1)
			validatePropsSpy:assertCalledWithDeepEqual({
				a = 1,
			})

			setStateCallback({
				b = 1,
			})

			expect(validatePropsSpy.callCount).to.equal(1)
		end)
	end)

	it("should throw if validateProps is not a function", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")
			MyComponent.validateProps = 1

			function MyComponent:render()
				return nil
			end

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

			expect(function()
				noopReconciler.mountVirtualNode(element, hostParent, key)
			end).to.throw()
		end)
	end)

	it("should throw if validateProps returns false", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")
			MyComponent.validateProps = function()
				return false
			end

			function MyComponent:render()
				return nil
			end

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

			expect(function()
				noopReconciler.mountVirtualNode(element, hostParent, key)
			end).to.throw()
		end)
	end)

	it("should include the component name in the error message", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")
			MyComponent.validateProps = function()
				return false
			end

			function MyComponent:render()
				return nil
			end

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

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

			expect(success).to.equal(false)
			local startIndex = error:find("MyComponent")
			expect(startIndex).to.be.ok()
		end)
	end)

	it("should be invoked after defaultProps are applied", function()
		local config = {
			propValidation = true,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")

			local validatePropsSpy = createSpy(function()
				return true
			end)

			MyComponent.validateProps = validatePropsSpy.value

			function MyComponent:render()
				return nil
			end

			MyComponent.defaultProps = {
				b = 2,
			}

			local element = createElement(MyComponent, { a = 1 })
			local hostParent = nil
			local key = "Test"

			local node = noopReconciler.mountVirtualNode(element, hostParent, key)
			expect(validatePropsSpy.callCount).to.equal(1)
			validatePropsSpy:assertCalledWithDeepEqual({
				a = 1,
				b = 2,
			})

			local newElement = createElement(MyComponent, { a = 2 })
			noopReconciler.updateVirtualNode(node, newElement)
			expect(validatePropsSpy.callCount).to.equal(2)
			validatePropsSpy:assertCalledWithDeepEqual({
				a = 2,
				b = 2,
			})
		end)
	end)

	it("should not be invoked if the flag is off", function()
		local config = {
			propValidation = false,
		}

		GlobalConfig.scoped(config, function()
			local MyComponent = Component:extend("MyComponent")

			local validatePropsSpy = createSpy(function()
				return true
			end)

			MyComponent.validateProps = validatePropsSpy.value

			function MyComponent:render()
				return nil
			end

			local element = createElement(MyComponent, { a = 1 })
			local hostParent = nil
			local key = "Test"

			local node = noopReconciler.mountVirtualNode(element, hostParent, key)
			expect(validatePropsSpy.callCount).to.equal(0)

			local newElement = createElement(MyComponent, { a = 2 })
			noopReconciler.updateVirtualNode(node, newElement)
			expect(validatePropsSpy.callCount).to.equal(0)
		end)
	end)
end
