local j local d local A local f=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 T=f.Array local Z=f.Symbol local function O(j)if not j then return end if T.isArray(j)then for j,d in j do O(d)end return end if j and j.instance then j.instance=nil end if j and(j.props and j.props.children)then j.props.children=nil end if T.isArray(j.rendered)then for j,d in j.rendered do O(d)end elseif typeof(j.rendered)=="\116\097\098\108\101"then O(j.rendered)end end local I=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 g=I.beforeEach local G=I.expect local J=I.describe local S=I.it local v=I.jest J("\082\101\097\099\116\084\101\115\116\082\101\110\100\101\114\101\114",function()g(function()v.resetModules()j=(require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\115\104\097\114\101\100")).ReactFeatureFlags j.replayFailedUnitOfWorkWithInvokeGuardedCallback=false d=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\114\101\097\099\116")A=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\114\101\097\099\116-\116\101\115\116-\114\101\110\100\101\114\101\114")end)S("\114\101\110\100\101\114\115 \097 \115\105\109\112\108\101 \099\111\109\112\111\110\101\110\116",function()local function j()return d.createElement("\097",{role="\108\105\110\107"})end local f=A.create(d.createElement(j));(G(f.toJSON())).toEqual({type="\097",props={role="\108\105\110\107"};children=nil})end)S("\114\101\110\100\101\114\115 \097 \116\111\112-\108\101\118\101\108 \101\109\112\116\121 \099\111\109\112\111\110\101\110\116",function()local function j()return nil end local f=A.create(d.createElement(j));(G(f.toJSON())).toEqual(nil)end)S("\101\120\112\111\115\101\115 \097 \116\121\112\101 \102\108\097\103",function()local function j()return d.createElement("\097",{role="\108\105\110\107"})end local f=A.create(d.createElement(j))local T=f.toJSON();(G(tostring(T["\036\036\116\121\112\101\111\102"]))).toEqual(tostring(Z.for_("\114\101\097\099\116\046\116\101\115\116\046\106\115\111\110")))for j,d in T do(G(j)).never.toEqual("\036\036\116\121\112\101\111\102")end end)S("\099\097\110 \114\101\110\100\101\114 \097 \099\111\109\112\111\115\105\116\101 \099\111\109\112\111\110\101\110\116",function()local j=d.Component:extend("\067\111\109\112\111\110\101\110\116")local f=function()return d.createElement("\109\111\111")end function j.render(j)return d.createElement("\100\105\118",{className="\112\117\114\112\108\101"},d.createElement(f,nil))end local T=A.create(d.createElement(j));(G(T.toJSON())).toEqual({type="\100\105\118";props={className="\112\117\114\112\108\101"};children={{type="\109\111\111",props={},children=nil}}})end)S("\114\101\110\100\101\114\115 \115\111\109\101 \098\097\115\105\099\115 \119\105\116\104 \097\110 \117\112\100\097\116\101",function()local j=0 local f=d.Component:extend("\067\111\109\112\111\110\101\110\116")local T=function()j=j+1 return d.createElement("\109\111\111")end local Z=function()j=j+1 return nil end function f.init(j)j.state={x=3}return end function f.render(A)j=j+1 return d.createElement("\100\105\118",{className="\112\117\114\112\108\101"},A.state.x,d.createElement(T),d.createElement(Z))end function f.componentDidMount(j)j:setState({x=7})end local O=A.create(d.createElement(f));(G(O.toJSON())).toEqual({type="\100\105\118",props={className="\112\117\114\112\108\101"};children={"\055";{type="\109\111\111",props={};children=nil}}});(G(j)).toEqual(6)end)S("\101\120\112\111\115\101\115 \116\104\101 \105\110\115\116\097\110\099\101",function()local j=d.Component:extend("\077\111\117\115\101")function j.init(j)j.state={mouse="\109\111\117\115\101"}end function j.handleMoose(j)j:setState({mouse="\109\111\111\115\101"})end function j.render(j)return d.createElement("\100\105\118",nil,j.state.mouse)end local f=A.create(d.createElement(j));(G(f.toJSON())).toEqual({type="\100\105\118",props={};children={"\109\111\117\115\101"}})local T=f.getInstance()T:handleMoose();(G(f.toJSON())).toEqual({type="\100\105\118",children={"\109\111\111\115\101"},props={}})end)S("\117\112\100\097\116\101\115 \116\121\112\101\115",function()local j=A.create(d.createElement("\100\105\118",nil,"\109\111\117\115\101"));(G(j.toJSON())).toEqual({type="\100\105\118";props={},children={"\109\111\117\115\101"}})j.update(d.createElement("\115\112\097\110",nil,"\109\105\099\101"));(G(j.toJSON())).toEqual({type="\115\112\097\110",props={},children={"\109\105\099\101"}})end)S("\117\112\100\097\116\101\115 \099\104\105\108\100\114\101\110",function()local j=A.create(d.createElement("\100\105\118",nil,d.createElement("\115\112\097\110",{key="\097"},"\065"),d.createElement("\115\112\097\110",{key="\098"},"\066"),d.createElement("\115\112\097\110",{key="\099"},"\067")));(G(j.toJSON())).toEqual({type="\100\105\118";props={};children={{type="\115\112\097\110";props={};children={"\065"}};{type="\115\112\097\110",props={},children={"\066"}},{type="\115\112\097\110",props={},children={"\067"}}}})j.update(d.createElement("\100\105\118",nil,d.createElement("\115\112\097\110",{key="\100"},"\068"),d.createElement("\115\112\097\110",{key="\099"},"\067"),d.createElement("\115\112\097\110",{key="\098"},"\066")));(G(j.toJSON())).toEqual({type="\100\105\118",props={};children={{type="\115\112\097\110";props={},children={"\068"}},{type="\115\112\097\110",props={},children={"\067"}},{type="\115\112\097\110",props={},children={"\066"}}}})end)S("\100\111\101\115 \116\104\101 \102\117\108\108 \108\105\102\101\099\121\099\108\101",function()local j={}local f=d.Component:extend("\076\111\103")function f.render(A)table.insert(j,"\114\101\110\100\101\114 "..A.props.name)return d.createElement("\100\105\118")end function f.componentDidMount(d)table.insert(j,"\109\111\117\110\116 "..d.props.name)end function f.componentWillUnmount(d)table.insert(j,"\117\110\109\111\117\110\116 "..d.props.name)end local T=A.create(d.createElement(f,{key="\102\111\111";name="\070\111\111"}))T.update(d.createElement(f,{key="\098\097\114",name="\066\097\114"}))T.unmount();(G(j)).toEqual({"\114\101\110\100\101\114 \070\111\111";"\109\111\117\110\116 \070\111\111","\114\101\110\100\101\114 \066\097\114";"\117\110\109\111\117\110\116 \070\111\111";"\109\111\117\110\116 \066\097\114";"\117\110\109\111\117\110\116 \066\097\114"})end)S("\103\105\118\101\115 \097 \114\101\102 \116\111 \110\097\116\105\118\101 \099\111\109\112\111\110\101\110\116\115",function()local j={}A.create(d.createElement("\100\105\118",{ref=function(d)return table.insert(j,d)end}));(G(j)).toEqual({nil})end)S("\119\097\114\110\115 \099\111\114\114\101\099\116\108\121 \102\111\114 \114\101\102\115 \111\110 \083\070\067\115",function()local function j()return d.createElement("\100\105\118",nil,"\072\101\108\108\111\044 \119\111\114\108\100")end local f=d.Component:extend("\070\111\111")function f.render(A)return d.createElement(j,{ref=d.createRef()})end local T=d.Component:extend("\066\097\122")function T.render(j)return d.createElement("\100\105\118",{ref=d.createRef()})end A.create(d.createElement(T));(G(function()return A.create(d.createElement(f))end)).toErrorDev("\087\097\114\110\105\110\103\058 \070\117\110\099\116\105\111\110 \099\111\109\112\111\110\101\110\116\115 \099\097\110\110\111\116 \098\101 \103\105\118\101\110 \114\101\102\115\046 \065\116\116\101\109\112\116\115 \116\111 \097\099\099\101\115\115 \116\104\105\115 \114\101\102 \119\105\108\108 \102\097\105\108\046 \068\105\100 \121\111\117 \109\101\097\110 \116\111 \117\115\101 \082\101\097\099\116\046\102\111\114\119\097\114\100\082\101\102\040\041\063\n\n\067\104\101\099\107 \116\104\101 \114\101\110\100\101\114 \109\101\116\104\111\100 \111\102 \096\070\111\111\096\046\n    \105\110 \066\097\114 \040\097\116 \042\042\041\n    \105\110 \070\111\111 \040\097\116 \042\042\041")end)S("\097\108\108\111\119\115 \097\110 \111\112\116\105\111\110\097\108 \099\114\101\097\116\101\078\111\100\101\077\111\099\107 \102\117\110\099\116\105\111\110",function()local j={appendChild=function() end}local f={focus=function() end}local T={click=function() end}local Z={hover=function() end}local O={}local I=d.createRef()local g=d.Component:extend("\070\111\111")function g.componentDidMount(j)table.insert(O,I.current)end function g.render(j)return d.createElement("\097",{ref=I},"\072\101\108\108\111\044 \119\111\114\108\100")end local function J(d)if d.type=="\100\105\118"then return j elseif d.type=="\105\110\112\117\116"then return f elseif d.type=="\108\105"then return T elseif d.type=="\097"then return Z else return{}end end A.create(d.createElement("\100\105\118",{ref=function(j)return table.insert(O,j)end}),{createNodeMock=J})A.create(d.createElement("\105\110\112\117\116",{ref=function(j)return table.insert(O,j)end}),{createNodeMock=J})A.create(d.createElement("\100\105\118",nil,d.createElement("\115\112\097\110",nil,d.createElement("\117\108",nil,d.createElement("\108\105",{ref=function(j)return table.insert(O,j)end})),d.createElement("\117\108",nil,d.createElement("\108\105",{ref=function(j)return table.insert(O,j)end}),d.createElement("\108\105",{ref=function(j)return table.insert(O,j)end})))),{createNodeMock=J;foobar=true})A.create(d.createElement(g),{createNodeMock=J})A.create(d.createElement("\100\105\118",{ref=function(j)return table.insert(O,j)end}))A.create(d.createElement("\100\105\118",{ref=function(j)return table.insert(O,j)end}),{});(G(O)).toEqual({j;f;T,T,T;Z})end)S("\115\117\112\112\111\114\116\115 \117\110\109\111\117\110\116\105\110\103 \119\104\101\110 \117\115\105\110\103 \114\101\102\115",function()local j=d.Component:extend("\070\111\111")local f=d.createRef()function j.render(j)return d.createElement("\100\105\118",{ref=f})end local T=A.create(d.createElement(j),{createNodeMock=function()return f.current end});(G(function()return T.unmount()end)).never.toThrow()end)S("\115\117\112\112\111\114\116\115 \117\110\109\111\117\110\116\105\110\103 \105\110\110\101\114 \105\110\115\116\097\110\099\101\115",function()local j=0 local f=d.Component:extend("\070\111\111")function f.componentWillUnmount(d)j=j+1 end function f.render(j)return d.createElement("\100\105\118")end local T=A.create(d.createElement("\100\105\118",nil,d.createElement(f)),{createNodeMock=function()return"\102\111\111"end});(G(function()return T.unmount()end)).never.toThrow();(G(j)).toEqual(1)end)S("\115\117\112\112\111\114\116\115 \117\112\100\097\116\101\115 \119\104\101\110 \117\115\105\110\103 \114\101\102\115",function()local j={}local f=function(d)table.insert(j,d.type)return d.type end local T=d.Component:extend("\070\111\111")function T.render(j)return(function()if j.props.useDiv then return d.createElement("\100\105\118",{ref=d.createRef()})end return d.createElement("\115\112\097\110",{ref=d.createRef()})end)()end local Z=A.create(d.createElement(T,{useDiv=true}),{createNodeMock=f})Z.update(d.createElement(T,{useDiv=false}));(G(j)).toEqual({"\100\105\118";"\115\112\097\110"})end)S("\115\117\112\112\111\114\116\115 \101\114\114\111\114 \098\111\117\110\100\097\114\105\101\115",function()local j={}local f=d.Component:extend("\065\110\103\114\121")function f.render(d)table.insert(j,"\065\110\103\114\121 \114\101\110\100\101\114")error("\080\108\101\097\115\101\044 \100\111 \110\111\116 \114\101\110\100\101\114 \109\101\046")end function f.componentDidMount(d)table.insert(j,"\065\110\103\114\121 \099\111\109\112\111\110\101\110\116\068\105\100\077\111\117\110\116")end function f.componentWillUnmount(d)table.insert(j,"\065\110\103\114\121 \099\111\109\112\111\110\101\110\116\087\105\108\108\085\110\109\111\117\110\116")end local T=d.Component:extend("\066\111\117\110\100\097\114\121")function T.init(d,j)d.state={error=false}end function T.render(A)table.insert(j,"\066\111\117\110\100\097\114\121 \114\101\110\100\101\114")if not A.state.error then return d.createElement("\100\105\118",nil,d.createElement("\098\117\116\116\111\110",{onClick=A.onClick},"\067\108\105\099\107\077\101"),d.createElement(f))else return d.createElement("\100\105\118",nil,"\072\097\112\112\121 \066\105\114\116\104\100\097\121\033")end end function T.componentDidMount(d)table.insert(j,"\066\111\117\110\100\097\114\121 \099\111\109\112\111\110\101\110\116\068\105\100\077\111\117\110\116")end function T.componentWillUnmount(d)table.insert(j,"\066\111\117\110\100\097\114\121 \099\111\109\112\111\110\101\110\116\087\105\108\108\085\110\109\111\117\110\116")end function T.onClick(j)return end function T.componentDidCatch(d)table.insert(j,"\066\111\117\110\100\097\114\121 \099\111\109\112\111\110\101\110\116\068\105\100\067\097\116\099\104")d:setState({error=true})end local Z=A.create(d.createElement(T));(G(Z.toJSON())).toEqual({type="\100\105\118";props={},children={"\072\097\112\112\121 \066\105\114\116\104\100\097\121\033"}});(G(j)).toEqual({"\066\111\117\110\100\097\114\121 \114\101\110\100\101\114";"\065\110\103\114\121 \114\101\110\100\101\114","\066\111\117\110\100\097\114\121 \099\111\109\112\111\110\101\110\116\068\105\100\077\111\117\110\116","\066\111\117\110\100\097\114\121 \099\111\109\112\111\110\101\110\116\068\105\100\067\097\116\099\104","\066\111\117\110\100\097\114\121 \114\101\110\100\101\114"})end)S("\099\097\110 \117\112\100\097\116\101 \116\101\120\116 \110\111\100\101\115",function()local j=d.Component:extend("\067\111\109\112\111\110\101\110\116")function j.render(j)return d.createElement("\100\105\118",nil,j.props.children)end local f=A.create(d.createElement(j,nil,"\072\105"));(G(f.toJSON())).toEqual({type="\100\105\118";children={"\072\105"};props={}})f.update(d.createElement(j,nil,{"\072\105";"\066\121\101"}));(G(f.toJSON())).toEqual({type="\100\105\118";children={"\072\105","\066\121\101"},props={}})f.update(d.createElement(j,nil,"\066\121\101"));(G(f.toJSON())).toEqual({type="\100\105\118",children={"\066\121\101"},props={}})f.update(d.createElement(j,nil,42));(G(f.toJSON())).toEqual({type="\100\105\118",children={"\052\050"},props={}})f.update(d.createElement(j,nil,d.createElement("\100\105\118")));(G(f.toJSON())).toEqual({type="\100\105\118",children={{type="\100\105\118";children=nil;props={}}};props={}})end)S("\116\111\084\114\101\101\040\041 \114\101\110\100\101\114\115 \115\105\109\112\108\101 \099\111\109\112\111\110\101\110\116\115 \114\101\116\117\114\110\105\110\103 \104\111\115\116 \099\111\109\112\111\110\101\110\116\115",function()local j=function()return d.createElement("\115\112\097\110",{className="\081\111\111"},"\072\101\108\108\111 \087\111\114\108\100\033")end local f=A.create(d.createElement(j))local T=f.toTree()O(T);(G(T)).toEqual({nodeType="\099\111\109\112\111\110\101\110\116";type=j,props={},instance=nil,rendered={nodeType="\104\111\115\116";type="\115\112\097\110",props={className="\081\111\111"};instance=nil,rendered={"\072\101\108\108\111 \087\111\114\108\100\033"}}})end)S("\116\111\084\114\101\101\040\041 \104\097\110\100\108\101\115 \110\101\115\116\101\100 \070\114\097\103\109\101\110\116\115",function()local j=function()return d.createElement(d.Fragment,nil,d.createElement(d.Fragment,nil,"\102\111\111"))end local f=A.create(d.createElement(j))local T=f.toTree()O(T);(G(T)).toEqual({nodeType="\099\111\109\112\111\110\101\110\116",type=j;instance=nil;props={};rendered="\102\111\111"})end)S("\116\111\084\114\101\101\040\041 \104\097\110\100\108\101\115 \110\117\108\108 \114\101\110\100\101\114\105\110\103 \099\111\109\112\111\110\101\110\116\115",function()local j=d.Component:extend("\070\111\111")function j.render(j)return nil end local f=A.create(d.createElement(j))local T=f.toTree();(G(T.instance._reactInternals.elementType.__componentName)).toEqual("\070\111\111")O(T);(G(T)).toEqual({type=j;nodeType="\099\111\109\112\111\110\101\110\116",props={};instance=nil,rendered=nil})end)S("\116\111\084\114\101\101\040\041 \104\097\110\100\108\101\115 \115\105\109\112\108\101 \099\111\109\112\111\110\101\110\116\115 \116\104\097\116 \114\101\116\117\114\110 \097\114\114\097\121\115",function()local j=function(j)local d=j.children return d end local f=A.create(d.createElement(j,nil,d.createElement("\100\105\118",nil,"\079\110\101"),d.createElement("\100\105\118",nil,"\084\119\111")))local T=f.toTree()O(T);(G(T)).toEqual({type=j;nodeType="\099\111\109\112\111\110\101\110\116";props={},instance=nil;rendered={{instance=nil,nodeType="\104\111\115\116",props={};rendered={"\079\110\101"};type="\100\105\118"};{instance=nil,nodeType="\104\111\115\116";props={},rendered={"\084\119\111"};type="\100\105\118"}}})end)S("\116\111\084\114\101\101\040\041 \104\097\110\100\108\101\115 \099\111\109\112\108\105\099\097\116\101\100 \116\114\101\101 \111\102 \097\114\114\097\121\115",function()local j=d.Component:extend("\070\111\111")function j.render(j)return j.props.children end local f=A.create(d.createElement("\100\105\118",nil,d.createElement(j,nil,d.createElement("\100\105\118",nil,"\079\110\101"),d.createElement("\100\105\118",nil,"\084\119\111"),d.createElement(j,nil,d.createElement("\100\105\118",nil,"\084\104\114\101\101"))),d.createElement("\100\105\118",nil,"\070\111\117\114")))local T=f.toTree()O(T);(G(T)).toEqual({type="\100\105\118";instance=nil,nodeType="\104\111\115\116";props={},rendered={{type=j,nodeType="\099\111\109\112\111\110\101\110\116";props={};instance=nil;rendered={{type="\100\105\118";nodeType="\104\111\115\116";props={},instance=nil,rendered={"\079\110\101"}};{type="\100\105\118";nodeType="\104\111\115\116",props={},instance=nil,rendered={"\084\119\111"}},{type=j;nodeType="\099\111\109\112\111\110\101\110\116";props={};instance=nil,rendered={type="\100\105\118",nodeType="\104\111\115\116",props={};instance=nil;rendered={"\084\104\114\101\101"}}}}},{type="\100\105\118",nodeType="\104\111\115\116";props={};instance=nil;rendered={"\070\111\117\114"}}}})end)S("\116\111\084\114\101\101\040\041 \104\097\110\100\108\101\115 \099\111\109\112\108\105\099\097\116\101\100 \116\114\101\101 \111\102 \102\114\097\103\109\101\110\116\115",function()local j=A.create(d.createElement(d.Fragment,nil,d.createElement(d.Fragment,nil,d.createElement("\100\105\118",nil,"\079\110\101"),d.createElement("\100\105\118",nil,"\084\119\111"),d.createElement(d.Fragment,nil,d.createElement("\100\105\118",nil,"\084\104\114\101\101"))),d.createElement("\100\105\118",nil,"\070\111\117\114")))local f=j.toTree()O(f);(G(f)).toEqual({{type="\100\105\118",nodeType="\104\111\115\116";props={};instance=nil;rendered={"\079\110\101"}},{type="\100\105\118",nodeType="\104\111\115\116";props={},instance=nil;rendered={"\084\119\111"}};{type="\100\105\118",nodeType="\104\111\115\116";props={},instance=nil;rendered={"\084\104\114\101\101"}},{type="\100\105\118",nodeType="\104\111\115\116",props={},instance=nil;rendered={"\070\111\117\114"}}})end)S("\114\111\111\116 \105\110\115\116\097\110\099\101 \097\110\100 \099\114\101\097\116\101\078\111\100\101\077\111\099\107 \114\101\102 \114\101\116\117\114\110 \116\104\101 \115\097\109\101 \118\097\108\117\101",function()local j=function(j)return{node=j}end local f=nil local T=A.create(d.createElement("\100\105\118",{ref=function(j)f=j return end}),{createNodeMock=j})local Z=T.getInstance();(G(Z)).toEqual(f)end)S("\116\111\084\114\101\101\040\041 \114\101\110\100\101\114\115 \099\111\109\112\108\105\099\097\116\101\100 \116\114\101\101\115 \111\102 \099\111\109\112\111\115\105\116\101\115 \097\110\100 \104\111\115\116\115",function()local j=function()return d.createElement("\115\112\097\110",{className="\081\111\111"},"\072\101\108\108\111 \087\111\114\108\100\033")end local f=function(j)local A,f=j.className,j.children return d.createElement("\100\105\118",{className="\070\111\111 "..A},d.createElement("\115\112\097\110",{className="\070\111\111\050"},"\076\105\116\101\114\097\108"),f)end local T=d.Component:extend("\066\097\114")function T.render(j)local A=j.props.children local T=j.props.special return d.createElement(f,{className=(function()if T then return"\115\112\101\099\105\097\108"end return"\110\111\114\109\097\108"end)()},A)end local Z=d.Component:extend("\066\097\109")function Z.render(A)return d.createElement(T,{special=true},d.createElement(j))end local I=A.create(d.createElement(Z))local g=I.toTree();(G(g.instance._reactInternals.elementType.__componentName)).toEqual("\066\097\109");(G(g.rendered.instance._reactInternals.elementType.__componentName)).toEqual("\066\097\114")O(g);(G(g)).toEqual({type=Z;nodeType="\099\111\109\112\111\110\101\110\116",props={},instance=nil,rendered={type=T,nodeType="\099\111\109\112\111\110\101\110\116";props={special=true};instance=nil,rendered={type=f;nodeType="\099\111\109\112\111\110\101\110\116";props={className="\115\112\101\099\105\097\108"};instance=nil;rendered={type="\100\105\118",nodeType="\104\111\115\116";props={className="\070\111\111 \115\112\101\099\105\097\108"},instance=nil;rendered={{type="\115\112\097\110",nodeType="\104\111\115\116";props={className="\070\111\111\050"},instance=nil,rendered={"\076\105\116\101\114\097\108"}},{type=j;nodeType="\099\111\109\112\111\110\101\110\116",props={},instance=nil;rendered={type="\115\112\097\110",nodeType="\104\111\115\116",props={className="\081\111\111"},instance=nil;rendered={"\072\101\108\108\111 \087\111\114\108\100\033"}}}}}}}})end)S("\099\097\110 \117\112\100\097\116\101 \116\101\120\116 \110\111\100\101\115 \119\104\101\110 \114\101\110\100\101\114\101\100 \097\115 \114\111\111\116",function()local j=A.create({"\072\101\108\108\111","\119\111\114\108\100"});(G(j.toJSON())).toEqual({"\072\101\108\108\111";"\119\111\114\108\100"})j.update(42);(G(j.toJSON())).toEqual("\052\050")j.update({42,"\119\111\114\108\100"});(G(j.toJSON())).toEqual({"\052\050";"\119\111\114\108\100"})end)S("\099\097\110 \114\101\110\100\101\114 \097\110\100 \117\112\100\097\116\101 \114\111\111\116 \102\114\097\103\109\101\110\116\115",function()local j=function(j)return j.children end local f=A.create({d.createElement(j,{key="\097"},"\072\105"),d.createElement(j,{key="\098"},"\066\121\101")});(G(f.toJSON())).toEqual({"\072\105","\066\121\101"})f.update(d.createElement("\100\105\118"));(G(f.toJSON())).toEqual({type="\100\105\118",children=nil;props={}})f.update({d.createElement("\100\105\118",{key="\097"},"\103\111\111\100\098\121\101");"\119\111\114\108\100"});(G(f.toJSON())).toEqual({{type="\100\105\118",children={"\103\111\111\100\098\121\101"},props={}},"\119\111\114\108\100"})end)S("\115\117\112\112\111\114\116\115 \099\111\110\116\101\120\116 \112\114\111\118\105\100\101\114\115 \097\110\100 \099\111\110\115\117\109\101\114\115",function()local j=d.createContext("\097")local f=j.Consumer local T=j.Provider local function Z(j)return j.value end local function O()return d.createElement(T,{value="\098"},d.createElement(f,nil,function(j)return d.createElement(Z,{value=j})end))end local I=A.create(d.createElement(O))local g=I.root:findByType(Z);(G(g.children)).toEqual({"\098"});(G(I.toTree())).toEqual({instance=nil;nodeType="\099\111\109\112\111\110\101\110\116";props={};rendered={instance=nil;nodeType="\099\111\109\112\111\110\101\110\116";props={value="\098"},rendered="\098",type=Z},type=O})end)S("\115\117\112\112\111\114\116\115 \109\111\100\101\115",function()local function j(j)return j.value end local function f(A)return d.createElement(d.StrictMode,nil,d.createElement(j,{value=A.value}))end local T=A.create(d.createElement(f,{value="\097"}))local Z=T.root:findByType(j);(G(Z.children)).toEqual({"\097"});(G(T.toTree())).toEqual({instance=nil;nodeType="\099\111\109\112\111\110\101\110\116";props={value="\097"},rendered={instance=nil,nodeType="\099\111\109\112\111\110\101\110\116";props={value="\097"};rendered="\097";type=j};type=f})end)S("\115\117\112\112\111\114\116\115 \102\111\114\119\097\114\100\082\101\102",function()local j=d.forwardRef(function(j,A)return d.createElement("\100\105\118",nil,d.createElement("\115\112\097\110",{ref=A}))end)local f=d.Component:extend("\065\112\112")function f.render(A)return d.createElement(j,{ref=function(j)A.ref=j return end})end local T=A.create(d.createElement(f))local Z=T.toTree()O(Z);(G(Z)).toEqual({instance=nil;nodeType="\099\111\109\112\111\110\101\110\116",props={};rendered={instance=nil,nodeType="\104\111\115\116",props={};rendered={{instance=nil;nodeType="\104\111\115\116",props={},rendered={};type="\115\112\097\110"}};type="\100\105\118"};type=f})end)S("\099\097\108\108\105\110\103 \102\105\110\100\066\121\084\121\112\101\040\041 \119\105\116\104 \097\110 \105\110\118\097\108\105\100 \099\111\109\112\111\110\101\110\116 \119\105\108\108 \102\097\108\108 \098\097\099\107 \116\111 \"\085\110\107\110\111\119\110\" \102\111\114 \099\111\109\112\111\110\101\110\116 \110\097\109\101",function()local j=function()return nil end local f=A.create(d.createElement(j))local T={};(G(function()f.root:findByType(T)end)).toThrow("\078\111 \105\110\115\116\097\110\099\101\115 \102\111\117\110\100 \119\105\116\104 \110\111\100\101 \116\121\112\101\058 \"\085\110\107\110\111\119\110\"")end)end)
-- Upstream: https://github.com/facebook/react/blob/16654436039dd8f16a63928e71081c7745872e8f/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js
--  * 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
--  */

