local j=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 d=j.beforeEach local A=j.expect local f=j.it local T=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 Z=T.Array local O=T.Error local I local g local G local J d(function()I=(require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\115\104\097\114\101\100")).UninitializedState g=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\114\101\097\099\116")G=require("\046\046")J=G.createRenderer end)local function S(j)if _G.__DEV__ then j._store.validated=true end return j end local function v(j)if _G.__DEV__ then for j,d in j do S(d)end end return j end local function s(j,d,A)if not A and j==nil then return nil end if type(j)~=d then return O("\101\120\112\101\099\116\101\100 "..d)end return nil end local t={string=function(j,d)return s(j[d],"\115\116\114\105\110\103")end;string_isRequired=function(j,d)return s(j[d],"\115\116\114\105\110\103",true)end}f("\115\104\111\117\108\100 \099\097\108\108 \097\108\108 \111\102 \116\104\101 \108\101\103\097\099\121 \108\105\102\101\099\121\099\108\101 \104\111\111\107\115",function()local j={}local d=function(d)return function()table.insert(j,d)return true end end local f=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")f.UNSAFE_componentWillMount=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116")f.componentDidMount=d("\099\111\109\112\111\110\101\110\116\068\105\100\077\111\117\110\116")f.UNSAFE_componentWillReceiveProps=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115")f.shouldComponentUpdate=d("\115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101")f.UNSAFE_componentWillUpdate=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101")f.componentDidUpdate=d("\099\111\109\112\111\110\101\110\116\068\105\100\085\112\100\097\116\101")f.componentWillUnmount=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\085\110\109\111\117\110\116")function f.render(j)return g.createElement("\070\114\097\109\101")end local T=J()T:render(g.createElement(f,{foo=1}));(A(j)).toEqual({"\099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116"})Z.splice(j,1)local O=T:getMountedInstance()O:setState({});(A(j)).toEqual({"\115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101";"\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101"})Z.splice(j,1)T:render(g.createElement(f,{foo=2}));(A(j)).toEqual({"\099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115";"\115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101","\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101"})end)f("\115\104\111\117\108\100 \099\097\108\108 \097\108\108 \111\102 \116\104\101 \110\101\119 \108\105\102\101\099\121\099\108\101 \104\111\111\107\115",function()local j={}local d=function(d)return function()table.insert(j,d)return true end end local f=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")f.getDerivedStateFromProps=d("\103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115")f.componentDidMount=d("\099\111\109\112\111\110\101\110\116\068\105\100\077\111\117\110\116")f.shouldComponentUpdate=d("\115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101")f.componentDidUpdate=d("\099\111\109\112\111\110\101\110\116\068\105\100\085\112\100\097\116\101")f.componentWillUnmount=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\085\110\109\111\117\110\116")function f.init(j)j.state={}end function f.render(j)return g.createElement("\070\114\097\109\101")end local T=J()T:render(g.createElement(f,{foo=1}));(A(j)).toEqual({"\103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115"})Z.splice(j,1)local O=T:getMountedInstance()O:setState({});(A(j)).toEqual({"\103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115","\115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101"})Z.splice(j,1)T:render(g.createElement(f,{foo=2}));(A(j)).toEqual({"\103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115";"\115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101"})end)f("\115\104\111\117\108\100 \110\111\116 \105\110\118\111\107\101 \100\101\112\114\101\099\097\116\101\100 \108\105\102\101\099\121\099\108\101\115 \040\099\087\077\047\099\087\082\080\047\099\087\085\041 \105\102 \110\101\119 \115\116\097\116\105\099 \103\068\083\070\080 \105\115 \112\114\101\115\101\110\116",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={}end function j.getDerivedStateFromProps()return nil end function j.componentWillMount(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.componentWillReceiveProps(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.componentWillUpdate(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.render(j)return nil end local d=J();(A(function()d:render(g.createElement(j))end)).never.toThrow()end)f("\115\104\111\117\108\100 \110\111\116 \105\110\118\111\107\101 \100\101\112\114\101\099\097\116\101\100 \108\105\102\101\099\121\099\108\101\115 \040\099\087\077\047\099\087\082\080\047\099\087\085\041 \105\102 \110\101\119 \103\101\116\083\110\097\112\115\104\111\116\066\101\102\111\114\101\085\112\100\097\116\101 \105\115 \112\114\101\115\101\110\116",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.getSnapshotBeforeUpdate(j)return nil end function j.componentWillMount(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.componentWillReceiveProps(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.componentWillUpdate(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.render(j)return nil end local d=J();(A(function()d:render(g.createElement(j,{value=1}))end)).never.toThrow();(A(function()d:render(g.createElement(j,{value=2}))end)).never.toThrow()end)f("\115\104\111\117\108\100 \110\111\116 \099\097\108\108 \103\101\116\083\110\097\112\115\104\111\116\066\101\102\111\114\101\085\112\100\097\116\101 \111\114 \099\111\109\112\111\110\101\110\116\068\105\100\085\112\100\097\116\101 \119\104\101\110 \117\112\100\097\116\105\110\103 \115\105\110\099\101 \114\101\102\115 \119\111\110\116 \101\120\105\115\116",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.getSnapshotBeforeUpdate(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.componentDidUpdate(j)error(O("\117\110\101\120\112\101\099\116\101\100"))end function j.render(j)return nil end local d=J();(A(function()d:render(g.createElement(j,{value=1}))end)).never.toThrow();(A(function()d:render(g.createElement(j,{value=2}))end)).never.toThrow()end)f("\115\104\111\117\108\100 \111\110\108\121 \114\101\110\100\101\114 \049 \108\101\118\101\108 \100\101\101\112",function()local function j()error(O("\084\104\105\115 \099\111\109\112\111\110\101\110\116 \115\104\111\117\108\100 \110\111\116 \114\101\110\100\101\114"))end local function d()return g.createElement("\070\114\097\109\101",nil,{Child=g.createElement(j)})end local A=J()A:render(g.createElement(d))end)f("\115\104\111\117\108\100 \104\097\118\101 \115\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\070\114\097\109\101",nil,g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\049"}),g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\050"}))end local d=J()local f=d:render(g.createElement(j));(A(f.type)).toEqual("\070\114\097\109\101");(A(f.props.children)).toEqual(v({g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\049"});g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\050"})}))end)f("\115\104\111\117\108\100 \104\097\110\100\108\101 \070\111\114\119\097\114\100\082\101\102",function()local j=g.createRef()local d=g.forwardRef(function(d,f)(A(f)).toEqual(j)return g.createElement("\070\114\097\109\101",nil,g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\049"}),g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\050"}))end)local f=J()local T=f:render(g.createElement(d,{ref=j}));(A(T.type)).toEqual("\070\114\097\109\101");(A(T.props.children)).toEqual(v({g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\049"});g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\099\104\105\108\100\050"})}))end)f("\115\104\111\117\108\100 \104\097\110\100\108\101 \080\114\111\102\105\108\101\114",function()local j=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement(g.Profiler,{id="\116\101\115\116",onRender=function() end},g.createElement("\084\101\120\116",nil,g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\049"}),g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\050"})))end local d=J()local f=d:render(g.createElement(j));(A(f.type)).toEqual(g.Profiler);(A(f.props.children)).toEqual(S(g.createElement("\084\101\120\116",nil,g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\049"}),g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\050"}))))end)f("\115\104\111\117\108\100 \101\110\097\098\108\101 \115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101 \116\111 \112\114\101\118\101\110\116 \097 \114\101-\114\101\110\100\101\114",function()local j=0 local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={update=false}end function d.shouldComponentUpdate(A,j,d)return A.state.update~=d.update end function d.render(d)j+=1 return g.createElement("\084\101\120\116\076\097\098\101\108",{Text=j})end local f=J()f:render(g.createElement(d));(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))local T=f:getMountedInstance()T:setState({update=false});(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))T:setState({update=true});(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=2}))end)f("\115\104\111\117\108\100 \101\110\097\098\108\101 \080\117\114\101\067\111\109\112\111\110\101\110\116 \116\111 \112\114\101\118\101\110\116 \097 \114\101-\114\101\110\100\101\114",function()local j=0 local d=g.PureComponent:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={update=false}end function d.render(d)j+=1 return g.createElement("\084\101\120\116\076\097\098\101\108",{Text=j})end local f=J()f:render(g.createElement(d));(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))local T=f:getMountedInstance()T:setState({update=false});(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))T:setState({update=true});(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=2}))end)f("\115\104\111\117\108\100 \110\111\116 \114\117\110 \115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101 \100\117\114\105\110\103 \102\111\114\099\101\100 \117\112\100\097\116\101",function()local j=0 local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={count=1}end function d.shouldComponentUpdate(d)j+=1 return false end function d.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",{Text=j.state.count})end local f=J()f:render(g.createElement(d));(A(j)).toEqual(0);(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))local T=f:getMountedInstance()T:forceUpdate();(A(j)).toEqual(0);(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))T:setState(function(j)return{count=j.count+1}end);(A(j)).toEqual(1);(A(T.state.count)).toEqual(2);(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=1}))T:forceUpdate();(A(j)).toEqual(1);(A(T.state.count)).toEqual(2);(A(f:getRenderOutput())).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text=2}))end)f("\115\104\111\117\108\100 \114\101\114\101\110\100\101\114 \119\104\101\110 \099\097\108\108\105\110\103 \102\111\114\099\101\085\112\100\097\116\101",function()local j=0 local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.render(d)j+=1 return g.createElement("\084\101\120\116\076\097\098\101\108")end local f=J()f:render(g.createElement(d));(A(j)).toEqual(1)local T=f:getMountedInstance()T:forceUpdate();(A(j)).toEqual(2)end)f("\115\104\111\117\108\100 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \097 \102\117\110\099\116\105\111\110 \099\111\109\112\111\110\101\110\116",function()local j=function(j,d)return g.createElement("\070\114\097\109\101",nil,{ChildFoo=g.createElement("\084\101\120\116\076\097\098\101\108",{Text=j.foo}),ChildBar=g.createElement("\084\101\120\116\076\097\098\101\108",{Text=d.bar}),Child1=g.createElement("\070\114\097\109\101",{Value="\099\104\105\108\100\049"}),Child2=g.createElement("\070\114\097\109\101",{Value="\099\104\105\108\100\050"})})end local d=J()local f=d:render(g.createElement(j,{foo="\070\079\079"}),{bar="\066\065\082"});(A(f.type)).toEqual("\070\114\097\109\101");(A(f.props.children)).toEqual(v({ChildFoo=g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\070\079\079"});ChildBar=g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\066\065\082"});Child1=g.createElement("\070\114\097\109\101",{Value="\099\104\105\108\100\049"}),Child2=g.createElement("\070\114\097\109\101",{Value="\099\104\105\108\100\050"})}))end)f("\115\104\111\117\108\100 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \097 \099\111\109\112\111\110\101\110\116 \114\101\116\117\114\110\105\110\103 \115\116\114\105\110\103\115 \100\105\114\101\099\116\108\121 \102\114\111\109 \114\101\110\100\101\114",function()local j=function(j)return j.value end local d=J()local f=d:render(g.createElement(j,{value="\102\111\111"}));(A(f)).toEqual("\102\111\111")end)f("\115\104\111\117\108\100 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \097 \099\111\109\112\111\110\101\110\116 \114\101\116\117\114\110\105\110\103 \110\117\109\098\101\114\115 \100\105\114\101\099\116\108\121 \102\114\111\109 \114\101\110\100\101\114",function()local j=function(j)return j.value end local d=J()local f=d:render(g.createElement(j,{value=10}));(A(f)).toEqual(10)end)f("\115\104\111\117\108\100 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \097 \102\114\097\103\109\101\110\116",function()local j=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108")end local d=g.Component:extend("\070\114\097\103\109\101\110\116")function d.render(d)return{ChildA=g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\097"}),ChildB=g.createElement("\070\114\097\109\101",{Value="\098"}),ChildC=g.createElement(j)}end local f=J()local T=f:render(g.createElement(d));(A(T.ChildA)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\097"}));(A(T.ChildB)).toEqual(g.createElement("\070\114\097\109\101",{Value="\098"}));(A(T.ChildC)).toEqual(g.createElement(j));(A(T)).toEqual({ChildC=g.createElement(j),ChildA=g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\097"});ChildB=g.createElement("\070\114\097\109\101",{Value="\098"})})end)f("\115\104\111\117\108\100 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \097 \082\101\097\099\116\046\070\114\097\103\109\101\110\116",function()local j=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108")end local d=g.Component:extend("\070\114\097\103\109\101\110\116")function d.render(d)return g.createElement(g.Fragment,nil,g.createElement("\084\101\120\116"),g.createElement("\070\114\097\109\101"),g.createElement(j))end local f=J()local T=f:render(g.createElement(d));(A(T.type)).toEqual(g.Fragment);(A(#T.props.children)).toEqual(3);(A(T.props.children[1])).toEqual(S(g.createElement("\084\101\120\116")));(A(T.props.children[2])).toEqual(S(g.createElement("\070\114\097\109\101")))g.createElement(g.Fragment,nil,g.createElement("\084\101\120\116"),g.createElement("\070\114\097\109\101"),g.createElement(j))end)f("\115\104\111\117\108\100 \116\104\114\111\119 \102\111\114 \105\110\118\097\108\105\100 \101\108\101\109\101\110\116\115",function()local j=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108")end local d=J();(A(function()d:render(j)end)).toThrow("\082\101\097\099\116\083\104\097\108\108\111\119\082\101\110\100\101\114\101\114 \114\101\110\100\101\114\040\041\058 \073\110\118\097\108\105\100 \099\111\109\112\111\110\101\110\116 \101\108\101\109\101\110\116\046 \073\110\115\116\101\097\100 \111\102 \112\097\115\115\105\110\103 \097 \099\111\109\112\111\110\101\110\116 \099\108\097\115\115\044 \109\097\107\101 \115\117\114\101 \116\111 \105\110\115\116\097\110\116\105\097\116\101 \105\116 \098\121 \112\097\115\115\105\110\103 \105\116 \116\111 \082\101\097\099\116\046\099\114\101\097\116\101\069\108\101\109\101\110\116\046");(A(function()d:render(g.createElement("\100\105\118"))end)).toThrow("\082\101\097\099\116\083\104\097\108\108\111\119\082\101\110\100\101\114\101\114 \114\101\110\100\101\114\040\041\058 \083\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103 \119\111\114\107\115 \111\110\108\121 \119\105\116\104 \099\117\115\116\111\109 \099\111\109\112\111\110\101\110\116\115\044 \110\111\116 \112\114\105\109\105\116\105\118\101\115 \040\100\105\118\041\046 \073\110\115\116\101\097\100 \111\102 \099\097\108\108\105\110\103 \096\046\114\101\110\100\101\114\040\101\108\041\096 \097\110\100 \105\110\115\112\101\099\116\105\110\103 \116\104\101 \114\101\110\100\101\114\101\100 \111\117\116\112\117\116\044 \108\111\111\107 \097\116 \096\101\108\046\112\114\111\112\115\096 \100\105\114\101\099\116\108\121 \105\110\115\116\101\097\100\046")end)f("\115\104\111\117\108\100 \104\097\118\101 \115\104\097\108\108\111\119 \117\110\109\111\117\110\116\105\110\103",function()local j=false local d=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function d.componentWillUnmount(d)j=true end function d.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108")end local f=J()f:render(g.createElement(d))f:unmount();(A(j)).toEqual(true)end)f("\099\097\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \116\111 \110\105\108",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.render(j)return nil end local d=J()local f=d:render(g.createElement(j));(A(f)).toEqual(nil)end)f("\099\097\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114 \119\105\116\104 \097 \114\101\102",function()local j=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\115\116\076\097\098\101\108",{ref="\104\101\108\108\111"})end local d=J();(A(function()d:render(g.createElement(j))end)).never.toThrow()end)f("\108\101\116\115 \121\111\117 \117\112\100\097\116\101 \115\104\097\108\108\111\119\108\121 \114\101\110\100\101\114\101\100 \099\111\109\112\111\110\101\110\116\115",function()local j=g.Component:extend("\083\111\109\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={clicked=false}end function j.onClick(j)j:setState({clicked=true})end function j.render(j)local d if j.state.clicked then d="\119\097\115-\099\108\105\099\107\101\100"else d=""end if j.props.aNew=="\112\114\111\112"then return g.createElement("\066\117\116\116\111\110",{onClick=function()j:onClick()end,className=d})else return g.createElement("\084\101\120\116\076\097\098\101\108",nil,g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\049"}),g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\050"}))end end local d=J()local f=d:render(g.createElement(j));(A(f.type)).toEqual("\084\101\120\116\076\097\098\101\108");(A(f.props.children)).toEqual(v({g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\049"}),g.createElement("\070\114\097\109\101",{className="\099\104\105\108\100\050"})}))local T=d:render(g.createElement(j,{aNew="\112\114\111\112"}));(A(T.type)).toEqual("\066\117\116\116\111\110")T.props:onClick()local Z=d:getRenderOutput();(A(Z.type)).toEqual("\066\117\116\116\111\110");(A(Z.props.className)).toEqual("\119\097\115-\099\108\105\099\107\101\100")end)f("\099\097\110 \097\099\099\101\115\115 \116\104\101 \109\111\117\110\116\101\100 \099\111\109\112\111\110\101\110\116 \105\110\115\116\097\110\099\101",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.someMethod(j)return j.props.n end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",{Text=j.props.n})end local d=J()d:render(g.createElement(j,{n=5}));(A((d:getMountedInstance()):someMethod())).toEqual(5)end)f("\099\097\110 \115\104\097\108\108\111\119\108\121 \114\101\110\100\101\114 \099\111\109\112\111\110\101\110\116\115 \119\105\116\104 \099\111\110\116\101\120\116\084\121\112\101\115",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")j.contextTypes={name=t.string}function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108")end local d=J()local f=d:render(g.createElement(j));(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108"))end)f("\112\097\115\115\101\115 \101\120\112\101\099\116\101\100 \112\097\114\097\109\115 \116\111 \108\101\103\097\099\121 \099\111\109\112\111\110\101\110\116 \108\105\102\101\099\121\099\108\101 \109\101\116\104\111\100\115",function()local j={}local d={}local f={}local T={}local Z={}local O={prop="\105\110\105\116 \112\114\111\112"}local I={state="\105\110\105\116 \115\116\097\116\101"}local G={context="\105\110\105\116 \099\111\110\116\101\120\116"}local S={state="\117\112\100\097\116\101\100 \115\116\097\116\101"}local v={prop="\117\112\100\097\116\101\100 \112\114\111\112"}local s={context="\117\112\100\097\116\101\100 \099\111\110\116\101\120\116"}local h=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function h.init(A,j,d)A.state=I end h.contextTypes={context=t.string}function h.componentDidUpdate(d,...)table.insert(j,{...})end function h.UNSAFE_componentWillReceiveProps(j,...)table.insert(d,{...})j:setState(function(...)table.insert(T,{...})return S end)end function h.UNSAFE_componentWillUpdate(j,...)table.insert(f,{...})end function h.shouldComponentUpdate(j,...)table.insert(Z,{...})return true end function h.render(j)return nil end local z=J()z:render(g.createElement(h,O),G);(A(j)).toEqual({});(A(d)).toEqual({});(A(f)).toEqual({});(A(T)).toEqual({});(A(Z)).toEqual({})z:render(g.createElement(h,v),s);(A(d)).toEqual({{v;s}});(A(T)).toEqual({{I;O}});(A(Z)).toEqual({{v;S,s}});(A(f)).toEqual({{v;S;s}});(A(j)).toEqual({})end)f("\112\097\115\115\101\115 \101\120\112\101\099\116\101\100 \112\097\114\097\109\115 \116\111 \110\101\119 \099\111\109\112\111\110\101\110\116 \108\105\102\101\099\121\099\108\101 \109\101\116\104\111\100\115",function()local j={}local d={}local f={}local T={prop="\105\110\105\116 \112\114\111\112"}local Z={state="\105\110\105\116 \115\116\097\116\101"}local O={context="\105\110\105\116 \099\111\110\116\101\120\116"}local I={prop="\117\112\100\097\116\101\100 \112\114\111\112"}local G={context="\117\112\100\097\116\101\100 \099\111\110\116\101\120\116"}local S=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function S.init(A,j,d)A.state=Z end S.contextTypes={context=t.string}function S.componentDidUpdate(d,...)table.insert(j,{...})end function S.getDerivedStateFromProps(...)table.insert(d,{...})return nil end function S.shouldComponentUpdate(j,...)table.insert(f,{...})return true end function S.render(j)return nil end local v=J()v:render(g.createElement(S,T),O);(A(d)).toEqual({{T;Z}});(A(j)).toEqual({});(A(f)).toEqual({})v:render(g.createElement(S,I),G);(A(d)).toEqual({{T;Z};{I;Z}});(A(f)).toEqual({{I,Z,G}});(A(j)).toEqual({})end)f("\099\097\110 \115\104\097\108\108\111\119\108\121 \114\101\110\100\101\114 \099\111\109\112\111\110\101\110\116\115 \119\105\116\104 \114\101\102 \097\115 \102\117\110\099\116\105\111\110",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={clicked=false}end function j.handleUserClick(j)j:setState({clicked=true})end function j.render(d)local A if d.state.clicked then A="\099\108\105\099\107\101\100"else A=""end return g.createElement(j,{ref=function() end,onClick=function()d:handleUserClick()end;className=A})end local d=J()d:render(g.createElement(j))local f=d:getRenderOutput();(A(f.props.className)).toEqual("")f.props.onClick()f=d:getRenderOutput();(A(f.props.className)).toEqual("\099\108\105\099\107\101\100")end)f("\099\097\110 \105\110\105\116\105\097\108\105\122\101 \115\116\097\116\101 \118\105\097 \115\116\097\116\105\099 \103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={count=1}end function j.getDerivedStateFromProps(j,d)return{count=d.count+j.incrementBy,other="\102\111\111\098\097\114"}end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",nil,"\099\111\117\110\116\058"..(j.state.count..("\044 \111\116\104\101\114\058"..j.state.other)))end local d=J()local f=d:render(g.createElement(j,{incrementBy=2}));(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",nil,"\099\111\117\110\116\058\051\044 \111\116\104\101\114\058\102\111\111\098\097\114"))end)f("\099\097\110 \115\101\116\083\116\097\116\101 \105\110 \099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116 \119\104\101\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.UNSAFE_componentWillMount(j)j:setState({groovy="\100\111\111\118\121"})end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",{Text=j.state.groovy})end local d=J()local f=d:render(g.createElement(j));(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\100\111\111\118\121"}))end)f("\099\097\110 \115\101\116\083\116\097\116\101 \105\110 \099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116 \114\101\112\101\097\116\101\100\108\121 \119\104\101\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={separator="-"}end function j.UNSAFE_componentWillMount(j)j:setState({groovy="\100\111\111\118\121"})j:setState({doovy="\103\114\111\111\118\121"})end function j.render(j)local d=j.state.groovy local A=j.state.doovy local f=j.state.separator return g.createElement("\084\101\120\116\076\097\098\101\108",{Text=d..(f..A)})end local d=J()local f=d:render(g.createElement(j));(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\100\111\111\118\121-\103\114\111\111\118\121"}))end)f("\099\097\110 \115\101\116\083\116\097\116\101 \105\110 \099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116 \119\105\116\104 \097\110 \117\112\100\097\116\101\114 \102\117\110\099\116\105\111\110 \114\101\112\101\097\116\101\100\108\121 \119\104\101\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={separator="-"}end function j.UNSAFE_componentWillMount(j)j:setState(function(j)return{groovy="\100\111\111\118\121"}end)j:setState(function(j)return{doovy=j.groovy}end)end function j.render(j)local d=j.state.groovy local A=j.state.doovy local f=j.state.separator return g.createElement("\084\101\120\116\076\097\098\101\108",nil,{d..(f..A)})end local d=J()local f=d:render(g.createElement(j));(A(f.props.children[1])).toEqual("\100\111\111\118\121-\100\111\111\118\121")end)f("\099\097\110 \115\101\116\083\116\097\116\101 \105\110 \099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115 \119\104\101\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={count=0}end function j.UNSAFE_componentWillReceiveProps(d,j)if j.updateState then d:setState({count=1})end end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",nil,j.state.count)end local d=J()local f=d:render(g.createElement(j,{updateState=false}));(A(f.props.children)).toEqual(0)f=d:render(g.createElement(j,{updateState=true}));(A(f.props.children)).toEqual(1)end)f("\099\097\110 \117\112\100\097\116\101 \115\116\097\116\101 \119\105\116\104 \115\116\097\116\105\099 \103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115 \119\104\101\110 \115\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={count=1}end function j.getDerivedStateFromProps(j,d)if j.updateState then return{count=j.incrementBy+d.count}end return nil end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",nil,j.state.count)end local d=J()local f=d:render(g.createElement(j,{updateState=false;incrementBy=0}));(A(f.props.children)).toEqual(1)f=d:render(g.createElement(j,{updateState=true;incrementBy=2}));(A(f.props.children)).toEqual(3)f=d:render(g.createElement(j,{updateState=false;incrementBy=2}));(A(f.props.children)).toEqual(3)end)f("\115\104\111\117\108\100 \110\111\116 \111\118\101\114\114\105\100\101 \115\116\097\116\101 \119\105\116\104 \115\116\097\108\101 \118\097\108\117\101\115 \105\102 \112\114\101\118\083\116\097\116\101 \105\115 \115\112\114\101\097\100 \119\105\116\104\105\110 \103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={value=0}end function j.getDerivedStateFromProps(j,d)return{table.unpack(d)}end function j.updateState(j)j:setState(function(j)return{value=j.value+1}end)end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",nil,"\118\097\108\117\101\058"..j.state.value)end local d=J()local f=d:render(g.createElement(j));(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",nil,"\118\097\108\117\101\058\048"))local T=d:getMountedInstance()T:updateState()f=d:getRenderOutput();(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",nil,"\118\097\108\117\101\058\049"))end)f("\115\104\111\117\108\100 \112\097\115\115 \112\114\101\118\105\111\117\115 \115\116\097\116\101 \116\111 \115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101 \101\118\101\110 \119\105\116\104 \103\101\116\068\101\114\105\118\101\100\083\116\097\116\101\070\114\111\109\080\114\111\112\115",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(j)j.state={value=j.props.value}end function j.getDerivedStateFromProps(j,d)if j.value==d.value then return nil end return{value=j.value}end function j.shouldComponentUpdate(A,j,d)return d.value~=A.state.value end function j.render(j)return g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\118\097\108\117\101\058"..j.state.value})end local d=J()local f=d:render(g.createElement(j,{value="\105\110\105\116\105\097\108"}));(A(f)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\118\097\108\117\101\058\105\110\105\116\105\097\108"}))local T=d:render(g.createElement(j,{value="\117\112\100\097\116\101\100"}));(A(T)).toEqual(g.createElement("\084\101\120\116\076\097\098\101\108",{Text="\118\097\108\117\101\058\117\112\100\097\116\101\100"}))end)f("\099\097\110 \115\101\116\083\116\097\116\101 \119\105\116\104 \097\110 \117\112\100\097\116\101\114 \102\117\110\099\116\105\111\110",function()local j local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={counter=0}end function d.render(d)j=d return g.createElement("\066\117\116\116\111\110",nil,d.state.counter)end local f=J()local T=f:render(g.createElement(d,{defaultCount=1}));(A(T.props.children)).toEqual(0)j:setState(function(d,A)return{counter=j.props.defaultCount+1}end)T=f:getRenderOutput();(A(T.props.children)).toEqual(2)end)f.skip("\099\097\110 \097\099\099\101\115\115 \099\111\109\112\111\110\101\110\116 \105\110\115\116\097\110\099\101 \102\114\111\109 \115\101\116\083\116\097\116\101 \117\112\100\097\116\101\114 \102\117\110\099\116\105\111\110",function()local j local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={something="\104\101\114\101"}end function d.render(d)j=d return nil end local f=J()f:render(g.createElement(d,{myProp=31337}))local T=false j:setState(function(j,d)(A(j)).toEqual({something="\104\101\114\101"});(A(d)).toEqual({myProp=31337})T=true end);(A(T)).toEqual(true)end)f("\099\097\110 \115\101\116\083\116\097\116\101 \119\105\116\104 \097 \099\097\108\108\098\097\099\107",function()local j local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={counter=0}end function d.render(d)j=d return g.createElement("\084\101\120\116",nil,d.state.counter)end local f=J()local T=f:render(g.createElement(d));(A(T.props.children)).toEqual(0)local Z=false local O=function(d)Z=true;(A(d)).toEqual(j)end j:setState({counter=1},O)local I=f:getRenderOutput();(A(I.props.children)).toEqual(1);(A(Z)).toEqual(true)end)f("\099\097\110 \114\101\112\108\097\099\101\083\116\097\116\101 \119\105\116\104 \097 \099\097\108\108\098\097\099\107",function()local j local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={counter=0}end function d.render(d)j=d return g.createElement("\084\101\120\116",nil,d.state.counter)end local f=J()local T=f:render(g.createElement(d));(A(T.props.children)).toEqual(0)local Z=false local O=function(d)Z=true;(A(d)).toEqual(j)end f._updater.enqueueReplaceState(j,{counter=1},O)local I=f:getRenderOutput();(A(I.props.children)).toEqual(1);(A(Z)).toEqual(true)end)f("\099\097\110 \102\111\114\099\101\085\112\100\097\116\101 \119\105\116\104 \097 \099\097\108\108\098\097\099\107",function()local j local d=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function d.init(j)j.state={counter=0}end function d.render(d)j=d return g.createElement("\084\101\120\116",nil,d.state.counter)end local f=J()local T=f:render(g.createElement(d));(A(T.props.children)).toEqual(0)local Z=false local O=function(d)Z=true;(A(d)).toEqual(j)end j:forceUpdate(O)local I=f:getRenderOutput();(A(I.props.children)).toEqual(0);(A(Z)).toEqual(true)end)f("\099\097\110 \112\097\115\115 \099\111\110\116\101\120\116 \119\104\101\110 \115\104\097\108\108\111\119\108\121 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")j.contextTypes={name=t.string}function j.render(j)return g.createElement("\084\101\120\116",nil,j.context.name)end local d=J()local f=d:render(g.createElement(j),{name="\102\111\111"});(A(f)).toEqual(g.createElement("\084\101\120\116",nil,"\102\111\111"))end)f("\115\104\111\117\108\100 \116\114\097\099\107 \099\111\110\116\101\120\116 \097\099\114\111\115\115 \117\112\100\097\116\101\115",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")j.contextTypes={foo=t.string}function j.init(j)j.state={bar="\098\097\114"}end function j.render(j)return g.createElement("\084\101\120\116",nil,j.context.foo..("\058"..j.state.bar))end local d=J()local f=d:render(g.createElement(j),{foo="\102\111\111"});(A(f.props.children)).toEqual("\102\111\111\058\098\097\114")local T=d:getMountedInstance()T:setState({bar="\098\097\122"})f=d:getRenderOutput();(A(f.props.children)).toEqual("\102\111\111\058\098\097\122")end)f("\115\104\111\117\108\100 \102\105\108\116\101\114 \099\111\110\116\101\120\116 \098\121 \099\111\110\116\101\120\116\084\121\112\101\115",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")j.contextTypes={foo=t.string}function j.render(j)return g.createElement("\084\101\120\116",nil,j.context.foo..("\058"..tostring(j.context.bar)))end local d=J()local f=d:render(g.createElement(j),{foo="\102\111\111",bar="\098\097\114"});(A(f.props.children)).toEqual("\102\111\111\058\110\105\108")end)f.skip("\099\097\110 \102\097\105\108 \099\111\110\116\101\120\116 \119\104\101\110 \115\104\097\108\108\111\119\108\121 \114\101\110\100\101\114\105\110\103",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")j.contextTypes={name=t.string_isRequired}function j.render(j)return g.createElement("\084\101\120\116",nil,j.context.name)end local d=J();(A(function()d:render(g.createElement(j))end)).toThrow("\087\097\114\110\105\110\103\058 \070\097\105\108\101\100 \099\111\110\116\101\120\116 \116\121\112\101\058 \084\104\101 \099\111\110\116\101\120\116 \096\110\097\109\101\096 \105\115 \109\097\114\107\101\100 \097\115 \114\101\113\117\105\114\101\100 \105\110 \096\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116\096\044 \098\117\116 \105\116\115 \118\097\108\117\101 \105\115 \096\117\110\100\101\102\105\110\101\100\096\046\n    \105\110 \083\105\109\112\108\101\067\111\109\112\111\110\101\110\116 \040\097\116 \042\042\041")end)f.skip("\115\104\111\117\108\100 \119\097\114\110 \097\098\111\117\116 \112\114\111\112\084\121\112\101\115 \040\098\117\116 \111\110\108\121 \111\110\099\101\041",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\120\116",nil,j.props.name)end j.propTypes={name=t.string_isRequired}local d=J();(A(function()d:render(g.createElement(j,{name=123}))end)).toThrow()end)f("\115\104\111\117\108\100 \101\110\097\098\108\101 \114\101\110\100\101\114\105\110\103 \111\102 \099\108\111\110\101\100 \101\108\101\109\101\110\116",function()local j=g.Component:extend("\083\105\109\112\108\101\067\111\109\112\111\110\101\110\116")function j.init(d,j)d.state={bar="\098\097\114"}end function j.render(j)return g.createElement("\084\101\120\116",nil,j.props.foo..("\058"..j.state.bar))end local d=J()local f=g.createElement(j,{foo="\102\111\111"})local T=d:render(f);(A(T.props.children)).toEqual("\102\111\111\058\098\097\114")local Z=g.cloneElement(f,{foo="\098\097\122"})T=d:render(Z);(A(T.props.children)).toEqual("\098\097\122\058\098\097\114")end)f("\115\101\108\102\046\115\116\097\116\101 \115\104\111\117\108\100 \098\101 \117\112\100\097\116\101\100 \111\110 \115\101\116\083\116\097\116\101 \099\097\108\108\098\097\099\107 \105\110\115\105\100\101 \099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116",function()local j=false local d=g.Component:extend("\067\111\109\112\111\110\101\110\116")function d.init(A,j,d)A.state={hasUpdatedState=false}end function d.UNSAFE_componentWillMount(d)d:setState({hasUpdatedState=true},function()j=d.state.hasUpdatedState end)end function d.render(j)return g.createElement("\084\101\120\116",nil,j.props.children)end local f=J()f:render(g.createElement(d));(A(j)).toEqual(true)end)f("\115\104\111\117\108\100 \104\097\110\100\108\101 \109\117\108\116\105\112\108\101 \099\097\108\108\098\097\099\107\115",function()local j=0 local d=function()j+=1 end local f=J()local T=g.Component:extend("\067\111\109\112\111\110\101\110\116")function T.init(A,j,d)A.state={foo="\102\111\111"}end function T.UNSAFE_componentWillMount(j)j:setState({foo="\098\097\114"},d)j:setState({foo="\102\111\111\098\097\114"},d)end function T.render(j)return g.createElement("\084\101\120\116",nil,j.state.foo)end f:render(g.createElement(T));(A(j)).toEqual(2)local Z=f:getMountedInstance()Z:setState({foo="\098\097\114"},function()d()end);(A(j)).toEqual(3)end)f("\115\104\111\117\108\100 \099\097\108\108 \116\104\101 \115\101\116\083\116\097\116\101 \099\097\108\108\098\097\099\107 \101\118\101\110 \105\102 \115\104\111\117\108\100\067\111\109\112\111\110\101\110\116\085\112\100\097\116\101 \061 \102\097\108\115\101",function()local j=0 local d=function()j+=1 return false end local f=g.Component:extend("\067\111\109\112\111\110\101\110\116")function f.init(A,j,d)A.state={hasUpdatedState=false}end function f.shouldComponentUpdate(j)return d()end function f.render(j)return g.createElement("\084\101\120\116",nil,j.state.hasUpdatedState)end local T=J()T:render(g.createElement(f))local Z=false local O=T:getMountedInstance()O:setState({hasUpdatedState=true},function()(A(j)).toEqual(1);(A(O.state.hasUpdatedState)).toEqual(true)Z=true end);(A(Z)).toEqual(true)end)f("\116\104\114\111\119\115 \117\115\101\102\117\108\108\121 \119\104\101\110 \114\101\110\100\101\114\105\110\103 \098\097\100\108\121-\116\121\112\101\100 \101\108\101\109\101\110\116\115",function()local j=J()local d=function(d,f)(A(function()(A(function()j:render(g.createElement(d))end)).toErrorDev("\082\101\097\099\116\046\099\114\101\097\116\101\069\108\101\109\101\110\116\058 \116\121\112\101 \105\115 \105\110\118\097\108\105\100 -- \101\120\112\101\099\116\101\100 \097 \115\116\114\105\110\103 "..("\040\102\111\114 \098\117\105\108\116-\105\110 \099\111\109\112\111\110\101\110\116\115\041 \111\114 \097 \099\108\097\115\115\047\102\117\110\099\116\105\111\110 \040\102\111\114 \099\111\109\112\111\115\105\116\101 \099\111\109\112\111\110\101\110\116\115\041 "..("\098\117\116 \103\111\116\058 "..(f.."\046"))))end)).toThrow("\082\101\097\099\116\083\104\097\108\108\111\119\082\101\110\100\101\114\101\114 \114\101\110\100\101\114\040\041\058 \083\104\097\108\108\111\119 \114\101\110\100\101\114\105\110\103 \119\111\114\107\115 \111\110\108\121 \119\105\116\104 \099\117\115\116\111\109 "..("\099\111\109\112\111\110\101\110\116\115\044 \098\117\116 \116\104\101 \112\114\111\118\105\100\101\100 \101\108\101\109\101\110\116 \116\121\112\101 \119\097\115 \096"..(f.."\096\046")))end d(nil,"\110\105\108")d({},"\097\114\114\097\121")end)f("\115\104\111\117\108\100 \104\097\118\101 \105\110\105\116\105\097\108 \115\116\097\116\101 \111\102 \085\110\105\110\105\116\105\097\108\105\122\101\100\083\116\097\116\101 \105\102 \110\111\116 \100\101\102\105\110\101\100",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\120\116")end local d=J()d:render(g.createElement(j));(A((d:getMountedInstance()).state)).toBe(I)end)f("\115\104\111\117\108\100 \105\110\118\111\107\101 \098\111\116\104 \100\101\112\114\101\099\097\116\101\100 \097\110\100 \110\101\119 \108\105\102\101\099\121\099\108\101\115 \105\102 \098\111\116\104 \097\114\101 \112\114\101\115\101\110\116",function()local j={}local d=function(d)return function()table.insert(j,d)return true end end local f=g.Component:extend("\067\111\109\112\111\110\101\110\116")f.componentWillMount=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116")f.componentWillReceiveProps=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115")f.componentWillUpdate=d("\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101")f.UNSAFE_componentWillMount=d("\085\078\083\065\070\069\095\099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116")f.UNSAFE_componentWillReceiveProps=d("\085\078\083\065\070\069\095\099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115")f.UNSAFE_componentWillUpdate=d("\085\078\083\065\070\069\095\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101")function f.render(j)return g.createElement("\084\101\120\116")end local T=J();(A(j)).toEqual({})T:render(g.createElement(f,{foo="\098\097\114"}));(A(j)).toEqual({"\099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116","\085\078\083\065\070\069\095\099\111\109\112\111\110\101\110\116\087\105\108\108\077\111\117\110\116"})Z.splice(j,1)T:render(g.createElement(f,{foo="\098\097\122"}));(A(j)).toEqual({"\099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115";"\085\078\083\065\070\069\095\099\111\109\112\111\110\101\110\116\087\105\108\108\082\101\099\101\105\118\101\080\114\111\112\115";"\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101";"\085\078\083\065\070\069\095\099\111\109\112\111\110\101\110\116\087\105\108\108\085\112\100\097\116\101"})end)f("\115\104\111\117\108\100 \115\116\111\112 \116\104\101 \117\112\100\097\116\101 \119\104\101\110 \115\101\116\083\116\097\116\101 \114\101\116\117\114\110\115 \110\105\108 \111\114 \117\110\100\101\102\105\110\101\100",function()local j={}local d local f=g.Component:extend("\067\111\109\112\111\110\101\110\116")function f.init(d,j)d.state={count=0}end function f.render(A)table.insert(j,"\114\101\110\100\101\114")d=A return nil end local T=J()T:render(g.createElement(f))Z.splice(j,1)d:setState(function()return nil end)d:setState(nil);(A(j)).toEqual({})d:setState(function(j)return{count=j.count+1}end);(A(j)).toEqual({"\114\101\110\100\101\114"})end)f("\115\104\111\117\108\100 \110\111\116 \103\101\116 \116\104\105\115 \105\110 \097 \102\117\110\099\116\105\111\110 \099\111\109\112\111\110\101\110\116",function()local j={}local d=nil local f=function()table.insert(j,d)return g.createElement("\084\101\120\116",nil,"\102\111\111")end local T=J()T:render(g.createElement(f,{foo="\098\097\114"}));(A(j)).toEqual({nil})end)f("\115\104\111\117\108\100 \104\097\110\100\108\101 \109\101\109\111",function()local j=function()return g.createElement("\084\101\120\116")end local d=g.memo(j)local f=J()local T=f:render(g.createElement(d));(A(T)).toEqual(g.createElement("\084\101\120\116"))end)f("\115\104\111\117\108\100 \101\110\097\098\108\101 \082\101\097\099\116\046\109\101\109\111 \116\111 \112\114\101\118\101\110\116 \097 \114\101-\114\101\110\100\101\114",function()local j={}local d=g.memo(function(d)table.insert(j,"\070\111\111\058 "..d.count)return g.createElement("\084\101\120\116",nil,d.count)end)local f=g.memo(function(d)table.insert(j,"\066\097\114\058 "..d.count)return g.createElement("\084\101\120\116",nil,d.count)end)local T=J()T:render(g.createElement(d,{count=1}));(A(j)).toEqual({"\070\111\111\058 \049"})Z.splice(j,1)T:render(g.createElement(d,{count=1}));(A(j)).toEqual({})T:render(g.createElement(f,{count=1}));(A(j)).toEqual({"\066\097\114\058 \049"})end)f("\115\104\111\117\108\100 \114\101\115\112\101\099\116 \097 \099\117\115\116\111\109 \099\111\109\112\097\114\105\115\111\110 \102\117\110\099\116\105\111\110 \119\105\116\104 \082\101\097\099\116\046\109\101\109\111",function()local j=0 local d=function(j,d)return j.foo==d.foo end local f=g.memo(function(d)j+=1 return g.createElement("\084\101\120\116",nil,tostring(d.foo)..tostring(d.bar))end,d)local T=J()T:render(g.createElement(f,{foo=1;bar=1}));(A(j)).toEqual(1)T:render(g.createElement(f,{foo=1;bar=2}));(A(j)).toEqual(1)T:render(g.createElement(f,{foo=2,bar=2}));(A(j)).toEqual(2)end)f("\115\104\111\117\108\100 \110\111\116 \099\097\108\108 \116\104\101 \099\111\109\112\097\114\105\115\111\110 \102\117\110\099\116\105\111\110 \119\105\116\104 \082\101\097\099\116\046\109\101\109\111 \111\110 \116\104\101 \105\110\105\116\105\097\108 \114\101\110\100\101\114",function()local j=false local d=function()j=true return false end local f=g.memo(function(j)return g.createElement("\084\101\120\116",nil,j.foo)end,d)local T=J()T:render(g.createElement(f,{foo=1}));(A(j)).toEqual(false);(A((T:getRenderOutput()).props.children)).toEqual(1)end)f("\115\104\111\117\108\100 \104\097\110\100\108\101 \109\101\109\111\040\102\111\114\119\097\114\100\082\101\102\040\041\041",function()local j=g.createRef()local d=g.forwardRef(function(d,f)(A(f)).toEqual(j)return g.createElement("\070\114\097\109\101",nil,g.createElement("\084\101\120\116",{className="\099\104\105\108\100\049"}),g.createElement("\084\101\120\116",{className="\099\104\105\108\100\050"}))end)local f=g.memo(d)local T=J()local Z=T:render(g.createElement(f,{ref=j}));(A(Z.type)).toEqual("\070\114\097\109\101");(A(Z.props.children)).toEqual(v({g.createElement("\084\101\120\116",{className="\099\104\105\108\100\049"}),g.createElement("\084\101\120\116",{className="\099\104\105\108\100\050"})}))end)f("\115\104\111\117\108\100 \119\097\114\110 \102\111\114 \102\111\114\119\097\114\100\082\101\102\040\109\101\109\111\040\041\041",function()local j=g.createRef()local d=g.memo(function(j)return g.createElement("\084\101\120\116",nil,j.foo)end)local f=J();(A(function()(A(function()local A=g.forwardRef(d)f:render(g.createElement(A,{ref=j}))end)).toErrorDev("\087\097\114\110\105\110\103\058 \102\111\114\119\097\114\100\082\101\102 \114\101\113\117\105\114\101\115 \097 \114\101\110\100\101\114 \102\117\110\099\116\105\111\110 \098\117\116 \114\101\099\101\105\118\101\100 \097 \096\109\101\109\111\096 \099\111\109\112\111\110\101\110\116\046 \073\110\115\116\101\097\100 \111\102 \102\111\114\119\097\114\100\082\101\102\040\109\101\109\111\040\046\046\046\041\041\044 \117\115\101 \109\101\109\111\040\102\111\114\119\097\114\100\082\101\102\040\046\046\046\041\041",{withoutStack=true})end)).toThrow("\102\111\114\119\097\114\100\082\101\102 \114\101\113\117\105\114\101\115 \097 \114\101\110\100\101\114 \102\117\110\099\116\105\111\110 \098\117\116 \119\097\115 \103\105\118\101\110 \116\097\098\108\101\046")end)f("\115\104\111\117\108\100 \108\101\116 \121\111\117 \099\104\097\110\103\101 \116\121\112\101",function()local j=function(j)return g.createElement("\084\101\120\116",nil,"\070\111\111 "..j.prop)end local d=function(j)return g.createElement("\084\101\120\116",nil,"\066\097\114 "..j.prop)end local f=J()f:render(g.createElement(j,{prop="\102\111\111\049"}));(A((f:getRenderOutput()).props.children)).toEqual("\070\111\111 \102\111\111\049")f:render(g.createElement(j,{prop="\102\111\111\050"}));(A((f:getRenderOutput()).props.children)).toEqual("\070\111\111 \102\111\111\050")f:render(g.createElement(d,{prop="\098\097\114\049"}));(A((f:getRenderOutput()).props.children)).toEqual("\066\097\114 \098\097\114\049")f:render(g.createElement(d,{prop="\098\097\114\050"}));(A((f:getRenderOutput()).props.children)).toEqual("\066\097\114 \098\097\114\050")end)f("\115\104\111\117\108\100 \108\111\099\097\108 \121\111\117 \099\104\097\110\103\101 \099\108\097\115\115 \116\121\112\101",function()local j=g.Component:extend("\067\111\109\112\111\110\101\110\116")function j.render(j)return g.createElement("\084\101\120\116",nil,"\070\111\111 "..j.props.prop)end local d=g.Component:extend("\067\111\109\112\111\110\101\110\116")function d.render(j)return g.createElement("\084\101\120\116",nil,"\066\097\114 "..j.props.prop)end local f=J()f:render(g.createElement(j,{prop="\102\111\111\049"}));(A((f:getRenderOutput()).props.children)).toEqual("\070\111\111 \102\111\111\049")f:render(g.createElement(j,{prop="\102\111\111\050"}));(A((f:getRenderOutput()).props.children)).toEqual("\070\111\111 \102\111\111\050")f:render(g.createElement(d,{prop="\098\097\114\049"}));(A((f:getRenderOutput()).props.children)).toEqual("\066\097\114 \098\097\114\049")f:render(g.createElement(d,{prop="\098\097\114\050"}));(A((f:getRenderOutput()).props.children)).toEqual("\066\097\114 \098\097\114\050")end)
--[[*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @emails react-core
 * @jest-environment node
]]

