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 ;
}));
});