-- !strict
local ReactFeatureFlags

local React
local ReactTestRenderer
-- local prettyFormat = require('pretty-format')

-- Isolate noop renderer
-- local ReactNoop = require("@pkg/ReactNoopRenderer")
-- local Scheduler = require("@pkg/@jsdotlua/scheduler")

local LuauPolyfill = require("@pkg/@jsdotlua/luau-polyfill")
local Array = LuauPolyfill.Array
local Symbol = LuauPolyfill.Symbol

-- Kind of hacky, but we nullify all the instances to test the tree structure
-- with jasmine's deep equality function, and test the instances separate. We
-- also delete children props because testing them is more annoying and not
-- really important to verify.
local function cleanNodeOrArray(node)
	if not node then
		return
	end
	if Array.isArray(node) then
		-- ROBLOX deviation: for loop in place of forEach()
		for _, v in node do
			cleanNodeOrArray(v)
		end
		return
	end
	if node and node.instance then
		node.instance = nil
	end
	if node and node.props and node.props.children then
		-- eslint-disable-next-line no-unused-vars
		node.props["children"] = nil
	end
	if Array.isArray(node.rendered) then
		-- ROBLOX deviation: for loop in place of forEach()
		for _, v in node.rendered do
			cleanNodeOrArray(v)
		end
	elseif typeof(node.rendered) == "table" then
		cleanNodeOrArray(node.rendered)
	end