-- local Dependencies = script.Parent.Parent.Parent.Parent.Packages
local JestGlobals = require("@pkg/@jsdotlua/jest-globals")
local beforeEach = JestGlobals.beforeEach
local jestExpect = JestGlobals.expect
local it = JestGlobals.it
local LuauPolyfill = require("@pkg/@jsdotlua/luau-polyfill")
local Array = LuauPolyfill.Array
local Error = LuauPolyfill.Error
local UninitializedState
-- local PropTypes = require("./Packages/PropTypes")
local React
local ReactShallowRenderer
local createRenderer

beforeEach(function()
	UninitializedState = require("@pkg/@jsdotlua/shared").UninitializedState
	React = require("@pkg/@jsdotlua/react")
	ReactShallowRenderer = require("..")
	createRenderer = ReactShallowRenderer.createRenderer
end)

local function validateElement(element)
	if _G.__DEV__ then
		element._store.validated = true
	end
	return element
end

local function validate(list)
	if _G.__DEV__ then
		for _, element in list do
			validateElement(element)
		end
	end
	return list
end

-- ROBLOX deviation START: inline simplified PropTypes logic
local function propTypes(value, expectedType, isRequired)
	if not isRequired and value == nil then
		return nil
	end
	if type(value) ~= expectedType then
		return Error("expected " .. expectedType)
	end
	return nil
