1- import { beforeEach , describe , expect , it , vi } from 'vitest' ;
1+ import { describe , expect , it } from 'vitest' ;
22import React from 'react' ;
33import { render , screen } from '@testing-library/react' ;
44
55import { UNSAFE_PortalProvider , usePortalRoot } from '../PortalProvider' ;
6- import { portalRootManager } from '../portal-root-manager' ;
76
8- describe ( 'PortalProvider ' , ( ) => {
7+ describe ( 'UNSAFE_PortalProvider ' , ( ) => {
98 it ( 'provides getContainer to children via context' , ( ) => {
109 const container = document . createElement ( 'div' ) ;
1110 const getContainer = ( ) => container ;
@@ -24,38 +23,31 @@ describe('PortalProvider', () => {
2423 expect ( screen . getByTestId ( 'test' ) . textContent ) . toBe ( 'found' ) ;
2524 } ) ;
2625
27- it ( 'registers with portalRootManager on mount ' , ( ) => {
26+ it ( 'only affects components within the provider ' , ( ) => {
2827 const container = document . createElement ( 'div' ) ;
2928 const getContainer = ( ) => container ;
30- const pushSpy = vi . spyOn ( portalRootManager , 'push' ) ;
3129
32- const { unmount } = render (
33- < UNSAFE_PortalProvider getContainer = { getContainer } >
34- < div > test</ div >
35- </ UNSAFE_PortalProvider > ,
36- ) ;
37-
38- expect ( pushSpy ) . toHaveBeenCalledTimes ( 1 ) ;
39- expect ( portalRootManager . getCurrent ( ) ) . toBe ( container ) ;
40-
41- unmount ( ) ;
42- } ) ;
30+ const InsideComponent = ( ) => {
31+ const portalRoot = usePortalRoot ( ) ;
32+ return < div data-testid = 'inside' > { portalRoot ( ) === container ? 'container' : 'null' } </ div > ;
33+ } ;
4334
44- it ( 'unregisters from portalRootManager on unmount' , ( ) => {
45- const container = document . createElement ( 'div' ) ;
46- const getContainer = ( ) => container ;
47- const popSpy = vi . spyOn ( portalRootManager , 'pop' ) ;
35+ const OutsideComponent = ( ) => {
36+ const portalRoot = usePortalRoot ( ) ;
37+ return < div data-testid = 'outside' > { portalRoot ( ) === null ? 'null' : ' container' } </ div > ;
38+ } ;
4839
49- const { unmount } = render (
50- < UNSAFE_PortalProvider getContainer = { getContainer } >
51- < div > test</ div >
52- </ UNSAFE_PortalProvider > ,
40+ render (
41+ < >
42+ < OutsideComponent />
43+ < UNSAFE_PortalProvider getContainer = { getContainer } >
44+ < InsideComponent />
45+ </ UNSAFE_PortalProvider >
46+ </ > ,
5347 ) ;
5448
55- unmount ( ) ;
56-
57- expect ( popSpy ) . toHaveBeenCalledTimes ( 1 ) ;
58- expect ( portalRootManager . getCurrent ( ) ) . toBeNull ( ) ;
49+ expect ( screen . getByTestId ( 'inside' ) . textContent ) . toBe ( 'container' ) ;
50+ expect ( screen . getByTestId ( 'outside' ) . textContent ) . toBe ( 'null' ) ;
5951 } ) ;
6052} ) ;
6153
@@ -78,103 +70,34 @@ describe('usePortalRoot', () => {
7870 expect ( screen . getByTestId ( 'test' ) . textContent ) . toBe ( 'found' ) ;
7971 } ) ;
8072
81- it ( 'returns manager.getCurrent when outside PortalProvider' , ( ) => {
82- const container = document . createElement ( 'div' ) ;
83- portalRootManager . push ( ( ) => container ) ;
84-
73+ it ( 'returns a function that returns null when outside PortalProvider' , ( ) => {
8574 const TestComponent = ( ) => {
8675 const portalRoot = usePortalRoot ( ) ;
87- return < div data-testid = 'test' > { portalRoot ( ) === container ? 'found ' : 'not-found ' } </ div > ;
76+ return < div data-testid = 'test' > { portalRoot ( ) === null ? 'null ' : 'not-null ' } </ div > ;
8877 } ;
8978
9079 render ( < TestComponent /> ) ;
9180
92- expect ( screen . getByTestId ( 'test' ) . textContent ) . toBe ( 'found' ) ;
93-
94- portalRootManager . pop ( ) ;
81+ expect ( screen . getByTestId ( 'test' ) . textContent ) . toBe ( 'null' ) ;
9582 } ) ;
9683
97- it ( 'context value takes precedence over manager' , ( ) => {
98- const contextContainer = document . createElement ( 'div' ) ;
99- const managerContainer = document . createElement ( 'div' ) ;
100- const contextGetContainer = ( ) => contextContainer ;
101-
102- portalRootManager . push ( ( ) => managerContainer ) ;
84+ it ( 'supports nested providers with innermost taking precedence' , ( ) => {
85+ const outerContainer = document . createElement ( 'div' ) ;
86+ const innerContainer = document . createElement ( 'div' ) ;
10387
10488 const TestComponent = ( ) => {
10589 const portalRoot = usePortalRoot ( ) ;
106- return < div data-testid = 'test' > { portalRoot ( ) === contextContainer ? 'found ' : 'not-found ' } </ div > ;
90+ return < div data-testid = 'test' > { portalRoot ( ) === innerContainer ? 'inner ' : 'outer ' } </ div > ;
10791 } ;
10892
10993 render (
110- < UNSAFE_PortalProvider getContainer = { contextGetContainer } >
111- < TestComponent />
94+ < UNSAFE_PortalProvider getContainer = { ( ) => outerContainer } >
95+ < UNSAFE_PortalProvider getContainer = { ( ) => innerContainer } >
96+ < TestComponent />
97+ </ UNSAFE_PortalProvider >
11298 </ UNSAFE_PortalProvider > ,
11399 ) ;
114100
115- expect ( screen . getByTestId ( 'test' ) . textContent ) . toBe ( 'found' ) ;
116-
117- portalRootManager . pop ( ) ;
118- } ) ;
119- } ) ;
120-
121- describe ( 'portalRootManager' , ( ) => {
122- beforeEach ( ( ) => {
123- // Clear the stack before each test
124- while ( portalRootManager . getCurrent ( ) !== null ) {
125- portalRootManager . pop ( ) ;
126- }
127- } ) ;
128-
129- it ( 'maintains stack of portal roots' , ( ) => {
130- const container1 = document . createElement ( 'div' ) ;
131- const container2 = document . createElement ( 'div' ) ;
132- const getContainer1 = ( ) => container1 ;
133- const getContainer2 = ( ) => container2 ;
134-
135- portalRootManager . push ( getContainer1 ) ;
136- portalRootManager . push ( getContainer2 ) ;
137-
138- expect ( portalRootManager . getCurrent ( ) ) . toBe ( container2 ) ;
139-
140- portalRootManager . pop ( ) ;
141- expect ( portalRootManager . getCurrent ( ) ) . toBe ( container1 ) ;
142-
143- portalRootManager . pop ( ) ;
144- } ) ;
145-
146- it ( 'getCurrent returns topmost root' , ( ) => {
147- const container1 = document . createElement ( 'div' ) ;
148- const container2 = document . createElement ( 'div' ) ;
149- const getContainer1 = ( ) => container1 ;
150- const getContainer2 = ( ) => container2 ;
151-
152- portalRootManager . push ( getContainer1 ) ;
153- portalRootManager . push ( getContainer2 ) ;
154-
155- expect ( portalRootManager . getCurrent ( ) ) . toBe ( container2 ) ;
156-
157- portalRootManager . pop ( ) ;
158- portalRootManager . pop ( ) ;
159- } ) ;
160-
161- it ( 'pop removes topmost root' , ( ) => {
162- const container1 = document . createElement ( 'div' ) ;
163- const container2 = document . createElement ( 'div' ) ;
164- const getContainer1 = ( ) => container1 ;
165- const getContainer2 = ( ) => container2 ;
166-
167- portalRootManager . push ( getContainer1 ) ;
168- portalRootManager . push ( getContainer2 ) ;
169-
170- portalRootManager . pop ( ) ;
171-
172- expect ( portalRootManager . getCurrent ( ) ) . toBe ( container1 ) ;
173-
174- portalRootManager . pop ( ) ;
175- } ) ;
176-
177- it ( 'getCurrent returns null when stack is empty' , ( ) => {
178- expect ( portalRootManager . getCurrent ( ) ) . toBeNull ( ) ;
101+ expect ( screen . getByTestId ( 'test' ) . textContent ) . toBe ( 'inner' ) ;
179102 } ) ;
180103} ) ;
0 commit comments