-
Notifications
You must be signed in to change notification settings - Fork 456
Expand file tree
/
Copy pathuseCustomElementPortal.test.tsx
More file actions
115 lines (87 loc) · 3.14 KB
/
Copy pathuseCustomElementPortal.test.tsx
File metadata and controls
115 lines (87 loc) · 3.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { render, screen } from '@testing-library/react';
import React, { useEffect } from 'react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { useCustomElementPortal } from '../useCustomElementPortal';
describe('useCustomElementPortal', () => {
let portalRoot: HTMLDivElement;
afterEach(() => {
portalRoot?.remove();
});
it('does not remount portal content when the parent rerenders', async () => {
const mountTracker = vi.fn();
const unmountTracker = vi.fn();
const CustomContent = ({ label }: { label: string }) => {
useEffect(() => {
mountTracker();
return unmountTracker;
}, []);
return <div>{label}</div>;
};
const TestComponent = ({ label }: { label: string }) => {
const [{ mount, portal: Portal, unmount }] = useCustomElementPortal([
{ component: <CustomContent label={label} />, id: 0 },
]);
useEffect(() => {
mount(portalRoot);
return unmount;
}, [mount, unmount]);
return <Portal />;
};
portalRoot = document.createElement('div');
document.body.appendChild(portalRoot);
const { rerender } = render(<TestComponent label='first render' />);
await screen.findByText('first render');
expect(mountTracker).toHaveBeenCalledTimes(1);
rerender(<TestComponent label='second render' />);
await screen.findByText('second render');
expect(mountTracker).toHaveBeenCalledTimes(1);
expect(unmountTracker).not.toHaveBeenCalled();
expect(portalRoot.textContent).toBe('second render');
});
it('renders falsy ReactNode values after mounting', async () => {
const TestComponent = () => {
const [{ mount, portal: Portal, unmount }] = useCustomElementPortal([{ component: 0, id: 0 }]);
useEffect(() => {
mount(portalRoot);
return unmount;
}, [mount, unmount]);
return <Portal />;
};
portalRoot = document.createElement('div');
document.body.appendChild(portalRoot);
render(<TestComponent />);
await screen.findByText('0');
expect(portalRoot.textContent).toBe('0');
});
it('keeps string and number ids in separate portal caches', async () => {
const TestComponent = () => {
const [
{ mount: mountNumber, portal: NumberPortal, unmount: unmountNumber },
{ mount: mountString, portal: StringPortal, unmount: unmountString },
] = useCustomElementPortal([
{ component: <div>number id</div>, id: 1 },
{ component: <div>string id</div>, id: '1' },
]);
useEffect(() => {
mountNumber(portalRoot);
mountString(portalRoot);
return () => {
unmountNumber();
unmountString();
};
}, [mountNumber, mountString, unmountNumber, unmountString]);
return (
<>
<NumberPortal />
<StringPortal />
</>
);
};
portalRoot = document.createElement('div');
document.body.appendChild(portalRoot);
render(<TestComponent />);
await screen.findByText('number id');
await screen.findByText('string id');
expect(portalRoot.textContent).toBe('number idstring id');
});
});