end
local PropTypes = {
	string = function(props, typeSpecName)
		return propTypes(props[typeSpecName], "string")
	end,
	string_isRequired = function(props, typeSpecName)
		return propTypes(props[typeSpecName], "string", true)
	end,
}
-- ROBLOX deviation END

it("should call all of the legacy lifecycle hooks", function()
	local logs = {}
	local logger = function(message)
		return function()
			table.insert(logs, message)
			return true
		end
	end

	local SomeComponent = React.Component:extend("SomeComponent")
	SomeComponent.UNSAFE_componentWillMount = logger("componentWillMount")
	SomeComponent.componentDidMount = logger("componentDidMount")
	SomeComponent.UNSAFE_componentWillReceiveProps = logger("componentWillReceiveProps")
	SomeComponent.shouldComponentUpdate = logger("shouldComponentUpdate")
	SomeComponent.UNSAFE_componentWillUpdate = logger("componentWillUpdate")
	SomeComponent.componentDidUpdate = logger("componentDidUpdate")
	SomeComponent.componentWillUnmount = logger("componentWillUnmount")
	function SomeComponent:render()
		return React.createElement("Frame")
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SomeComponent, {
		foo = 1,
	}))

	-- Calling cDU might lead to problems with host component references.
	-- Since our components aren't really mounted, refs won't be available.
	jestExpect(logs).toEqual({ "componentWillMount" })

	Array.splice(logs, 1)

	local instance = shallowRenderer:getMountedInstance()
	instance:setState({})

	jestExpect(logs).toEqual({ "shouldComponentUpdate", "componentWillUpdate" })

	Array.splice(logs, 1)

	shallowRenderer:render(React.createElement(SomeComponent, {
		foo = 2,
	}))

	-- The previous shallow renderer did not trigger cDU for props changes.
	jestExpect(logs).toEqual({
		"componentWillReceiveProps",
		"shouldComponentUpdate",
		"componentWillUpdate",
	})
