import { RenderResult, act, render } from '@testing-library/react' import { createRef, forwardRef, useEffect, useImperativeHandle } from 'react' import { atom } from '../core/Atom' import { track } from './track' // test("tracked components are memo'd", async () => { // let numRenders = 0 // const Component = track(function Component({ a, b, c }: { a: string; b: string; c: string }) { // numRenders++ // return ( // <> // {a} // {b} // {c} // // ) // }) // let view: RenderResult | undefined // await act(() => { // view = render() // }) // if (view) { // expect(view.container.textContent).toMatchInlineSnapshot(` // "a // b // c" // `) // expect(numRenders).toBe(1) // await act(() => { // view!.rerender() // }) // expect(numRenders).toBe(1) // await act(() => { // view!.rerender() // }) // expect(numRenders).toBe(2) // expect(view.container.textContent).toMatchInlineSnapshot(` // "a // b // d" // `) // } // }) // test("it's fine to call track on components that are already memo'd", async () => { // let numRenders = 0 // const Component = track( // memo(function Component({ a, b, c }: { a: string; b: string; c: string }) { // numRenders++ // return ( // <> // {a} // {b} // {c} // // ) // }) // ) // let view: RenderResult | undefined // await act(() => { // view = render() // }) // if (view) { // expect(view.container.textContent).toMatchInlineSnapshot(` // "a // b // c" // `) // expect(numRenders).toBe(1) // await act(() => { // view!.rerender() // }) // expect(numRenders).toBe(1) // await act(() => { // view!.rerender() // }) // expect(numRenders).toBe(2) // expect(view.container.textContent).toMatchInlineSnapshot(` // "a // b // d" // `) // } // }) test('tracked components can use refs', async () => { const Component = track( forwardRef<{ handle: string }, { prop: string }>(function Component({ prop }, ref) { useImperativeHandle(ref, () => ({ handle: prop }), [prop]) return <>output }) ) const ref = createRef<{ handle: string }>() let view: RenderResult | undefined await act(() => { view = render() }) if (view) { expect(view.container.textContent).toMatchInlineSnapshot('"output"') expect(ref.current?.handle).toBe('hello') await act(() => { view!.rerender() }) expect(view.container.textContent).toMatchInlineSnapshot('"output"') expect(ref.current?.handle).toBe('world') } }) test('tracked components update when the state they reference updates', async () => { const a = atom('a', 1) const C = track(function Component() { return <>{a.get()} }) let view: RenderResult | undefined await act(() => { view = render() }) if (view) { expect(view.container.textContent).toMatchInlineSnapshot(`"1"`) await act(() => { a.set(2) }) expect(view.container.textContent).toMatchInlineSnapshot(`"2"`) } }) test('things referenced in effects do not trigger updates', async () => { const a = atom('a', 1) let numRenders = 0 const Component = track(function Component() { numRenders++ useEffect(() => { a.get() }, []) return <>hi }) let view: RenderResult | undefined await act(() => { view = render() }) if (view) { expect(view.container.textContent).toMatchInlineSnapshot(`"hi"`) expect(numRenders).toBe(1) await act(() => { a.set(2) }) expect(numRenders).toBe(1) expect(view.container.textContent).toMatchInlineSnapshot(`"hi"`) } }) // test("tracked zombie-children don't throw", async () => { // const theAtom = atom>('map', { a: 1, b: 2, c: 3 }) // const Parent = track(function Parent() { // const ids = Object.keys(theAtom.get()) // return ( // <> // {ids.map((id) => ( // // ))} // // ) // }) // const Child = track(function Child({ id }: { id: string }) { // if (!(id in theAtom.get())) throw new Error('id not found!') // const value = theAtom.get()[id] // return <>{value} // }) // let view: RenderResult | undefined // await act(() => { // view = render() // }) // if (view) { // expect(view.container.textContent).toMatchInlineSnapshot(` // "1 // 2 // 3" // `) // // remove id 'b' creating a zombie-child // await act(() => { // theAtom?.update(({ b: _, ...rest }) => rest) // }) // expect(view.container.textContent).toMatchInlineSnapshot(` // "1 // 3" // `) // } // })