@@ -186,4 +186,225 @@ describe('ReactDOMFiber', () => {
186
186
expect ( firstNode . tagName ) . toBe ( 'DIV' ) ;
187
187
} ) ;
188
188
}
189
+
190
+ if ( ReactDOMFeatureFlags . useFiber ) {
191
+ it ( 'should render portal children' , ( ) => {
192
+ var portalContainer1 = document . createElement ( 'div' ) ;
193
+ var portalContainer2 = document . createElement ( 'div' ) ;
194
+
195
+ var ops = [ ] ;
196
+ class Child extends React . Component {
197
+ componentDidMount ( ) {
198
+ ops . push ( `${ this . props . name } componentDidMount` ) ;
199
+ }
200
+ componentDidUpdate ( ) {
201
+ ops . push ( `${ this . props . name } componentDidUpdate` ) ;
202
+ }
203
+ componentWillUnmount ( ) {
204
+ ops . push ( `${ this . props . name } componentWillUnmount` ) ;
205
+ }
206
+ render ( ) {
207
+ return < div > { this . props . name } </ div > ;
208
+ }
209
+ }
210
+
211
+ class Parent extends React . Component {
212
+ componentDidMount ( ) {
213
+ ops . push ( `Parent:${ this . props . step } componentDidMount` ) ;
214
+ }
215
+ componentDidUpdate ( ) {
216
+ ops . push ( `Parent:${ this . props . step } componentDidUpdate` ) ;
217
+ }
218
+ componentWillUnmount ( ) {
219
+ ops . push ( `Parent:${ this . props . step } componentWillUnmount` ) ;
220
+ }
221
+ render ( ) {
222
+ const { step} = this . props ;
223
+ return [
224
+ < Child name = { `normal[0]:${ step } ` } /> ,
225
+ ReactDOM . unstable_createPortal (
226
+ < Child name = { `portal1[0]:${ step } ` } /> ,
227
+ portalContainer1
228
+ ) ,
229
+ < Child name = { `normal[1]:${ step } ` } /> ,
230
+ ReactDOM . unstable_createPortal (
231
+ [
232
+ < Child name = { `portal2[0]:${ step } ` } /> ,
233
+ < Child name = { `portal2[1]:${ step } ` } /> ,
234
+ ] ,
235
+ portalContainer2
236
+ ) ,
237
+ ] ;
238
+ }
239
+ }
240
+
241
+ ReactDOM . render ( < Parent step = "a" /> , container ) ;
242
+ expect ( portalContainer1 . innerHTML ) . toBe ( '<div>portal1[0]:a</div>' ) ;
243
+ expect ( portalContainer2 . innerHTML ) . toBe ( '<div>portal2[0]:a</div><div>portal2[1]:a</div>' ) ;
244
+ expect ( container . innerHTML ) . toBe ( '<div>normal[0]:a</div><div>normal[1]:a</div>' ) ;
245
+ expect ( ops ) . toEqual ( [
246
+ 'normal[0]:a componentDidMount' ,
247
+ 'portal1[0]:a componentDidMount' ,
248
+ 'normal[1]:a componentDidMount' ,
249
+ 'portal2[0]:a componentDidMount' ,
250
+ 'portal2[1]:a componentDidMount' ,
251
+ 'Parent:a componentDidMount' ,
252
+ ] ) ;
253
+
254
+ ops . length = 0 ;
255
+ ReactDOM . render ( < Parent step = "b" /> , container ) ;
256
+ expect ( portalContainer1 . innerHTML ) . toBe ( '<div>portal1[0]:b</div>' ) ;
257
+ expect ( portalContainer2 . innerHTML ) . toBe ( '<div>portal2[0]:b</div><div>portal2[1]:b</div>' ) ;
258
+ expect ( container . innerHTML ) . toBe ( '<div>normal[0]:b</div><div>normal[1]:b</div>' ) ;
259
+ expect ( ops ) . toEqual ( [
260
+ 'normal[0]:b componentDidUpdate' ,
261
+ 'portal1[0]:b componentDidUpdate' ,
262
+ 'normal[1]:b componentDidUpdate' ,
263
+ 'portal2[0]:b componentDidUpdate' ,
264
+ 'portal2[1]:b componentDidUpdate' ,
265
+ 'Parent:b componentDidUpdate' ,
266
+ ] ) ;
267
+
268
+ ops . length = 0 ;
269
+ ReactDOM . unmountComponentAtNode ( container ) ;
270
+ expect ( portalContainer1 . innerHTML ) . toBe ( '' ) ;
271
+ expect ( portalContainer2 . innerHTML ) . toBe ( '' ) ;
272
+ expect ( container . innerHTML ) . toBe ( '' ) ;
273
+ expect ( ops ) . toEqual ( [
274
+ 'Parent:b componentWillUnmount' ,
275
+ 'normal[0]:b componentWillUnmount' ,
276
+ 'portal1[0]:b componentWillUnmount' ,
277
+ 'normal[1]:b componentWillUnmount' ,
278
+ 'portal2[0]:b componentWillUnmount' ,
279
+ 'portal2[1]:b componentWillUnmount' ,
280
+ ] ) ;
281
+ } ) ;
282
+
283
+ it ( 'should pass portal context when rendering subtree elsewhere' , ( ) => {
284
+ var portalContainer = document . createElement ( 'div' ) ;
285
+
286
+ class Component extends React . Component {
287
+ static contextTypes = {
288
+ foo : React . PropTypes . string . isRequired ,
289
+ } ;
290
+
291
+ render ( ) {
292
+ return < div > { this . context . foo } </ div > ;
293
+ }
294
+ }
295
+
296
+ class Parent extends React . Component {
297
+ static childContextTypes = {
298
+ foo : React . PropTypes . string . isRequired ,
299
+ } ;
300
+
301
+ getChildContext ( ) {
302
+ return {
303
+ foo : 'bar' ,
304
+ } ;
305
+ }
306
+
307
+ render ( ) {
308
+ return ReactDOM . unstable_createPortal (
309
+ < Component /> ,
310
+ portalContainer
311
+ ) ;
312
+ }
313
+ }
314
+
315
+ ReactDOM . render ( < Parent /> , container ) ;
316
+ expect ( container . innerHTML ) . toBe ( '' ) ;
317
+ expect ( portalContainer . innerHTML ) . toBe ( '<div>bar</div>' ) ;
318
+ } ) ;
319
+
320
+ it ( 'should update portal context if it changes due to setState' , ( ) => {
321
+ var portalContainer = document . createElement ( 'div' ) ;
322
+
323
+ class Component extends React . Component {
324
+ static contextTypes = {
325
+ foo : React . PropTypes . string . isRequired ,
326
+ getFoo : React . PropTypes . func . isRequired ,
327
+ } ;
328
+
329
+ render ( ) {
330
+ return < div > { this . context . foo + '-' + this . context . getFoo ( ) } </ div > ;
331
+ }
332
+ }
333
+
334
+ class Parent extends React . Component {
335
+ static childContextTypes = {
336
+ foo : React . PropTypes . string . isRequired ,
337
+ getFoo : React . PropTypes . func . isRequired ,
338
+ } ;
339
+
340
+ state = {
341
+ bar : 'initial' ,
342
+ } ;
343
+
344
+ getChildContext ( ) {
345
+ return {
346
+ foo : this . state . bar ,
347
+ getFoo : ( ) => this . state . bar ,
348
+ } ;
349
+ }
350
+
351
+ render ( ) {
352
+ return ReactDOM . unstable_createPortal (
353
+ < Component /> ,
354
+ portalContainer
355
+ ) ;
356
+ }
357
+ }
358
+
359
+ var instance = ReactDOM . render ( < Parent /> , container ) ;
360
+ expect ( portalContainer . innerHTML ) . toBe ( '<div>initial-initial</div>' ) ;
361
+ expect ( container . innerHTML ) . toBe ( '' ) ;
362
+ instance . setState ( { bar : 'changed' } ) ;
363
+ expect ( portalContainer . innerHTML ) . toBe ( '<div>changed-changed</div>' ) ;
364
+ expect ( container . innerHTML ) . toBe ( '' ) ;
365
+ } ) ;
366
+
367
+ it ( 'should update portal context if it changes due to re-render' , ( ) => {
368
+ var portalContainer = document . createElement ( 'div' ) ;
369
+
370
+ class Component extends React . Component {
371
+ static contextTypes = {
372
+ foo : React . PropTypes . string . isRequired ,
373
+ getFoo : React . PropTypes . func . isRequired ,
374
+ } ;
375
+
376
+ render ( ) {
377
+ return < div > { this . context . foo + '-' + this . context . getFoo ( ) } </ div > ;
378
+ }
379
+ }
380
+
381
+ class Parent extends React . Component {
382
+ static childContextTypes = {
383
+ foo : React . PropTypes . string . isRequired ,
384
+ getFoo : React . PropTypes . func . isRequired ,
385
+ } ;
386
+
387
+ getChildContext ( ) {
388
+ return {
389
+ foo : this . props . bar ,
390
+ getFoo : ( ) => this . props . bar ,
391
+ } ;
392
+ }
393
+
394
+ render ( ) {
395
+ return ReactDOM . unstable_createPortal (
396
+ < Component /> ,
397
+ portalContainer
398
+ ) ;
399
+ }
400
+ }
401
+
402
+ ReactDOM . render ( < Parent bar = "initial" /> , container ) ;
403
+ expect ( portalContainer . innerHTML ) . toBe ( '<div>initial-initial</div>' ) ;
404
+ expect ( container . innerHTML ) . toBe ( '' ) ;
405
+ ReactDOM . render ( < Parent bar = "changed" /> , container ) ;
406
+ expect ( portalContainer . innerHTML ) . toBe ( '<div>changed-changed</div>' ) ;
407
+ expect ( container . innerHTML ) . toBe ( '' ) ;
408
+ } ) ;
409
+ }
189
410
} ) ;
0 commit comments