end)

it("should call all of the new lifecycle hooks", function()
	local logs = {}
	local logger = function(message)
		return function()
			table.insert(logs, message)
			return true
		end
	end

	local SomeComponent = React.Component:extend("SomeComponent")
	SomeComponent.getDerivedStateFromProps = logger("getDerivedStateFromProps")
	SomeComponent.componentDidMount = logger("componentDidMount")
	SomeComponent.shouldComponentUpdate = logger("shouldComponentUpdate")
	SomeComponent.componentDidUpdate = logger("componentDidUpdate")
	SomeComponent.componentWillUnmount = logger("componentWillUnmount")
	function SomeComponent:init()
		self.state = {}
	end
	function SomeComponent:render()
		return React.createElement("Frame")
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SomeComponent, {
		foo = 1,
	}))

	-- Calling cDU might lead to problems with host component references.
	-- Since our components aren't really mounted, refs won't be available.
	jestExpect(logs).toEqual({ "getDerivedStateFromProps" })

	Array.splice(logs, 1)

	local instance = shallowRenderer:getMountedInstance()
	instance:setState({})

	jestExpect(logs).toEqual({ "getDerivedStateFromProps", "shouldComponentUpdate" })

	Array.splice(logs, 1)

	shallowRenderer:render(React.createElement(SomeComponent, {
		foo = 2,
	}))

	-- The previous shallow renderer did not trigger cDU for props changes.
	jestExpect(logs).toEqual({ "getDerivedStateFromProps", "shouldComponentUpdate" })
