@@ -2715,4 +2715,72 @@ describe('ReactIncremental', () => {
27152715
27162716 expect ( ReactNoop . flush ( ) ) . toEqual ( [ ] ) ;
27172717 } ) ;
2718+
2719+ it ( 'does not break with a bad Map polyfill' , ( ) => {
2720+ const realMapSet = Map . prototype . set ;
2721+
2722+ function triggerCodePathThatUsesFibersAsMapKeys ( ) {
2723+ function Thing ( ) {
2724+ throw new Error ( 'No.' ) ;
2725+ }
2726+ class Boundary extends React . Component {
2727+ state = { didError : false } ;
2728+ componentDidCatch ( ) {
2729+ this . setState ( { didError : true } ) ;
2730+ }
2731+ render ( ) {
2732+ return this . state . didError ? null : < Thing /> ;
2733+ }
2734+ }
2735+ ReactNoop . render ( < Boundary /> ) ;
2736+ ReactNoop . flush ( ) ;
2737+ }
2738+
2739+ // First, verify that this code path normally receives Fibers as keys,
2740+ // and that they're not extensible.
2741+ jest . resetModules ( ) ;
2742+ let receivedNonExtensibleObjects ;
2743+ Map . prototype . set = function ( key ) {
2744+ if ( typeof key === 'object' && key !== null ) {
2745+ if ( ! Object . isExtensible ( key ) ) {
2746+ receivedNonExtensibleObjects = true ;
2747+ }
2748+ }
2749+ return realMapSet . apply ( this , arguments ) ;
2750+ } ;
2751+ React = require ( 'react' ) ;
2752+ ReactNoop = require ( 'react-noop-renderer' ) ;
2753+ try {
2754+ receivedNonExtensibleObjects = false ;
2755+ triggerCodePathThatUsesFibersAsMapKeys ( ) ;
2756+ } finally {
2757+ Map . prototype . set = realMapSet ;
2758+ }
2759+ // If this fails, find another code path in Fiber
2760+ // that passes Fibers as keys to Maps.
2761+ // Note that we only expect them to be non-extensible
2762+ // in development.
2763+ expect ( receivedNonExtensibleObjects ) . toBe ( __DEV__ ) ;
2764+
2765+ // Next, verify that a Map polyfill that "writes" to keys
2766+ // doesn't cause a failure.
2767+ jest . resetModules ( ) ;
2768+ Map . prototype . set = function ( key , value ) {
2769+ if ( typeof key === 'object' && key !== null ) {
2770+ // A polyfill could do something like this.
2771+ // It would throw if an object is not extensible.
2772+ key . __internalValueSlot = value ;
2773+ }
2774+ } ;
2775+ React = require ( 'react' ) ;
2776+ ReactNoop = require ( 'react-noop-renderer' ) ;
2777+ try {
2778+ triggerCodePathThatUsesFibersAsMapKeys ( ) ;
2779+ } finally {
2780+ Map . prototype . set = realMapSet ;
2781+ }
2782+ // If we got this far, our feature detection worked.
2783+ // We knew that Map#set() throws for non-extensible objects,
2784+ // so we didn't set them as non-extensible for that reason.
2785+ } ) ;
27182786} ) ;
0 commit comments