local c local H local e local n=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\106\101\115\116-\103\108\111\098\097\108\115")local v=n.afterEach local Q=n.beforeEach local R=n.expect local b=n.describe local f=n.it local U=n.jest local j=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\108\117\097\117-\112\111\108\121\102\105\108\108")local V=j.Error b("\116\101\115\116\115 \112\114\111\112\084\121\112\101\115 \097\110\100 \118\097\108\105\100\097\116\101\080\114\111\112\115 \098\101\104\097\118\105\111\114",function()Q(function()U.resetModules()H=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\114\101\097\099\116-\110\111\111\112-\114\101\110\100\101\114\101\114")e=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\115\099\104\101\100\117\108\101\114")c=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\114\101\097\099\116")end)f("\112\114\111\112\084\121\112\101\115 \100\101\102\105\110\101\100\044 \114\101\116\117\114\110\115 \101\114\114\111\114",function()local n=c.Component:extend("\100\105\118")n.propTypes={myProp=function(c,H,e)return V("\110\111 \110\111 \110\111 \110\111 \110\111")end}function n.render(H)return c.createElement("\100\105\118")end;(R(function()H.act(function()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)end)).toWarnDev("\110\111 \110\111 \110\111 \110\111 \110\111")end)f("\112\114\111\112\084\121\112\101\115 \100\101\102\105\110\101\100\044 \114\101\116\117\114\110\115 \110\105\108",function()local n=c.Component:extend("\070\111\111")n.propTypes={myProp=function(c,H,e)return nil end}function n.render(H)return c.createElement("\100\105\118")end H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)f("\118\097\108\105\100\097\116\101\080\114\111\112\115 \100\101\102\105\110\101\100\044 \114\101\116\117\114\110\115 \102\097\108\115\101",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return false,"\110\111 \110\111 \110\111 \110\111 \110\111"end function n.render(H)return c.createElement("\100\105\118")end local function v()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end if _G.__DEV__ then(R(v)).toThrow("\110\111 \110\111 \110\111 \110\111 \110\111")else(R(v)).never.toThrow()end end)f("\118\097\108\105\100\097\116\101\080\114\111\112\115 \100\101\102\105\110\101\100\044 \114\101\116\117\114\110\115 \116\114\117\101",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return true end function n.render(H)return c.createElement("\100\105\118")end H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)f("\119\097\114\110\105\110\103 \119\104\101\110 \098\111\116\104 \109\101\116\104\111\100\115 \097\114\101 \100\101\102\105\110\101\100",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return true end n.propTypes={myProp=function(c,H,e)return nil end}function n.render(H)return c.createElement("\100\105\118")end;(R(function()H.act(function()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)end)).toWarnDev("\089\111\117\'\118\101 \100\101\102\105\110\101\100 \098\111\116\104 \112\114\111\112\084\121\112\101\115 \097\110\100 \118\097\108\105\100\097\116\101\080\114\111\112\115 \111\110 \070\111\111",{withoutStack=true})end)f("\118\097\108\105\100\097\116\101\080\114\111\112\115 \102\097\105\108\115\044 \112\114\111\112\084\121\112\101\115 \102\097\105\108\115",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return false,"\110\111 \110\111 \110\111 \110\111 \110\111"end n.propTypes={myProp=function(c,H,e)error(V("\110\111 \110\111 \110\111 \110\111 \110\111"))end}function n.render(H)return c.createElement("\100\105\118")end local function v()(R(function()H.act(function()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)end)).toWarnDev("\089\111\117\'\118\101 \100\101\102\105\110\101\100 \098\111\116\104 \112\114\111\112\084\121\112\101\115 \097\110\100 \118\097\108\105\100\097\116\101\080\114\111\112\115 \111\110 \070\111\111",{withoutStack=2})end if _G.__DEV__ then(R(v)).toThrow("\110\111 \110\111 \110\111 \110\111 \110\111")else(R(v)).never.toThrow()end end)f("\118\097\108\105\100\097\116\101\080\114\111\112\115 \115\117\099\099\101\101\100\115\044 \112\114\111\112\084\121\112\101\115 \102\097\105\108\115",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return true end n.propTypes={myProp=function(c,H,e)error(V("\110\111 \110\111 \110\111 \110\111 \110\111"))end}function n.render(H)return c.createElement("\100\105\118")end;(R(function()H.act(function()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)end)).toWarnDev({"\089\111\117\'\118\101 \100\101\102\105\110\101\100 \098\111\116\104 \112\114\111\112\084\121\112\101\115 \097\110\100 \118\097\108\105\100\097\116\101\080\114\111\112\115 \111\110 \070\111\111","\110\111 \110\111 \110\111 \110\111 \110\111"},{withoutStack=1})end)f("\118\097\108\105\100\097\116\101\080\114\111\112\115 \102\097\105\108\115\044 \112\114\111\112\084\121\112\101\115 \115\117\099\099\101\101\100\115",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return false,"\110\111 \110\111 \110\111 \110\111 \110\111"end n.propTypes={myProp=function(c,H,e)return nil end}function n.render(H)return c.createElement("\100\105\118")end local function v()(R(function()H.act(function()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)end)).toWarnDev("\089\111\117\'\118\101 \100\101\102\105\110\101\100 \098\111\116\104 \112\114\111\112\084\121\112\101\115 \097\110\100 \118\097\108\105\100\097\116\101\080\114\111\112\115 \111\110 \070\111\111",{withoutStack=2})end if _G.__DEV__ then(R(v)).toThrow("\110\111 \110\111 \110\111 \110\111 \110\111")else(R(v)).never.toThrow()end end)f("\098\097\100 \112\114\111\112\084\121\112\101\115 \109\101\116\104\111\100",function()local n=c.Component:extend("\070\111\111")n.propTypes={myProp=function(c,H,e)return"\110\105\108"end}function n.render(H)return c.createElement("\100\105\118")end;(R(function()H.act(function()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end)end)).toErrorDev({"\070\111\111\058 \116\121\112\101 \115\112\101\099\105\102\105\099\097\116\105\111\110 \111\102 \112\114\111\112 \096\109\121\080\114\111\112\096 \105\115 \105\110\118\097\108\105\100\059 \116\104\101 \116\121\112\101 \099\104\101\099\107\101\114 \102\117\110\099\116\105\111\110 \109\117\115\116 \114\101\116\117\114\110 \096\110\105\108\096 \111\114 \097\110 \096\069\114\114\111\114\096 \098\117\116 \114\101\116\117\114\110\101\100 \097 \115\116\114\105\110\103\046 \089\111\117 \109\097\121 \104\097\118\101 \102\111\114\103\111\116\116\101\110 \116\111 \112\097\115\115 \097\110 \097\114\103\117\109\101\110\116 \116\111 \116\104\101 \116\121\112\101 \099\104\101\099\107\101\114 \099\114\101\097\116\111\114 \040\097\114\114\097\121\079\102\044 \105\110\115\116\097\110\099\101\079\102\044 \111\098\106\101\099\116\079\102\044 \111\110\101\079\102\044 \111\110\101\079\102\084\121\112\101\044 \097\110\100 \115\104\097\112\101 \097\108\108 \114\101\113\117\105\114\101 \097\110 \097\114\103\117\109\101\110\116\041\046"})end)f("\098\097\100 \118\097\108\105\100\097\116\101\080\114\111\112\115 \109\101\116\104\111\100",function()local n=c.Component:extend("\070\111\111")function n.render(H)return c.createElement("\100\105\118")end;(R(e)).toFlushWithoutYielding();(R(function()H.act(function()n.validateProps="\116\104\105\115 \105\115 \097 \115\116\114\105\110\103"H.render(c.createElement(n,{myProp="\104\101\108\108\111"}))end)end)).toErrorDev({"\118\097\108\105\100\097\116\101\080\114\111\112\115 \109\117\115\116 \098\101 \097 \102\117\110\099\116\105\111\110\044 \098\117\116 \105\116 \105\115 \097 \115\116\114\105\110\103\046\n\067\104\101\099\107 \116\104\101 \100\101\102\105\110\105\116\105\111\110 \111\102 \116\104\101 \099\111\109\112\111\110\101\110\116 \"\070\111\111\"\046"},{withoutStack=1})end)b("\095\095\068\073\083\065\066\076\069\095\065\076\076\095\087\065\082\078\073\078\071\083\095\069\088\067\069\080\084\095\080\082\079\080\095\086\065\076\073\068\065\084\073\079\078\095\095",function()Q(function(c)c.oldValidate=_G.__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__ _G.__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__=true end)v(function(c)_G.__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__=c.oldValidate end)f("\118\097\108\105\100\097\116\101\080\114\111\112\115 \100\101\102\105\110\101\100\044 \114\101\116\117\114\110\115 \102\097\108\115\101",function()local n=c.Component:extend("\070\111\111")n.validateProps=function(c)return false,"\110\111 \110\111 \110\111 \110\111 \110\111"end function n.render(H)return c.createElement("\100\105\118")end local function v()H.render(c.createElement(n,{myProp="\104\101\108\108\111"}));(R(e)).toFlushWithoutYielding()end if _G.__DEV__ then(R(v)).toThrow("\110\111 \110\111 \110\111 \110\111 \110\111")else(R(v)).never.toThrow()end end)end)end)
local React

local ReactNoop
local Scheduler
local JestGlobals = require("@pkg/@jsdotlua/jest-globals")
local afterEach = JestGlobals.afterEach
local beforeEach = JestGlobals.beforeEach
local jestExpect = JestGlobals.expect
local describe = JestGlobals.describe
local it = JestGlobals.it
local jest = JestGlobals.jest
local LuauPolyfill = require("@pkg/@jsdotlua/luau-polyfill")
local Error = LuauPolyfill.Error

describe("tests propTypes and validateProps behavior", function()
	beforeEach(function()
		jest.resetModules()
		ReactNoop = require("@pkg/@jsdotlua/react-noop-renderer")
		Scheduler = require("@pkg/@jsdotlua/scheduler")
		React = require("@pkg/@jsdotlua/react")
	end)
	it("propTypes defined, returns error", function()
		local Foo = React.Component:extend("div")

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				return Error("no no no no no")
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end
		jestExpect(function()
			ReactNoop.act(function()
				ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
				jestExpect(Scheduler).toFlushWithoutYielding()
			end)
		end).toWarnDev("no no no no no")
	end)
	it("propTypes defined, returns nil", function()
		local Foo = React.Component:extend("Foo")

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				return nil
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end
		ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
		jestExpect(Scheduler).toFlushWithoutYielding()
	end)
	it("validateProps defined, returns false", function()
		local Foo = React.Component:extend("Foo")

		Foo.validateProps = function(props)
			return false, "no no no no no"
		end

		function Foo:render()
			return React.createElement("div")
		end
		local function testValidation()
			ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
			jestExpect(Scheduler).toFlushWithoutYielding()
		end
		if _G.__DEV__ then
			-- For legacy compatibility, this test throws as well as warning
			jestExpect(testValidation).toThrow("no no no no no")
		else
			jestExpect(testValidation).never.toThrow()
		end
	end)
	it("validateProps defined, returns true", function()
		local Foo = React.Component:extend("Foo")

		Foo.validateProps = function(props)
			return true
		end

		function Foo:render()
			return React.createElement("div")
		end

		ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
		jestExpect(Scheduler).toFlushWithoutYielding()
	end)
	it("warning when both methods are defined", function()
		local Foo = React.Component:extend("Foo")

		Foo.validateProps = function(props)
			return true
		end

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				return nil
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end

		jestExpect(function()
			ReactNoop.act(function()
				ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
				jestExpect(Scheduler).toFlushWithoutYielding()
			end)
		end).toWarnDev(
			"You've defined both propTypes and validateProps on Foo",
			{ withoutStack = true }
		)
	end)
	it("validateProps fails, propTypes fails", function()
		local Foo = React.Component:extend("Foo")

		Foo.validateProps = function(props)
			return false, "no no no no no"
		end

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				error(Error("no no no no no"))
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end

		local function testValidation()
			jestExpect(function()
				ReactNoop.act(function()
					ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
					jestExpect(Scheduler).toFlushWithoutYielding()
				end)
			end).toWarnDev(
				"You've defined both propTypes and validateProps on Foo",
				{ withoutStack = 2 }
			)
		end
		if _G.__DEV__ then
			-- For legacy compatibility, this test throws as well as warning
			jestExpect(testValidation).toThrow("no no no no no")
		else
			jestExpect(testValidation).never.toThrow()
		end
	end)
	it("validateProps succeeds, propTypes fails", function()
		local Foo = React.Component:extend("Foo")

		Foo.validateProps = function(props)
			return true
		end

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				error(Error("no no no no no"))
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end

		jestExpect(function()
			ReactNoop.act(function()
				ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
				jestExpect(Scheduler).toFlushWithoutYielding()
			end)
		end).toWarnDev({
			"You've defined both propTypes and validateProps on Foo",
			"no no no no no",
		}, { withoutStack = 1 })
	end)
	it("validateProps fails, propTypes succeeds", function()
		local Foo = React.Component:extend("Foo")

		Foo.validateProps = function(props)
			return false, "no no no no no"
		end

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				return nil
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end

		local function testValidation()
			jestExpect(function()
				ReactNoop.act(function()
					ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
					jestExpect(Scheduler).toFlushWithoutYielding()
				end)
			end).toWarnDev(
				"You've defined both propTypes and validateProps on Foo",
				{ withoutStack = 2 }
			)
		end
		if _G.__DEV__ then
			-- For legacy compatibility, this test throws as well as warning
			jestExpect(testValidation).toThrow("no no no no no")
		else
			jestExpect(testValidation).never.toThrow()
		end
	end)
	it("bad propTypes method", function()
		local Foo = React.Component:extend("Foo")

		Foo.propTypes = {
			myProp = function(prop, propName, componentName)
				return "nil"
			end,
		}

		function Foo:render()
			return React.createElement("div")
		end

		jestExpect(function()
			ReactNoop.act(function()
				ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
				jestExpect(Scheduler).toFlushWithoutYielding()
			end)
		end).toErrorDev({
			"Foo: type specification of prop"
				.. " `myProp` is invalid; the type checker "
				.. "function must return `nil` or an `Error` but returned a string. "
				.. "You may have forgotten to pass an argument to the type checker "
				.. "creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and "
				.. "shape all require an argument).",
		})
	end)
	it("bad validateProps method", function()
		local Foo = React.Component:extend("Foo")

		function Foo:render()
			return React.createElement("div")
		end

		jestExpect(Scheduler).toFlushWithoutYielding()
		jestExpect(function()
			ReactNoop.act(function()
				Foo.validateProps = "this is a string"

				ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
			end)
		end).toErrorDev({
			'validateProps must be a function, but it is a string.\nCheck the definition of the component "Foo".',
		}, { withoutStack = 1 })
	end)

	describe("__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__", function()
		beforeEach(function(context)
			context.oldValidate = _G.__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__
			_G.__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__ = true
		end)

		afterEach(function(context)
			_G.__DISABLE_ALL_WARNINGS_EXCEPT_PROP_VALIDATION__ = context.oldValidate
		end)

		it("validateProps defined, returns false", function()
			local Foo = React.Component:extend("Foo")

			Foo.validateProps = function(props)
				return false, "no no no no no"
			end

			function Foo:render()
				return React.createElement("div")
			end
			local function testValidation()
				ReactNoop.render(React.createElement(Foo, { myProp = "hello" }))
				jestExpect(Scheduler).toFlushWithoutYielding()
			end

			-- For legacy compatibility, this test throws as well as warning
			if _G.__DEV__ then
				jestExpect(testValidation).toThrow("no no no no no")
			else
				jestExpect(testValidation).never.toThrow()
			end
		end)
	end)
end)