end)

it(
	"should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present",
	function()
		local Component = React.Component:extend("Component")
		function Component:init()
			self.state = {}
		end
		function Component.getDerivedStateFromProps()
			return nil
		end
		function Component:componentWillMount()
			error(Error("unexpected"))
		end
		function Component:componentWillReceiveProps()
			error(Error("unexpected"))
		end
		function Component:componentWillUpdate()
			error(Error("unexpected"))
		end
		function Component:render()
			return nil
		end

		local shallowRenderer = createRenderer()
		jestExpect(function()
			shallowRenderer:render(React.createElement(Component))
		end).never.toThrow()
	end
)

it(
	"should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present",
	function()
		local Component = React.Component:extend("Component")
		function Component:getSnapshotBeforeUpdate()
			return nil
		end
		function Component:componentWillMount()
			error(Error("unexpected"))
		end
		function Component:componentWillReceiveProps()
			error(Error("unexpected"))
		end
		function Component:componentWillUpdate()
			error(Error("unexpected"))
		end
		function Component:render()
			return nil
		end

		local shallowRenderer = createRenderer()
		jestExpect(function()
			shallowRenderer:render(React.createElement(Component, { value = 1 }))
		end).never.toThrow()
		jestExpect(function()
			shallowRenderer:render(React.createElement(Component, { value = 2 }))
		end).never.toThrow()
	end
)

it(
	"should not call getSnapshotBeforeUpdate or componentDidUpdate when updating since refs wont exist",
	function()
		local Component = React.Component:extend("Component")
		function Component:getSnapshotBeforeUpdate()
			error(Error("unexpected"))
		end
		function Component:componentDidUpdate()
			error(Error("unexpected"))
		end
		function Component:render()
			return nil
		end

		local shallowRenderer = createRenderer()
		jestExpect(function()
			shallowRenderer:render(React.createElement(Component, { value = 1 }))
		end).never.toThrow()
		jestExpect(function()
			shallowRenderer:render(React.createElement(Component, { value = 2 }))
		end).never.toThrow()
	end
)

it("should only render 1 level deep", function()
	local function Child()
		error(Error("This component should not render"))
	end

	local function Parent()
		return React.createElement("Frame", nil, {
			Child = React.createElement(Child),
		})
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Parent))
end)

it("should have shallow rendering", function()
	local SomeComponent = React.Component:extend("Component")
	function SomeComponent:render()
		return React.createElement(
			"Frame",
			nil,
			React.createElement("TextLabel", { Text = "child1" }),
			React.createElement("TextLabel", { Text = "child2" })
		)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SomeComponent))

	jestExpect(result.type).toEqual("Frame")
	jestExpect(result.props.children).toEqual(validate({
		React.createElement("TextLabel", { Text = "child1" }),
		React.createElement("TextLabel", { Text = "child2" }),
	}))
end)

it("should handle ForwardRef", function()
	local testRef = React.createRef()
	local SomeComponent = React.forwardRef(function(props, ref)
		jestExpect(ref).toEqual(testRef)
		return React.createElement(
			"Frame",
			nil,
			React.createElement("TextLabel", { Text = "child1" }),
			React.createElement("TextLabel", { Text = "child2" })
		)
	end)

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SomeComponent, {
		ref = testRef,
	}))

	jestExpect(result.type).toEqual("Frame")
	jestExpect(result.props.children).toEqual(validate({
		React.createElement("TextLabel", { Text = "child1" }),
		React.createElement("TextLabel", { Text = "child2" }),
	}))
end)

it("should handle Profiler", function()
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:render()
		return React.createElement(
			React.Profiler,
			{ id = "test", onRender = function() end },
			React.createElement(
				"Text",
				nil,
				React.createElement("Frame", { className = "child1" }),
				React.createElement("Frame", { className = "child2" })
			)
		)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SomeComponent))

	jestExpect(result.type).toEqual(React.Profiler)
	jestExpect(result.props.children).toEqual(
		validateElement(
			React.createElement(
				"Text",
				nil,
				React.createElement("Frame", { className = "child1" }),
				React.createElement("Frame", { className = "child2" })
			)
		)
	)
end)

it("should enable shouldComponentUpdate to prevent a re-render", function()
	local renderCounter = 0
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { update = false }
	end
	function SimpleComponent:shouldComponentUpdate(nextProps, nextState)
		return self.state.update ~= nextState.update
	end
	function SimpleComponent:render()
		renderCounter += 1
		return React.createElement("TextLabel", { Text = renderCounter })
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	local instance = shallowRenderer:getMountedInstance()
	instance:setState({ update = false })
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	instance:setState({ update = true })
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 2 })
	)
end)

it("should enable PureComponent to prevent a re-render", function()
	local renderCounter = 0
	local SimpleComponent = React.PureComponent:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { update = false }
	end
	function SimpleComponent:render()
		renderCounter += 1
		return React.createElement("TextLabel", { Text = renderCounter })
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	local instance = shallowRenderer:getMountedInstance()
	instance:setState({ update = false })
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	instance:setState({ update = true })
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 2 })
	)
end)

it("should not run shouldComponentUpdate during forced update", function()
	local scuCounter = 0
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { count = 1 }
	end
	function SimpleComponent:shouldComponentUpdate()
		scuCounter += 1
		return false
	end
	function SimpleComponent:render()
		return React.createElement("TextLabel", { Text = self.state.count })
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(scuCounter).toEqual(0)
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	-- Force update the initial state. sCU should not fire.
	local instance = shallowRenderer:getMountedInstance()
	instance:forceUpdate()
	jestExpect(scuCounter).toEqual(0)
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	-- Setting state updates the instance, but doesn't re-render
	-- because sCU returned false.
	instance:setState(function(state)
		return { count = state.count + 1 }
	end)
	jestExpect(scuCounter).toEqual(1)
	jestExpect(instance.state.count).toEqual(2)
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 1 })
	)

	-- A force update updates the render output, but doesn't call sCU.
	instance:forceUpdate()
	jestExpect(scuCounter).toEqual(1)
	jestExpect(instance.state.count).toEqual(2)
	jestExpect(shallowRenderer:getRenderOutput()).toEqual(
		React.createElement("TextLabel", { Text = 2 })
	)
end)

it("should rerender when calling forceUpdate", function()
	local renderCounter = 0
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:render()
		renderCounter += 1
		return React.createElement("TextLabel")
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(renderCounter).toEqual(1)

	local instance = shallowRenderer:getMountedInstance()
	instance:forceUpdate()
	jestExpect(renderCounter).toEqual(2)
end)

it("should shallow render a function component", function()
	local SomeComponent = function(props, context)
		return (
			React.createElement("Frame", nil, {
				ChildFoo = React.createElement("TextLabel", { Text = props.foo }),
				ChildBar = React.createElement("TextLabel", { Text = context.bar }),
				Child1 = React.createElement("Frame", { Value = "child1" }),
				Child2 = React.createElement("Frame", { Value = "child2" }),
			})
		)
	end
	-- ROBLOX deviation: we don't support contextTypes on function components
	--     SomeComponent.contextTypes = {
	--       bar = PropTypes.string
	--     }

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(
		React.createElement(SomeComponent, { foo = "FOO" }),
		{ bar = "BAR" }
	)

	jestExpect(result.type).toEqual("Frame")
	jestExpect(result.props.children).toEqual(validate({
		ChildFoo = React.createElement("TextLabel", { Text = "FOO" }),
		ChildBar = React.createElement("TextLabel", { Text = "BAR" }),
		Child1 = React.createElement("Frame", { Value = "child1" }),
		Child2 = React.createElement("Frame", { Value = "child2" }),
	}))
end)