end

local JestGlobals = require("@pkg/@jsdotlua/jest-globals")
local beforeEach = JestGlobals.beforeEach
local jestExpect = JestGlobals.expect
local describe = JestGlobals.describe
local it = JestGlobals.it
local jest = JestGlobals.jest

describe("ReactTestRenderer", function()
	beforeEach(function()
		jest.resetModules()

		ReactFeatureFlags = require("@pkg/@jsdotlua/shared").ReactFeatureFlags
		ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false

		React = require("@pkg/@jsdotlua/react")
		ReactTestRenderer = require("@pkg/@jsdotlua/react-test-renderer")
		-- local prettyFormat = require('pretty-format')
	end)
	it("renders a simple component", function()
		local function Link()
			return React.createElement("a", {
				role = "link",
			})
		end

		local renderer = ReactTestRenderer.create(React.createElement(Link))

		jestExpect(renderer.toJSON()).toEqual({
			type = "a",
			props = {
				role = "link",
			},
			children = nil,
		})
	end)
	it("renders a top-level empty component", function()
		local function Empty()
			return nil
		end

		local renderer = ReactTestRenderer.create(React.createElement(Empty))

		jestExpect(renderer.toJSON()).toEqual(nil)
	end)
	it("exposes a type flag", function()
		local function Link()
			return React.createElement("a", {
				role = "link",
			})
		end

		local renderer = ReactTestRenderer.create(React.createElement(Link))
		local object = renderer.toJSON()
		-- ROBLOX FIXME: needs to stringify $$typeof because Symbol module is reset. Un-stringify once we've found a solution.
		jestExpect(tostring(object["$$typeof"])).toEqual(
			tostring(Symbol.for_("react.test.json"))
		)

		-- $$typeof should not be enumerable.
		for key, _ in object do
			jestExpect(key).never.toEqual("$$typeof")
		end
	end)
	it("can render a composite component", function()
		local Component = React.Component:extend("Component")

		local Child = function()
			return React.createElement("moo")
		end

		function Component:render()
			return React.createElement("div", {
				className = "purple",
			}, React.createElement(Child, nil))
		end

		local renderer = ReactTestRenderer.create(React.createElement(Component))

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {
				className = "purple",
			},
			children = {
				{
					type = "moo",
					props = {},
					children = nil,
				},
			},
		})
	end)
	it("renders some basics with an update", function()
		local renders = 0
		local Component = React.Component:extend("Component")

		local Child = function()
			renders = renders + 1

			return React.createElement("moo")
		end
		local Null = function()
			renders = renders + 1
			return nil
		end

		function Component:init()
			self.state = { x = 3 }
			return
		end
		function Component:render()
			renders = renders + 1

			return React.createElement("div", {
				className = "purple",
			}, self.state.x, React.createElement(Child), React.createElement(Null))
		end
		function Component:componentDidMount()
			self:setState({ x = 7 })
		end

		local renderer = ReactTestRenderer.create(React.createElement(Component))

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {
				className = "purple",
			},
			children = {
				"7",
				{
					type = "moo",
					props = {},
					children = nil,
				},
			},
		})
		jestExpect(renders).toEqual(6)
	end)
	it("exposes the instance", function()
		local Mouse = React.Component:extend("Mouse")

		function Mouse:init()
			self.state = {
				mouse = "mouse",
			}
		end
		function Mouse:handleMoose()
			self:setState({
				mouse = "moose",
			})
		end
		function Mouse:render()
			return React.createElement("div", nil, self.state.mouse)
		end

		local renderer = ReactTestRenderer.create(React.createElement(Mouse))

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {},
			children = {
				"mouse",
			},
		})

		local mouse = renderer.getInstance()

		mouse:handleMoose()
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = {
				"moose",
			},
			props = {},
		})
	end)
	it("updates types", function()
		local renderer =
			ReactTestRenderer.create(React.createElement("div", nil, "mouse"))

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {},
			children = {
				"mouse",
			},
		})
		renderer.update(React.createElement("span", nil, "mice"))
		jestExpect(renderer.toJSON()).toEqual({
			type = "span",
			props = {},
			children = {
				"mice",
			},
		})
	end)
	it("updates children", function()
		local renderer = ReactTestRenderer.create(
			React.createElement(
				"div",
				nil,
				React.createElement("span", {
					key = "a",
				}, "A"),
				React.createElement("span", {
					key = "b",
				}, "B"),
				React.createElement("span", {
					key = "c",
				}, "C")
			)
		)

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {},
			children = {
				{
					type = "span",
					props = {},
					children = {
						"A",
					},
				},
				{
					type = "span",
					props = {},
					children = {
						"B",
					},
				},
				{
					type = "span",
					props = {},
					children = {
						"C",
					},
				},
			},
		})
		renderer.update(React.createElement(
			"div",
			nil,
			React.createElement("span", {
				key = "d",
			}, "D"),
			React.createElement("span", {
				key = "c",
			}, "C"),
			React.createElement("span", {
				key = "b",
			}, "B")
		))
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {},
			children = {
				{
					type = "span",
					props = {},
					children = {
						"D",
					},
				},
				{
					type = "span",
					props = {},
					children = {
						"C",
					},
				},
				{
					type = "span",
					props = {},
					children = {
						"B",
					},
				},
			},
		})
	end)
	it("does the full lifecycle", function()
		local log = {}
		local Log = React.Component:extend("Log")

		function Log:render()
			table.insert(log, "render " .. self.props.name)
			return React.createElement("div")
		end
		function Log:componentDidMount()
			table.insert(log, "mount " .. self.props.name)
		end
		function Log:componentWillUnmount()
			table.insert(log, "unmount " .. self.props.name)
		end

		local renderer = ReactTestRenderer.create(React.createElement(Log, {
			key = "foo",
			name = "Foo",
		}))

		renderer.update(React.createElement(Log, {
			key = "bar",
			name = "Bar",
		}))
		renderer.unmount()
		jestExpect(log).toEqual({
			"render Foo",
			"mount Foo",
			"render Bar",
			"unmount Foo",
			"mount Bar",
			"unmount Bar",
		})
	end)
	it("gives a ref to native components", function()
		local log = {}

		ReactTestRenderer.create(React.createElement("div", {
			ref = function(r)
				return table.insert(log, r)
			end,
		}))
		jestExpect(log).toEqual({ nil })
	end)
	it("warns correctly for refs on SFCs", function()
		local function Bar()
			return React.createElement("div", nil, "Hello, world")
		end

		local Foo = React.Component:extend("Foo")

		function Foo:render()
			return React.createElement(Bar, {
				ref = React.createRef(),
			})
		end

		local Baz = React.Component:extend("Baz")

		function Baz:render()
			return React.createElement("div", {
				ref = React.createRef(),
			})
		end

		ReactTestRenderer.create(React.createElement(Baz))
		jestExpect(function()
			return ReactTestRenderer.create(React.createElement(Foo))
		end).toErrorDev(
			"Warning: Function components cannot be given refs. Attempts "
				.. "to access this ref will fail. "
				.. "Did you mean to use React.forwardRef()?\n\n"
				.. "Check the render method of `Foo`.\n"
				.. "    in Bar (at **)\n"
				.. "    in Foo (at **)"
		)
	end)
	it("allows an optional createNodeMock function", function()
		local mockDivInstance = {
			appendChild = function() end,
		}
		local mockInputInstance = {
			focus = function() end,
		}
		local mockListItemInstance = {
			click = function() end,
		}
		local mockAnchorInstance = {
			hover = function() end,
		}
		local log = {}

		-- ROBLOX deviation: using createRef in place of string refs
		local bar = React.createRef()
		local Foo = React.Component:extend("Foo")

		function Foo:componentDidMount()
			table.insert(log, bar.current)
		end
		function Foo:render()
			return React.createElement("a", {
				ref = bar,
			}, "Hello, world")
		end

		local function createNodeMock(element)
			if element.type == "div" then
				return mockDivInstance
			elseif element.type == "input" then
				return mockInputInstance
			elseif element.type == "li" then
				return mockListItemInstance
			elseif element.type == "a" then
				return mockAnchorInstance
			else
				return {}
			end
		end

		ReactTestRenderer.create(
			React.createElement("div", {
				ref = function(r)
					return table.insert(log, r)
				end,
			}),
			{ createNodeMock = createNodeMock }
		)
		ReactTestRenderer.create(
			React.createElement("input", {
				ref = function(r)
					return table.insert(log, r)
				end,
			}),
			{ createNodeMock = createNodeMock }
		)
		ReactTestRenderer.create(
			React.createElement(
				"div",
				nil,
				React.createElement(
					"span",
					nil,
					React.createElement(
						"ul",
						nil,
						React.createElement("li", {
							ref = function(r)
								return table.insert(log, r)
							end,
						})
					),
					React.createElement(
						"ul",
						nil,
						React.createElement("li", {
							ref = function(r)
								return table.insert(log, r)
							end,
						}),
						React.createElement("li", {
							ref = function(r)
								return table.insert(log, r)
							end,
						})
					)
				)
			),
			{
				createNodeMock = createNodeMock,
				foobar = true,
			}
		)
		ReactTestRenderer.create(
			React.createElement(Foo),
			{ createNodeMock = createNodeMock }
		)
		ReactTestRenderer.create(React.createElement("div", {
			ref = function(r)
				return table.insert(log, r)
			end,
		}))
		ReactTestRenderer.create(
			React.createElement("div", {
				ref = function(r)
					return table.insert(log, r)
				end,
			}),
			{}
		)
		jestExpect(log).toEqual({
			mockDivInstance,
			mockInputInstance,
			mockListItemInstance,
			mockListItemInstance,
			mockListItemInstance,
			mockAnchorInstance,
		})
	end)
	it("supports unmounting when using refs", function()
		local Foo = React.Component:extend("Foo")

		-- ROBLOX deviation: using createRef in place of string refs
		local foo = React.createRef()

		function Foo:render()
			return React.createElement("div", {
				ref = foo,
			})
		end

		local inst = ReactTestRenderer.create(React.createElement(Foo), {
			createNodeMock = function()
				return foo.current
			end,
		})

		jestExpect(function()
			return inst.unmount()
		end).never.toThrow()
	end)
	it("supports unmounting inner instances", function()
		local count = 0
		local Foo = React.Component:extend("Foo")

		function Foo:componentWillUnmount()
			count = count + 1
		end
		function Foo:render()
			return React.createElement("div")
		end

		local inst = ReactTestRenderer.create(
			React.createElement("div", nil, React.createElement(Foo)),
			{
				createNodeMock = function()
					return "foo"
				end,
			}
		)

		jestExpect(function()
			return inst.unmount()
		end).never.toThrow()
		jestExpect(count).toEqual(1)
	end)
	it("supports updates when using refs", function()
		local log = {}
		local createNodeMock = function(element)
			table.insert(log, element.type)
			return element.type
		end
		local Foo = React.Component:extend("Foo")

		function Foo:render()
			return (function()
				if self.props.useDiv then
					return React.createElement("div", {
						ref = React.createRef(),
					})
				end

				return React.createElement("span", {
					ref = React.createRef(),
				})
			end)()
		end

		local inst = ReactTestRenderer.create(
			React.createElement(Foo, { useDiv = true }),
			{ createNodeMock = createNodeMock }
		)

		inst.update(React.createElement(Foo, { useDiv = false }))
		jestExpect(log).toEqual({
			"div",
			"span",
		})
	end)
	it("supports error boundaries", function()
		local log = {}
		local Angry = React.Component:extend("Angry")

		function Angry:render()
			table.insert(log, "Angry render")
			error("Please, do not render me.")
		end
		function Angry:componentDidMount()
			table.insert(log, "Angry componentDidMount")
		end
		function Angry:componentWillUnmount()
			table.insert(log, "Angry componentWillUnmount")
		end

		local Boundary = React.Component:extend("Boundary")

		function Boundary:init(props)
			self.state = { error = false }
		end
		function Boundary:render()
			table.insert(log, "Boundary render")

			if not self.state.error then
				return React.createElement(
					"div",
					nil,
					React.createElement("button", {
						onClick = self.onClick,
					}, "ClickMe"),
					React.createElement(Angry)
				)
			else
				return React.createElement("div", nil, "Happy Birthday!")
			end
		end
		function Boundary:componentDidMount()
			table.insert(log, "Boundary componentDidMount")
		end
		function Boundary:componentWillUnmount()
			table.insert(log, "Boundary componentWillUnmount")
		end
		function Boundary:onClick()
			-- do nothing
			return
		end
		function Boundary:componentDidCatch()
			table.insert(log, "Boundary componentDidCatch")
			self:setState({ error = true })
		end

		-- ROBLOX Test Noise: jest setup config makes this hide error
		-- boundary warnings in upstream (scripts/jest/setupTests.js:72)
		local renderer = ReactTestRenderer.create(React.createElement(Boundary))

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			props = {},
			children = {
				"Happy Birthday!",
			},
		})
		jestExpect(log).toEqual({
			"Boundary render",
			"Angry render",
			"Boundary componentDidMount",
			"Boundary componentDidCatch",
			"Boundary render",
		})
	end)
	it("can update text nodes", function()
		local Component = React.Component:extend("Component")

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

		local renderer =
			ReactTestRenderer.create(React.createElement(Component, nil, "Hi"))

		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = {
				"Hi",
			},
			props = {},
		})
		renderer.update(React.createElement(Component, nil, {
			"Hi",
			"Bye",
		}))
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = {
				"Hi",
				"Bye",
			},
			props = {},
		})
		renderer.update(React.createElement(Component, nil, "Bye"))
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = {
				"Bye",
			},
			props = {},
		})
		renderer.update(React.createElement(Component, nil, 42))
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = {
				"42",
			},
			props = {},
		})
		renderer.update(React.createElement(Component, nil, React.createElement("div")))
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = {
				{
					type = "div",
					children = nil,
					props = {},
				},
			},
			props = {},
		})
	end)
	it("toTree() renders simple components returning host components", function()
		local Qoo = function()
			return React.createElement("span", {
				className = "Qoo",
			}, "Hello World!")
		end
		local renderer = ReactTestRenderer.create(React.createElement(Qoo))
		local tree = renderer.toTree()

		cleanNodeOrArray(tree)

		-- ROBLOX deviation: no need to pretty format
		jestExpect(tree).toEqual({
			nodeType = "component",
			type = Qoo,
			props = {},
			instance = nil,
			rendered = {
				nodeType = "host",
				type = "span",
				props = {
					className = "Qoo",
				},
				instance = nil,
				rendered = {
					"Hello World!",
				},
			},
		})
	end)
	it("toTree() handles nested Fragments", function()
		local Foo = function()
			return React.createElement(
				React.Fragment,
				nil,
				React.createElement(React.Fragment, nil, "foo")
			)
		end
		local renderer = ReactTestRenderer.create(React.createElement(Foo))
		local tree = renderer.toTree()

		cleanNodeOrArray(tree)

		-- ROBLOX deviation: no need to pretty format
		jestExpect(tree).toEqual({
			nodeType = "component",
			type = Foo,
			instance = nil,
			props = {},
			rendered = "foo",
		})
	end)
	it("toTree() handles null rendering components", function()
		local Foo = React.Component:extend("Foo")

		function Foo:render()
			return nil
		end

		local renderer = ReactTestRenderer.create(React.createElement(Foo))
		local tree = renderer.toTree()

		-- ROBLOX deviation: toBeInstanceOf not yet implemented, workaround by checking elementType
		jestExpect(tree.instance._reactInternals.elementType.__componentName).toEqual(
			"Foo"
		)
		cleanNodeOrArray(tree)

		jestExpect(tree).toEqual({
			type = Foo,
			nodeType = "component",
			props = {},
			instance = nil,
			rendered = nil,
		})
	end)
	it("toTree() handles simple components that return arrays", function()
		local Foo = function(_ref)
			local children = _ref.children

			return children
		end
		local renderer = ReactTestRenderer.create(
			React.createElement(
				Foo,
				nil,
				React.createElement("div", nil, "One"),
				React.createElement("div", nil, "Two")
			)
		)
		local tree = renderer.toTree()

		cleanNodeOrArray(tree)

		-- ROBLOX deviation: no need to pretty format
		jestExpect(tree).toEqual({
			type = Foo,
			nodeType = "component",
			props = {},
			instance = nil,
			rendered = {
				{
					instance = nil,
					nodeType = "host",
					props = {},
					rendered = {
						"One",
					},
					type = "div",
				},
				{
					instance = nil,
					nodeType = "host",
					props = {},
					rendered = {
						"Two",
					},
					type = "div",
				},
			},
		})
	end)
	it("toTree() handles complicated tree of arrays", function()
		local Foo = React.Component:extend("Foo")

		function Foo:render()
			return self.props.children
		end

		local renderer = ReactTestRenderer.create(
			React.createElement(
				"div",
				nil,
				React.createElement(
					Foo,
					nil,
					React.createElement("div", nil, "One"),
					React.createElement("div", nil, "Two"),
					React.createElement(
						Foo,
						nil,
						React.createElement("div", nil, "Three")
					)
				),
				React.createElement("div", nil, "Four")
			)
		)
		local tree = renderer.toTree()

		cleanNodeOrArray(tree)

		-- ROBLOX deviation: no need to pretty format
		jestExpect(tree).toEqual({
			type = "div",
			instance = nil,
			nodeType = "host",
			props = {},
			rendered = {
				{
					type = Foo,
					nodeType = "component",
					props = {},
					instance = nil,
					rendered = {
						{
							type = "div",
							nodeType = "host",
							props = {},
							instance = nil,
							rendered = {
								"One",
							},
						},
						{
							type = "div",
							nodeType = "host",
							props = {},
							instance = nil,
							rendered = {
								"Two",
							},
						},
						{
							type = Foo,
							nodeType = "component",
							props = {},
							instance = nil,
							rendered = {
								type = "div",
								nodeType = "host",
								props = {},
								instance = nil,
								rendered = {
									"Three",
								},
							},
						},
					},
				},
				{
					type = "div",
					nodeType = "host",
					props = {},
					instance = nil,
					rendered = {
						"Four",
					},
				},
			},
		})
	end)
	it("toTree() handles complicated tree of fragments", function()
		local renderer = ReactTestRenderer.create(
			React.createElement(
				React.Fragment,
				nil,
				React.createElement(
					React.Fragment,
					nil,
					React.createElement("div", nil, "One"),
					React.createElement("div", nil, "Two"),
					React.createElement(
						React.Fragment,
						nil,
						React.createElement("div", nil, "Three")
					)
				),
				React.createElement("div", nil, "Four")
			)
		)
		local tree = renderer.toTree()

		cleanNodeOrArray(tree)
		-- ROBLOX deviation: no need to pretty format
		jestExpect(tree).toEqual({
			{
				type = "div",
				nodeType = "host",
				props = {},
				instance = nil,
				rendered = {
					"One",
				},
			},
			{
				type = "div",
				nodeType = "host",
				props = {},
				instance = nil,
				rendered = {
					"Two",
				},
			},
			{
				type = "div",
				nodeType = "host",
				props = {},
				instance = nil,
				rendered = {
					"Three",
				},
			},
			{
				type = "div",
				nodeType = "host",
				props = {},
				instance = nil,
				rendered = {
					"Four",
				},
			},
		})
	end)
	it("root instance and createNodeMock ref return the same value", function()
		local createNodeMock = function(ref)
			return { node = ref }
		end
		local refInst = nil
		local renderer = ReactTestRenderer.create(
			React.createElement("div", {
				ref = function(ref)
					refInst = ref
					return
				end,
			}),
			{ createNodeMock = createNodeMock }
		)
		local root = renderer.getInstance()

		jestExpect(root).toEqual(refInst)
	end)
	it("toTree() renders complicated trees of composites and hosts", function()
		-- SFC returning host. no children props.
		local Qoo = function()
			return React.createElement("span", {
				className = "Qoo",
			}, "Hello World!")
		end

		-- SFC returning host. passes through children.
		local Foo = function(props)
			local className, children = props.className, props.children

			return React.createElement(
				"div",
				{
					className = "Foo " .. className,
				},
				React.createElement("span", {
					className = "Foo2",
				}, "Literal"),
				children
			)
		end

		-- class composite returning composite. passes through children.
		local Bar = React.Component:extend("Bar")
		function Bar:render()
			local children = self.props.children
			local special = self.props.special

			return React.createElement(Foo, {
				className = (function()
					if special then
						return "special"
					end

					return "normal"
				end)(),
			}, children)
		end

		-- class composite return composite. no children props.
		local Bam = React.Component:extend("Bam")

		function Bam:render()
			return React.createElement(Bar, { special = true }, React.createElement(Qoo))
		end

		local renderer = ReactTestRenderer.create(React.createElement(Bam))
		local tree = renderer.toTree()

		-- we test for the presence of instances before nulling them out
		-- ROBLOX deviation: toBeInstanceOf not yet implemented, workaround by checking elementType
		jestExpect(tree.instance._reactInternals.elementType.__componentName).toEqual(
			"Bam"
		)
		jestExpect(tree.rendered.instance._reactInternals.elementType.__componentName).toEqual(
			"Bar"
		)

		cleanNodeOrArray(tree)

		jestExpect(tree).toEqual({
			type = Bam,
			nodeType = "component",
			props = {},
			instance = nil,
			rendered = {
				type = Bar,
				nodeType = "component",
				props = { special = true },
				instance = nil,
				rendered = {
					type = Foo,
					nodeType = "component",
					props = {
						className = "special",
					},
					instance = nil,
					rendered = {
						type = "div",
						nodeType = "host",
						props = {
							className = "Foo special",
						},
						instance = nil,
						rendered = {
							{
								type = "span",
								nodeType = "host",
								props = {
									className = "Foo2",
								},
								instance = nil,
								rendered = {
									"Literal",
								},
							},
							{
								type = Qoo,
								nodeType = "component",
								props = {},
								instance = nil,
								rendered = {
									type = "span",
									nodeType = "host",
									props = {
										className = "Qoo",
									},
									instance = nil,
									rendered = {
										"Hello World!",
									},
								},
							},
						},
					},
				},
			},
		})
	end)
	it("can update text nodes when rendered as root", function()
		local renderer = ReactTestRenderer.create({
			"Hello",
			"world",
		})

		jestExpect(renderer.toJSON()).toEqual({
			"Hello",
			"world",
		})
		renderer.update(42)
		jestExpect(renderer.toJSON()).toEqual("42")
		renderer.update({
			42,
			"world",
		})
		jestExpect(renderer.toJSON()).toEqual({
			"42",
			"world",
		})
	end)
	it("can render and update root fragments", function()
		local Component = function(props)
			return props.children
		end
		local renderer = ReactTestRenderer.create({
			React.createElement(Component, {
				key = "a",
			}, "Hi"),
			React.createElement(Component, {
				key = "b",
			}, "Bye"),
		})

		jestExpect(renderer.toJSON()).toEqual({
			"Hi",
			"Bye",
		})
		renderer.update(React.createElement("div"))
		jestExpect(renderer.toJSON()).toEqual({
			type = "div",
			children = nil,
			props = {},
		})
		renderer.update({
			React.createElement("div", {
				key = "a",
			}, "goodbye"),
			"world",
		})
		jestExpect(renderer.toJSON()).toEqual({
			{
				type = "div",
				children = {
					"goodbye",
				},
				props = {},
			},
			"world",
		})
	end)
	it("supports context providers and consumers", function()
		local context = React.createContext("a")
		local Consumer = context.Consumer
		local Provider = context.Provider

		local function Child(props)
			return props.value
		end
		local function App()
			return React.createElement(
				Provider,
				{
					value = "b",
				},
				React.createElement(Consumer, nil, function(value)
					return React.createElement(Child, { value = value })
				end)
			)
		end

		local renderer = ReactTestRenderer.create(React.createElement(App))
		local child = renderer.root:findByType(Child)

		jestExpect(child.children).toEqual({
			"b",
		})
		-- ROBLOX deviation: no need to pretty format
		jestExpect(renderer.toTree()).toEqual({
			instance = nil,
			nodeType = "component",
			props = {},
			rendered = {
				instance = nil,
				nodeType = "component",
				props = {
					value = "b",
				},
				rendered = "b",
				type = Child,
			},
			type = App,
		})
	end)
	it("supports modes", function()
		local function Child(props)
			return props.value
		end
		local function App(props)
			return React.createElement(
				React.StrictMode,
				nil,
				React.createElement(Child, {
					value = props.value,
				})
			)
		end

		local renderer = ReactTestRenderer.create(React.createElement(App, {
			value = "a",
		}))
		local child = renderer.root:findByType(Child)

		jestExpect(child.children).toEqual({
			"a",
		})
		-- ROBLOX deviation: no need to pretty format
		jestExpect(renderer.toTree()).toEqual({
			instance = nil,
			nodeType = "component",
			props = {
				value = "a",
			},
			rendered = {
				instance = nil,
				nodeType = "component",
				props = {
					value = "a",
				},
				rendered = "a",
				type = Child,
			},
			type = App,
		})
	end)
	it("supports forwardRef", function()
		local InnerRefed = React.forwardRef(function(props, ref)
			return React.createElement(
				"div",
				nil,
				React.createElement("span", { ref = ref })
			)
		end)
		local App = React.Component:extend("App")

		function App:render()
			return React.createElement(InnerRefed, {
				ref = function(r)
					self.ref = r
					return
				end,
			})
		end

		local renderer = ReactTestRenderer.create(React.createElement(App))
		local tree = renderer.toTree()

		cleanNodeOrArray(tree)

		-- ROBLOX deviation: no need to pretty format
		jestExpect(tree).toEqual({
			instance = nil,
			nodeType = "component",
			props = {},
			rendered = {
				instance = nil,
				nodeType = "host",
				props = {},
				rendered = {
					{
						instance = nil,
						nodeType = "host",
						props = {},
						rendered = {},
						type = "span",
					},
				},
				type = "div",
			},
			type = App,
		})
	end)
	-- ROBLOX TODO: set up React Noop in this file
	-- xit('can concurrently render context with a "primary" renderer', function()
	--     local Context = React.createContext(nil)
	--     local Indirection = React.Fragment
	--     local App = function()
	--         return React.createElement(Context.Provider, {value = nil}, React.createElement(Indirection, nil, React.createElement(Context.Consumer, nil, function(
	--         )
	--             return nil
	--         end)))
	--     end

	--     ReactNoop.render(React.createElement(App))
	--     jestExpect(Scheduler).toFlushWithoutYielding()
	--     ReactTestRenderer.create(React.createElement(App))
	-- end)
	it(
		'calling findByType() with an invalid component will fall back to "Unknown" for component name',
		function()
			local App = function()
				return nil
			end
			local renderer = ReactTestRenderer.create(React.createElement(App))
			local NonComponent = {}
			jestExpect(function()
				renderer.root:findByType(NonComponent)
			end).toThrow('No instances found with node type: "Unknown"')
		end
	)
end)
