import { jest } from '@jest/globals'; import { waitFor } from '@testing-library/react'; import type { ComponentType } from 'react'; import React from 'react'; import { runInDom } from '../../../__test_dependency__/run-in-dom.js'; import type { Binding } from '../../../binding/types/binding'; import { useBinding } from '../../../binding/use-binding.js'; import { BindingsConsumer } from '../index.js'; describe('BindingsConsumer', () => { it('nested initial render should work', () => runInDom(({ onMount }) => { const MyComponent: ComponentType = jest.fn(() => { const b1 = useBinding(() => 0, { id: 'test1' }); const b2 = useBinding(() => 0, { id: 'test2' }); return ( {({ b1 }) => ( {({ b2 }) => ( {b1}-{b2} )} )} ); }); onMount((rootElement) => { expect(MyComponent).toHaveBeenCalledTimes(1); expect(rootElement.innerHTML).toBe('
0-0
'); }); return ; })); it('updating inner binding should rerender just inner', () => runInDom(({ onMount }) => { let b1: Binding; let b2: Binding; const consumer2Renderer = jest.fn(({ b2 }: { b2: number }) => {b2}); const consumer1Renderer = jest.fn(({ b1: _b1 }: { b1: number }) => { return {consumer2Renderer}; }); const MyComponent: ComponentType = jest.fn(() => { b1 = useBinding(() => 0, { id: 'test1' }); b2 = useBinding(() => 0, { id: 'test2' }); return {consumer1Renderer}; }); onMount(async (rootElement) => { expect(MyComponent).toHaveBeenCalledTimes(1); expect(consumer1Renderer).toHaveBeenCalledTimes(1); expect(consumer2Renderer).toHaveBeenCalledTimes(1); expect(rootElement.innerHTML).toBe('
0
'); b2.set(1); await waitFor(() => expect(rootElement.innerHTML).toBe('
1
')); expect(MyComponent).toHaveBeenCalledTimes(1); expect(consumer1Renderer).toHaveBeenCalledTimes(1); expect(consumer2Renderer).toHaveBeenCalledTimes(2); }); return ; })); it('updating outer binding should rerender both outer and inner', () => runInDom(({ onMount }) => { let b1: Binding; let b2: Binding; const consumer2Renderer = jest.fn(({ b2 }: { b2: number }) => {b2}); const consumer1Renderer = jest.fn(({ b1: _b1 }: { b1: number }) => { return {consumer2Renderer}; }); const MyComponent: ComponentType = jest.fn(() => { b1 = useBinding(() => 0, { id: 'test1' }); b2 = useBinding(() => 0, { id: 'test2' }); return {consumer1Renderer}; }); onMount(async (rootElement) => { expect(MyComponent).toHaveBeenCalledTimes(1); expect(consumer1Renderer).toHaveBeenCalledTimes(1); expect(consumer2Renderer).toHaveBeenCalledTimes(1); expect(rootElement.innerHTML).toBe('
0
'); b1.set(1); await waitFor(() => expect(consumer1Renderer).toHaveBeenCalledTimes(2)); expect(MyComponent).toHaveBeenCalledTimes(1); expect(consumer2Renderer).toHaveBeenCalledTimes(2); expect(rootElement.innerHTML).toBe('
0
'); }); return ; })); it('quickly updating both inner and outer bindings should rerender both outer and inner, but just once', () => runInDom(({ onMount }) => { let b1: Binding; let b2: Binding; const consumer2Renderer = jest.fn(({ b2 }: { b2: number }) => {b2}); const consumer1Renderer = jest.fn(({ b1: _b1 }: { b1: number }) => { return {consumer2Renderer}; }); const MyComponent: ComponentType = jest.fn(() => { b1 = useBinding(() => 0, { id: 'test1' }); b2 = useBinding(() => 0, { id: 'test2' }); return {consumer1Renderer}; }); onMount(async (rootElement) => { expect(MyComponent).toHaveBeenCalledTimes(1); expect(consumer1Renderer).toHaveBeenCalledTimes(1); expect(consumer2Renderer).toHaveBeenCalledTimes(1); expect(rootElement.innerHTML).toBe('
0
'); b1.set(1); b2.set(2); await waitFor(() => expect(rootElement.innerHTML).toBe('
2
')); expect(MyComponent).toHaveBeenCalledTimes(1); expect(consumer1Renderer).toHaveBeenCalledTimes(2); expect(consumer2Renderer).toHaveBeenCalledTimes(2); }); return ; })); });