it("should shallow render a component returning strings directly from render", function()
	local Text = function(props)
		return props.value
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(Text, { value = "foo" }))
	jestExpect(result).toEqual("foo")
end)

it("should shallow render a component returning numbers directly from render", function()
	local Text = function(props)
		return props.value
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(Text, { value = 10 }))
	jestExpect(result).toEqual(10)
end)

it("should shallow render a fragment", function()
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:render()
		return React.createElement("TextLabel")
	end

	local Fragment = React.Component:extend("Fragment")
	function Fragment:render()
		return {
			ChildA = React.createElement("TextLabel", { Text = "a" }),
			ChildB = React.createElement("Frame", { Value = "b" }),
			ChildC = React.createElement(SomeComponent),
		}
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(Fragment))
	jestExpect(result.ChildA).toEqual(React.createElement("TextLabel", { Text = "a" }))
	jestExpect(result.ChildB).toEqual(React.createElement("Frame", { Value = "b" }))
	jestExpect(result.ChildC).toEqual(React.createElement(SomeComponent))
	jestExpect(result).toEqual({
		ChildC = React.createElement(SomeComponent),
		ChildA = React.createElement("TextLabel", { Text = "a" }),
		ChildB = React.createElement("Frame", { Value = "b" }),
	})
end)

it("should shallow render a React.Fragment", function()
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:render()
		return React.createElement("TextLabel")
	end

	local Fragment = React.Component:extend("Fragment")
	function Fragment:render()
		return React.createElement(
			React.Fragment,
			nil,
			React.createElement("Text"),
			React.createElement("Frame"),
			React.createElement(SomeComponent)
		)
	end
	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(Fragment))
	jestExpect(result.type).toEqual(React.Fragment)

	jestExpect(#result.props.children).toEqual(3)
	jestExpect(result.props.children[1]).toEqual(
		validateElement(React.createElement("Text"))
	)
	jestExpect(result.props.children[2]).toEqual(
		validateElement(React.createElement("Frame"))
	)
	React.createElement(
		React.Fragment,
		nil,
		React.createElement("Text"),
		React.createElement("Frame"),
		React.createElement(SomeComponent)
	)
end)

it("should throw for invalid elements", function()
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:render()
		return React.createElement("TextLabel")
	end

	local shallowRenderer = createRenderer()
	jestExpect(function()
		shallowRenderer:render(SomeComponent)
	end).toThrow(
		"ReactShallowRenderer render(): Invalid component element. Instead of "
			.. "passing a component class, make sure to instantiate it by passing it "
			.. "to React.createElement."
	)
	jestExpect(function()
		shallowRenderer:render(React.createElement("div"))
	end).toThrow(
		"ReactShallowRenderer render(): Shallow rendering works only with "
			.. "custom components, not primitives (div). Instead of calling "
			.. "`.render(el)` and inspecting the rendered output, look at `el.props` "
			.. "directly instead."
	)
end)

it("should have shallow unmounting", function()
	local willUnmountWasCalled = false
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:componentWillUnmount()
		willUnmountWasCalled = true
	end

	function SomeComponent:render()
		return React.createElement("TextLabel")
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SomeComponent))
	shallowRenderer:unmount()

	jestExpect(willUnmountWasCalled).toEqual(true)
end)

it("can shallow render to nil", function()
	local SomeComponent = React.Component:extend("Component")
	function SomeComponent:render()
		return nil
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SomeComponent))

	jestExpect(result).toEqual(nil)
end)

it("can shallow render with a ref", function()
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:render()
		return React.createElement("TestLabel", { ref = "hello" })
	end

	local shallowRenderer = createRenderer()
	-- Shouldn't crash.
	jestExpect(function()
		shallowRenderer:render(React.createElement(SomeComponent))
	end).never.toThrow()
end)

it("lets you update shallowly rendered components", function()
	local SomeComponent = React.Component:extend("SomeComponent")
	function SomeComponent:init()
		self.state = { clicked = false }
	end

	function SomeComponent:onClick()
		self:setState({ clicked = true })
	end

	function SomeComponent:render()
		local className
		if self.state.clicked then
			className = "was-clicked"
		else
			className = ""
		end

		if self.props.aNew == "prop" then
			return React.createElement("Button", {
				onClick = function()
					self:onClick()
				end,
				className = className,
			})
		else
			return React.createElement(
				"TextLabel",
				nil,
				React.createElement("Frame", { className = "child1" }),
				React.createElement("Frame", { className = "child2" })
			)
		end
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SomeComponent))
	jestExpect(result.type).toEqual("TextLabel")
	jestExpect(result.props.children).toEqual(validate({
		React.createElement("Frame", { className = "child1" }),
		React.createElement("Frame", { className = "child2" }),
	}))

	local updatedResult =
		shallowRenderer:render(React.createElement(SomeComponent, { aNew = "prop" }))
	jestExpect(updatedResult.type).toEqual("Button")

	updatedResult.props:onClick()

	local updatedResultCausedByClick = shallowRenderer:getRenderOutput()
	jestExpect(updatedResultCausedByClick.type).toEqual("Button")
	jestExpect(updatedResultCausedByClick.props.className).toEqual("was-clicked")
end)

it("can access the mounted component instance", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:someMethod()
		return self.props.n
	end

	function SimpleComponent:render()
		return React.createElement("TextLabel", { Text = self.props.n })
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent, { n = 5 }))
	jestExpect(shallowRenderer:getMountedInstance():someMethod()).toEqual(5)
end)

it("can shallowly render components with contextTypes", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	SimpleComponent.contextTypes = {
		name = PropTypes.string,
	}

	function SimpleComponent:render()
		return React.createElement("TextLabel")
	end

	local shallowRenderer = createRenderer()
	-- ROBLOX Test Noise: jest setup config makes this hide error
	-- boundary warnings in upstream (scripts/jest/setupTests.js:72)
	local result = shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(result).toEqual(React.createElement("TextLabel"))
end)

it("passes expected params to legacy component lifecycle methods", function()
	local componentDidUpdateParams = {}
	local componentWillReceivePropsParams = {}
	local componentWillUpdateParams = {}
	local setStateParams = {}
	local shouldComponentUpdateParams = {}

	local initialProp = { prop = "init prop" }
	local initialState = { state = "init state" }
	local initialContext = { context = "init context" }
	local updatedState = { state = "updated state" }
	local updatedProp = { prop = "updated prop" }
	local updatedContext = { context = "updated context" }

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init(props, context)
		self.state = initialState
	end

	SimpleComponent.contextTypes = {
		context = PropTypes.string,
	}

	function SimpleComponent:componentDidUpdate(...)
		table.insert(componentDidUpdateParams, { ... })
	end
	function SimpleComponent:UNSAFE_componentWillReceiveProps(...)
		table.insert(componentWillReceivePropsParams, { ... })
		self:setState(function(...)
			table.insert(setStateParams, { ... })
			return updatedState
		end)
	end
	function SimpleComponent:UNSAFE_componentWillUpdate(...)
		table.insert(componentWillUpdateParams, { ... })
	end
	function SimpleComponent:shouldComponentUpdate(...)
		table.insert(shouldComponentUpdateParams, { ... })
		return true
	end
	function SimpleComponent:render()
		return nil
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(
		React.createElement(SimpleComponent, initialProp),
		initialContext
	)
	jestExpect(componentDidUpdateParams).toEqual({})
	jestExpect(componentWillReceivePropsParams).toEqual({})
	jestExpect(componentWillUpdateParams).toEqual({})
	jestExpect(setStateParams).toEqual({})
	jestExpect(shouldComponentUpdateParams).toEqual({})

	-- Lifecycle hooks should be invoked with the correct prev/next params on update.
	-- ROBLOX Test Noise: jest setup config makes this hide error
	-- boundary warnings in upstream (scripts/jest/setupTests.js:72)
	shallowRenderer:render(
		React.createElement(SimpleComponent, updatedProp),
		updatedContext
	)

	jestExpect(componentWillReceivePropsParams).toEqual({
		{ updatedProp, updatedContext },
	})
	jestExpect(setStateParams).toEqual({
		{ initialState, initialProp },
	})
	jestExpect(shouldComponentUpdateParams).toEqual({
		{ updatedProp, updatedState, updatedContext },
	})
	jestExpect(componentWillUpdateParams).toEqual({
		{ updatedProp, updatedState, updatedContext },
	})
	jestExpect(componentDidUpdateParams).toEqual({})
end)

it("passes expected params to new component lifecycle methods", function()
	local componentDidUpdateParams = {}
	local getDerivedStateFromPropsParams = {}
	local shouldComponentUpdateParams = {}

	local initialProp = { prop = "init prop" }
	local initialState = { state = "init state" }
	local initialContext = { context = "init context" }
	local updatedProp = { prop = "updated prop" }
	local updatedContext = { context = "updated context" }

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init(props, context)
		self.state = initialState
	end

	SimpleComponent.contextTypes = {
		context = PropTypes.string,
	}

	function SimpleComponent:componentDidUpdate(...)
		table.insert(componentDidUpdateParams, { ... })
	end

	function SimpleComponent.getDerivedStateFromProps(...)
		table.insert(getDerivedStateFromPropsParams, { ... })
		return nil
	end

	function SimpleComponent:shouldComponentUpdate(...)
		table.insert(shouldComponentUpdateParams, { ... })
		return true
	end

	function SimpleComponent:render()
		return nil
	end

	local shallowRenderer = createRenderer()

	-- The only lifecycle hook that should be invoked on initial render
	-- Is the static getDerivedStateFromProps() methods
	shallowRenderer:render(
		React.createElement(SimpleComponent, initialProp),
		initialContext
	)
	jestExpect(getDerivedStateFromPropsParams).toEqual({
		{
			initialProp,
			initialState,
		},
	})
	jestExpect(componentDidUpdateParams).toEqual({})
	jestExpect(shouldComponentUpdateParams).toEqual({})

	-- Lifecycle hooks should be invoked with the correct prev/next params on update.
	shallowRenderer:render(
		React.createElement(SimpleComponent, updatedProp),
		updatedContext
	)

	jestExpect(getDerivedStateFromPropsParams).toEqual({
		{ initialProp, initialState },
		{ updatedProp, initialState },
	})
	jestExpect(shouldComponentUpdateParams).toEqual({
		{
			updatedProp,
			initialState,
			updatedContext,
		},
	})
	jestExpect(componentDidUpdateParams).toEqual({})
end)

it("can shallowly render components with ref as function", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { clicked = false }
	end

	function SimpleComponent:handleUserClick()
		self:setState({ clicked = true })
	end

	function SimpleComponent:render()
		local wasClicked
		if self.state.clicked then
			wasClicked = "clicked"
		else
			wasClicked = ""
		end

		return React.createElement(SimpleComponent, {
			ref = function() end,
			onClick = function()
				self:handleUserClick()
			end,
			className = wasClicked,
		})
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent))
	local result = shallowRenderer:getRenderOutput()
	-- jestExpect(result.type).toEqual('div')
	jestExpect(result.props.className).toEqual("")
	result.props.onClick()

	result = shallowRenderer:getRenderOutput()
	-- jestExpect(result.type).toEqual('div')
	jestExpect(result.props.className).toEqual("clicked")
end)

it("can initialize state via static getDerivedStateFromProps", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = {
			count = 1,
		}
	end

	function SimpleComponent.getDerivedStateFromProps(props, prevState)
		return {
			count = prevState.count + props.incrementBy,
			other = "foobar",
		}
	end

	function SimpleComponent:render()
		return React.createElement(
			"TextLabel",
			nil,
			"count:" .. self.state.count .. ", other:" .. self.state.other
		)
	end

	local shallowRenderer = createRenderer()
	local result =
		shallowRenderer:render(React.createElement(SimpleComponent, { incrementBy = 2 }))
	jestExpect(result).toEqual(
		React.createElement("TextLabel", nil, "count:3, other:foobar")
	)
end)

it("can setState in componentWillMount when shallow rendering", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:UNSAFE_componentWillMount()
		self:setState({ groovy = "doovy" })
	end

	function SimpleComponent:render()
		return React.createElement("TextLabel", { Text = self.state.groovy })
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(result).toEqual(React.createElement("TextLabel", { Text = "doovy" }))
end)

it("can setState in componentWillMount repeatedly when shallow rendering", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { separator = "-" }
	end

	function SimpleComponent:UNSAFE_componentWillMount()
		self:setState({ groovy = "doovy" })
		self:setState({ doovy = "groovy" })
	end

	function SimpleComponent:render()
		local groovy = self.state.groovy
		local doovy = self.state.doovy
		local separator = self.state.separator

		return React.createElement("TextLabel", { Text = groovy .. separator .. doovy })
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(result).toEqual(
		React.createElement("TextLabel", { Text = "doovy-groovy" })
	)
end)

it(
	"can setState in componentWillMount with an updater function repeatedly when shallow rendering",
	function()
		local SimpleComponent = React.Component:extend("SimpleComponent")
		function SimpleComponent:init()
			self.state = { separator = "-" }
		end

		function SimpleComponent:UNSAFE_componentWillMount()
			self:setState(function(state)
				return { groovy = "doovy" }
			end)
			self:setState(function(state)
				return { doovy = state.groovy }
			end)
		end

		function SimpleComponent:render()
			local groovy = self.state.groovy
			local doovy = self.state.doovy
			local separator = self.state.separator

			return React.createElement("TextLabel", nil, { groovy .. separator .. doovy })
		end

		local shallowRenderer = createRenderer()
		local result = shallowRenderer:render(React.createElement(SimpleComponent))
		jestExpect(result.props.children[1]).toEqual("doovy-doovy")
	end
)

it("can setState in componentWillReceiveProps when shallow rendering", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { count = 0 }
	end

	function SimpleComponent:UNSAFE_componentWillReceiveProps(nextProps)
		if nextProps.updateState then
			self:setState({ count = 1 })
		end
	end

	function SimpleComponent:render()
		return React.createElement("TextLabel", nil, self.state.count)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(
		React.createElement(SimpleComponent, { updateState = false })
	)

	jestExpect(result.props.children).toEqual(0)

	result = shallowRenderer:render(
		React.createElement(SimpleComponent, { updateState = true })
	)

	jestExpect(result.props.children).toEqual(1)
end)

it(
	"can update state with static getDerivedStateFromProps when shallow rendering",
	function()
		local SimpleComponent = React.Component:extend("SimpleComponent")
		function SimpleComponent:init()
			self.state = { count = 1 }
		end

		function SimpleComponent.getDerivedStateFromProps(nextProps, prevState)
			if nextProps.updateState then
				return { count = nextProps.incrementBy + prevState.count }
			end

			return nil
		end

		function SimpleComponent:render()
			return React.createElement("TextLabel", nil, self.state.count)
		end

		local shallowRenderer = createRenderer()
		local result = shallowRenderer:render(
			React.createElement(SimpleComponent, { updateState = false, incrementBy = 0 })
		)

		jestExpect(result.props.children).toEqual(1)

		result = shallowRenderer:render(
			React.createElement(SimpleComponent, { updateState = true, incrementBy = 2 })
		)
		jestExpect(result.props.children).toEqual(3)

		result = shallowRenderer:render(
			React.createElement(SimpleComponent, { updateState = false, incrementBy = 2 })
		)

		jestExpect(result.props.children).toEqual(3)
	end
)

it(
	"should not override state with stale values if prevState is spread within getDerivedStateFromProps",
	function()
		local SimpleComponent = React.Component:extend("SimpleComponent")
		function SimpleComponent:init()
			self.state = { value = 0 }
		end

		function SimpleComponent.getDerivedStateFromProps(nextProps, prevState)
			return { table.unpack(prevState) }
		end

		function SimpleComponent:updateState()
			self:setState(function(state)
				return { value = state.value + 1 }
			end)
		end

		function SimpleComponent:render()
			return React.createElement("TextLabel", nil, "value:" .. self.state.value)
		end

		local shallowRenderer = createRenderer()
		local result = shallowRenderer:render(React.createElement(SimpleComponent))
		jestExpect(result).toEqual(React.createElement("TextLabel", nil, "value:0"))

		local instance = shallowRenderer:getMountedInstance()
		instance:updateState()
		result = shallowRenderer:getRenderOutput()
		jestExpect(result).toEqual(React.createElement("TextLabel", nil, "value:1"))
	end
)

it(
	"should pass previous state to shouldComponentUpdate even with getDerivedStateFromProps",
	function()
		local SimpleComponent = React.Component:extend("SimpleComponent")
		function SimpleComponent:init()
			self.state = {
				value = self.props.value,
			}
		end

		function SimpleComponent.getDerivedStateFromProps(nextProps, prevState)
			if nextProps.value == prevState.value then
				return nil
			end

			return { value = nextProps.value }
		end

		function SimpleComponent:shouldComponentUpdate(nextProps, nextState)
			return nextState.value ~= self.state.value
		end

		function SimpleComponent:render()
			return React.createElement(
				"TextLabel",
				{ Text = "value:" .. self.state.value }
			)
		end

		local shallowRenderer = createRenderer()
		local initialResult = shallowRenderer:render(
			React.createElement(SimpleComponent, { value = "initial" })
		)
		jestExpect(initialResult).toEqual(
			React.createElement("TextLabel", { Text = "value:initial" })
		)
		local updatedResult = shallowRenderer:render(
			React.createElement(SimpleComponent, { value = "updated" })
		)
		jestExpect(updatedResult).toEqual(
			React.createElement("TextLabel", { Text = "value:updated" })
		)
	end
)

it("can setState with an updater function", function()
	local instance

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = {
			counter = 0,
		}
	end

	function SimpleComponent:render()
		instance = self
		return (React.createElement("Button", nil, self.state.counter))
	end

	local shallowRenderer = createRenderer()
	local result =
		shallowRenderer:render(React.createElement(SimpleComponent, { defaultCount = 1 }))
	jestExpect(result.props.children).toEqual(0)

	instance:setState(function(state, props)
		return { counter = instance.props.defaultCount + 1 }
	end)

	result = shallowRenderer:getRenderOutput()
	jestExpect(result.props.children).toEqual(2)
end)

-- ROBLOX deviation: Lua doesn't have a good way to bind to the correct closure for this pattern
-- it's okay, since it doesn't work in leacy Roact and should be okay with the useState() hook
it.skip("can access component instance from setState updater function", function()
	local instance

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = { something = "here" }
	end
	function SimpleComponent:render()
		instance = self
		return nil
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SimpleComponent, { myProp = 31337 }))

	local updaterWasCalled = false
	instance:setState(function(state, props)
		-- ROBLOX deviation: we deviate here. legacy Roact doesn't support this, and is moot with useState() hook
		-- jestExpect(self).toEqual(instance)
		jestExpect(state).toEqual({ something = "here" })
		jestExpect(props).toEqual({ myProp = 31337 })
		updaterWasCalled = true
	end)
	jestExpect(updaterWasCalled).toEqual(true)
end)

it("can setState with a callback", function()
	local instance

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = {
			counter = 0,
		}
	end
	function SimpleComponent:render()
		instance = self
		return React.createElement("Text", nil, self.state.counter)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(result.props.children).toEqual(0)

	local callbackHasBeenCalled = false
	local callback = function(self)
		callbackHasBeenCalled = true
		jestExpect(self).toEqual(instance)
	end

	instance:setState({ counter = 1 }, callback)

	local updated = shallowRenderer:getRenderOutput()
	jestExpect(updated.props.children).toEqual(1)
	jestExpect(callbackHasBeenCalled).toEqual(true)
end)

it("can replaceState with a callback", function()
	local instance

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = {
			counter = 0,
		}
	end
	function SimpleComponent:render()
		instance = self
		return React.createElement("Text", nil, self.state.counter)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(result.props.children).toEqual(0)

	local callbackHasBeenCalled = false
	local callback = function(self)
		callbackHasBeenCalled = true
		jestExpect(self).toEqual(instance)
	end

	-- No longer a public API, but we can test that it works internally by
	-- reaching into the updater.
	shallowRenderer._updater.enqueueReplaceState(instance, { counter = 1 }, callback)

	local updated = shallowRenderer:getRenderOutput()
	jestExpect(updated.props.children).toEqual(1)
	jestExpect(callbackHasBeenCalled).toEqual(true)
end)

it("can forceUpdate with a callback", function()
	local instance

	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init()
		self.state = {
			counter = 0,
		}
	end
	function SimpleComponent:render()
		instance = self
		return React.createElement("Text", nil, self.state.counter)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent))
	jestExpect(result.props.children).toEqual(0)

	local callbackHasBeenCalled = false
	local callback = function(self)
		callbackHasBeenCalled = true
		jestExpect(self).toEqual(instance)
	end

	instance:forceUpdate(callback)

	local updated = shallowRenderer:getRenderOutput()
	jestExpect(updated.props.children).toEqual(0)
	jestExpect(callbackHasBeenCalled).toEqual(true)
end)

it("can pass context when shallowly rendering", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	SimpleComponent.contextTypes = {
		name = PropTypes.string,
	}

	function SimpleComponent:render()
		return React.createElement("Text", nil, self.context.name)
	end

	local shallowRenderer = createRenderer()
	-- ROBLOX Test Noise: jest setup config makes this hide error
	-- boundary warnings in upstream (scripts/jest/setupTests.js:72)
	local result = shallowRenderer:render(React.createElement(SimpleComponent), {
		name = "foo",
	})
	jestExpect(result).toEqual(React.createElement("Text", nil, "foo"))
end)

it("should track context across updates", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	SimpleComponent.contextTypes = {
		foo = PropTypes.string,
	}

	function SimpleComponent:init()
		self.state = {
			bar = "bar",
		}
	end

	function SimpleComponent:render()
		return React.createElement("Text", nil, self.context.foo .. ":" .. self.state.bar)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent), {
		foo = "foo",
	})
	jestExpect(result.props.children).toEqual("foo:bar")

	local instance = shallowRenderer:getMountedInstance()
	instance:setState({ bar = "baz" })

	result = shallowRenderer:getRenderOutput()
	jestExpect(result.props.children).toEqual("foo:baz")
end)

it("should filter context by contextTypes", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	SimpleComponent.contextTypes = {
		foo = PropTypes.string,
	}
	function SimpleComponent:render()
		return React.createElement(
			"Text",
			nil,
			self.context.foo .. ":" .. tostring(self.context.bar)
		)
	end

	local shallowRenderer = createRenderer()
	local result = shallowRenderer:render(React.createElement(SimpleComponent), {
		foo = "foo",
		bar = "bar",
	})
	jestExpect(result.props.children).toEqual("foo:nil")
end)

-- ROBLOX TODO: we'll need prop-types ported for this to pass
it.skip("can fail context when shallowly rendering", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	SimpleComponent.contextTypes = {
		-- ROBLOX deviation: using simplified inline PropTypes
		name = PropTypes.string_isRequired,
	}

	function SimpleComponent:render()
		return React.createElement("Text", nil, self.context.name)
	end

	local shallowRenderer = createRenderer()
	jestExpect(function()
		shallowRenderer:render(React.createElement(SimpleComponent))
	end).toThrow(
		"Warning: Failed context type: The context `name` is marked as "
			.. "required in `SimpleComponent`, but its value is `undefined`.\n"
			.. "    in SimpleComponent (at **)"
	)
end)

-- ROBLOX TODO: we'll need prop-types ported for this to pass
it.skip("should warn about propTypes (but only once)", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:render()
		return React.createElement("Text", nil, self.props.name)
	end

	SimpleComponent.propTypes = {
		-- ROBLOX deviation: using simplified inline PropTypes
		name = PropTypes.string_isRequired,
	}

	local shallowRenderer = createRenderer()
	jestExpect(function()
		shallowRenderer:render(React.createElement(SimpleComponent, { name = 123 }))
	end).toThrow()
	-- ROBLOX TODO: port toErrorDev to jest-roblox matchers
	-- ).toErrorDev(
	--   'Warning: Failed prop type: Invalid prop `name` of type `number` ' +
	--     'supplied to `SimpleComponent`, expected `string`.\n' +
	--     '    in SimpleComponent',
	-- )
end)

it("should enable rendering of cloned element", function()
	local SimpleComponent = React.Component:extend("SimpleComponent")
	function SimpleComponent:init(props)
		self.state = {
			bar = "bar",
		}
	end

	function SimpleComponent:render()
		return React.createElement("Text", nil, self.props.foo .. ":" .. self.state.bar)
	end

	local shallowRenderer = createRenderer()
	local el = React.createElement(SimpleComponent, { foo = "foo" })
	local result = shallowRenderer:render(el)
	jestExpect(result.props.children).toEqual("foo:bar")

	local cloned = React.cloneElement(el, { foo = "baz" })
	result = shallowRenderer:render(cloned)
	jestExpect(result.props.children).toEqual("baz:bar")
end)

it(
	"self.state should be updated on setState callback inside componentWillMount",
	function()
		local stateSuccessfullyUpdated = false

		local MyComponent = React.Component:extend("Component")
		function MyComponent:init(props, context)
			self.state = {
				hasUpdatedState = false,
			}
		end

		function MyComponent:UNSAFE_componentWillMount()
			self:setState({ hasUpdatedState = true }, function()
				stateSuccessfullyUpdated = self.state.hasUpdatedState
			end)
		end

		function MyComponent:render()
			return React.createElement("Text", nil, self.props.children)
		end

		local shallowRenderer = createRenderer()
		shallowRenderer:render(React.createElement(MyComponent))
		jestExpect(stateSuccessfullyUpdated).toEqual(true)
	end
)

it("should handle multiple callbacks", function()
	local mockCalledTimes = 0
	local mockFn = function()
		mockCalledTimes += 1
	end
	local shallowRenderer = createRenderer()

	local Component = React.Component:extend("Component")
	function Component:init(props, context)
		self.state = {
			foo = "foo",
		}
	end

	function Component:UNSAFE_componentWillMount()
		self:setState({ foo = "bar" }, mockFn)
		self:setState({ foo = "foobar" }, mockFn)
	end

	function Component:render()
		return React.createElement("Text", nil, self.state.foo)
	end

	shallowRenderer:render(React.createElement(Component))

	jestExpect(mockCalledTimes).toEqual(2)

	-- Ensure the callback queue is cleared after the callbacks are invoked
	local mountedInstance = shallowRenderer:getMountedInstance()
	mountedInstance:setState({ foo = "bar" }, function()
		mockFn()
	end)
	jestExpect(mockCalledTimes).toEqual(3)
end)

it("should call the setState callback even if shouldComponentUpdate = false", function()
	local mockCalledTimes = 0
	local mockFn = function()
		mockCalledTimes += 1
		return false
	end

	local Component = React.Component:extend("Component")
	function Component:init(props, context)
		self.state = {
			hasUpdatedState = false,
		}
	end

	function Component:shouldComponentUpdate()
		return mockFn()
	end

	function Component:render()
		return React.createElement("Text", nil, self.state.hasUpdatedState)
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Component))

	local callbackWasCalled = false
	local mountedInstance = shallowRenderer:getMountedInstance()
	mountedInstance:setState({ hasUpdatedState = true }, function()
		jestExpect(mockCalledTimes).toEqual(1)
		jestExpect(mountedInstance.state.hasUpdatedState).toEqual(true)
		callbackWasCalled = true
	end)
	jestExpect(callbackWasCalled).toEqual(true)
end)

it("throws usefully when rendering badly-typed elements", function()
	local shallowRenderer = createRenderer()

	local renderAndVerifyWarningAndError = function(Component, typeString)
		jestExpect(function()
			jestExpect(function()
				shallowRenderer:render(React.createElement(Component))
			end).toErrorDev(
				"React.createElement: type is invalid -- expected a string "
					.. "(for built-in components) or a class/function (for composite components) "
					.. "but got: "
					.. typeString
					.. "."
			)
		end).toThrow(
			"ReactShallowRenderer render(): Shallow rendering works only with custom "
				.. "components, but the provided element type was `"
				.. typeString
				.. "`."
		)
	end

	-- ROBLOX deviation: no undefined in Lua, only nil
	-- renderAndVerifyWarningAndError(undefined, 'undefined')
	renderAndVerifyWarningAndError(nil, "nil")
	renderAndVerifyWarningAndError({}, "array")
end)

-- ROBLOX DEVIATION: We initialize state to a singleton for compatibility
it("should have initial state of UninitializedState if not defined", function()
	local SomeComponent = React.Component:extend("Component")
	function SomeComponent:render()
		return React.createElement("Text")
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(SomeComponent))

	jestExpect(shallowRenderer:getMountedInstance().state).toBe(UninitializedState)
end)

it("should invoke both deprecated and new lifecycles if both are present", function()
	local logs = {}
	local logger = function(message)
		return function()
			table.insert(logs, message)
			return true
		end
	end

	local Component = React.Component:extend("Component")
	Component.componentWillMount = logger("componentWillMount")

	Component.componentWillReceiveProps = logger("componentWillReceiveProps")
	Component.componentWillUpdate = logger("componentWillUpdate")
	Component.UNSAFE_componentWillMount = logger("UNSAFE_componentWillMount")
	Component.UNSAFE_componentWillReceiveProps =
		logger("UNSAFE_componentWillReceiveProps")
	Component.UNSAFE_componentWillUpdate = logger("UNSAFE_componentWillUpdate")

	function Component:render()
		return React.createElement("Text")
	end

	local shallowRenderer = createRenderer()
	jestExpect(logs).toEqual({})
	shallowRenderer:render(React.createElement(Component, { foo = "bar" }))
	jestExpect(logs).toEqual({ "componentWillMount", "UNSAFE_componentWillMount" })

	Array.splice(logs, 1)

	shallowRenderer:render(React.createElement(Component, { foo = "baz" }))
	jestExpect(logs).toEqual({
		"componentWillReceiveProps",
		"UNSAFE_componentWillReceiveProps",
		"componentWillUpdate",
		"UNSAFE_componentWillUpdate",
	})
end)

it("should stop the update when setState returns nil or undefined", function()
	local logs = {}
	local instance
	local Component = React.Component:extend("Component")
	function Component:init(props)
		self.state = {
			count = 0,
		}
	end
	function Component:render()
		table.insert(logs, "render")
		instance = self
		return nil
	end
	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Component))
	Array.splice(logs, 1)
	instance:setState(function()
		return nil
	end)
	-- ROBLOX deviation: no undefined in Lua, no different than nil
	-- instance:setState(() => undefined)
	instance:setState(nil)
	-- ROBLOX deviation: no undefined in Lua, no different than nil
	-- instance:setState(undefined)
	jestExpect(logs).toEqual({})
	instance:setState(function(state)
		return { count = state.count + 1 }
	end)
	jestExpect(logs).toEqual({ "render" })
end)

it("should not get this in a function component", function()
	local logs = {}
	local self = nil
	local Foo = function()
		table.insert(logs, self)
		return React.createElement("Text", nil, "foo")
	end
	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Foo, { foo = "bar" }))
	jestExpect(logs).toEqual({ nil })
end)

it("should handle memo", function()
	local Foo = function()
		return React.createElement("Text")
	end
	local MemoFoo = React.memo(Foo)
	local shallowRenderer = createRenderer()
	local renderOutput = shallowRenderer:render(React.createElement(MemoFoo))
	jestExpect(renderOutput).toEqual(React.createElement("Text"))
end)

it("should enable React.memo to prevent a re-render", function()
	local logs = {}
	local Foo = React.memo(function(props)
		table.insert(logs, "Foo: " .. props.count)
		return React.createElement("Text", nil, props.count)
	end)
	local Bar = React.memo(function(props)
		table.insert(logs, "Bar: " .. props.count)
		return React.createElement("Text", nil, props.count)
	end)
	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Foo, { count = 1 }))
	jestExpect(logs).toEqual({ "Foo: 1" })
	Array.splice(logs, 1)
	-- Rendering the same element with the same props should be prevented
	shallowRenderer:render(React.createElement(Foo, { count = 1 }))
	jestExpect(logs).toEqual({})
	-- A different element with the same props should cause a re-render
	shallowRenderer:render(React.createElement(Bar, { count = 1 }))
	jestExpect(logs).toEqual({ "Bar: 1" })
end)

it("should respect a custom comparison function with React.memo", function()
	local renderCount = 0
	local areEqual = function(props, nextProps)
		return props.foo == nextProps.foo
	end
	local Foo = React.memo(function(props)
		renderCount += 1
		return React.createElement(
			"Text",
			nil,
			tostring(props.foo) .. tostring(props.bar)
		)
	end, areEqual)

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Foo, { foo = 1, bar = 1 }))
	jestExpect(renderCount).toEqual(1)
	-- Change a prop that the comparison funciton ignores
	shallowRenderer:render(React.createElement(Foo, { foo = 1, bar = 2 }))
	jestExpect(renderCount).toEqual(1)
	shallowRenderer:render(React.createElement(Foo, { foo = 2, bar = 2 }))
	jestExpect(renderCount).toEqual(2)
end)

it(
	"should not call the comparison function with React.memo on the initial render",
	function()
		local comparisonWasCalled = false
		local areEqual = function()
			comparisonWasCalled = true
			return false
		end
		local SomeComponent = React.memo(function(props)
			return React.createElement("Text", nil, props.foo)
		end, areEqual)
		local shallowRenderer = createRenderer()
		shallowRenderer:render(React.createElement(SomeComponent, { foo = 1 }))
		jestExpect(comparisonWasCalled).toEqual(false)
		jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual(1)
	end
)

it("should handle memo(forwardRef())", function()
	local testRef = React.createRef()
	local SomeComponent = React.forwardRef(function(props, ref)
		jestExpect(ref).toEqual(testRef)
		return React.createElement(
			"Frame",
			nil,
			React.createElement("Text", { className = "child1" }),
			React.createElement("Text", { className = "child2" })
		)
	end)

	local SomeMemoComponent = React.memo(SomeComponent)

	local shallowRenderer = createRenderer()
	local result =
		shallowRenderer:render(React.createElement(SomeMemoComponent, { ref = testRef }))

	jestExpect(result.type).toEqual("Frame")
	jestExpect(result.props.children).toEqual(validate({
		React.createElement("Text", { className = "child1" }),
		React.createElement("Text", { className = "child2" }),
	}))
end)

it("should warn for forwardRef(memo())", function()
	local testRef = React.createRef()
	local SomeMemoComponent = React.memo(function(props)
		return React.createElement("Text", nil, props.foo)
	end)
	local shallowRenderer = createRenderer()
	jestExpect(function()
		jestExpect(function()
			local SomeComponent = React.forwardRef(SomeMemoComponent)
			shallowRenderer:render(React.createElement(SomeComponent, { ref = testRef }))
		end).toErrorDev(
			"Warning: forwardRef requires a render function but received "
				.. "a `memo` component. Instead of forwardRef(memo(...)), use "
				.. "memo(forwardRef(...))",
			{ withoutStack = true }
		)
	end).toThrow(
		-- ROBLOX deviaton: we say table instead of object due to typeof
		"forwardRef requires a render function but was given table."
	)
end)

it("should let you change type", function()
	local Foo = function(props)
		return React.createElement("Text", nil, "Foo " .. props.prop)
	end
	local Bar = function(props)
		return React.createElement("Text", nil, "Bar " .. props.prop)
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Foo, { prop = "foo1" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Foo foo1")
	shallowRenderer:render(React.createElement(Foo, { prop = "foo2" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Foo foo2")
	shallowRenderer:render(React.createElement(Bar, { prop = "bar1" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Bar bar1")
	shallowRenderer:render(React.createElement(Bar, { prop = "bar2" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Bar bar2")
end)

it("should local you change class type", function()
	local Foo = React.Component:extend("Component")
	function Foo:render()
		return React.createElement("Text", nil, "Foo " .. self.props.prop)
	end

	local Bar = React.Component:extend("Component")
	function Bar:render()
		return React.createElement("Text", nil, "Bar " .. self.props.prop)
	end

	local shallowRenderer = createRenderer()
	shallowRenderer:render(React.createElement(Foo, { prop = "foo1" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Foo foo1")
	shallowRenderer:render(React.createElement(Foo, { prop = "foo2" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Foo foo2")
	shallowRenderer:render(React.createElement(Bar, { prop = "bar1" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Bar bar1")
	shallowRenderer:render(React.createElement(Bar, { prop = "bar2" }))
	jestExpect(shallowRenderer:getRenderOutput().props.children).toEqual("Bar bar2")
end)
