diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js index 0595f868b14fd..bf91fb08dda10 100644 --- a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js @@ -587,6 +587,7 @@ describe('ReactCompositeComponent', () => { ); }); + // @gate !disableLegacyContext it('should pass context to children when not owner', () => { class Parent extends React.Component { render() { @@ -652,6 +653,7 @@ describe('ReactCompositeComponent', () => { expect(childRenders).toBe(1); }); + // @gate !disableLegacyContext it('should pass context when re-rendered for static child', () => { let parentInstance = null; let childInstance = null; @@ -712,6 +714,7 @@ describe('ReactCompositeComponent', () => { expect(childInstance.context).toEqual({foo: 'bar', flag: true}); }); + // @gate !disableLegacyContext it('should pass context when re-rendered for static child within a composite component', () => { class Parent extends React.Component { static childContextTypes = { @@ -768,6 +771,7 @@ describe('ReactCompositeComponent', () => { expect(wrapper.childRef.current.context).toEqual({flag: false}); }); + // @gate !disableLegacyContext it('should pass context transitively', () => { let childInstance = null; let grandchildInstance = null; @@ -829,6 +833,7 @@ describe('ReactCompositeComponent', () => { expect(grandchildInstance.context).toEqual({foo: 'bar', depth: 1}); }); + // @gate !disableLegacyContext it('should pass context when re-rendered', () => { let parentInstance = null; let childInstance = null; @@ -883,6 +888,7 @@ describe('ReactCompositeComponent', () => { expect(childInstance.context).toEqual({foo: 'bar', depth: 0}); }); + // @gate !disableLegacyContext it('unmasked context propagates through updates', () => { class Leaf extends React.Component { static contextTypes = { @@ -946,6 +952,7 @@ describe('ReactCompositeComponent', () => { expect(div.children[0].id).toBe('aliens'); }); + // @gate !disableLegacyContext it('should trigger componentWillReceiveProps for context changes', () => { let contextChanges = 0; let propChanges = 0; @@ -1219,6 +1226,7 @@ describe('ReactCompositeComponent', () => { expect(a).toBe(b); }); + // @gate !disableLegacyContext || !__DEV__ it('context should be passed down from the parent', () => { class Parent extends React.Component { static childContextTypes = { diff --git a/packages/react-dom/src/__tests__/ReactDOMFiber-test.js b/packages/react-dom/src/__tests__/ReactDOMFiber-test.js index 865337e8b5470..06773b68f1f55 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiber-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiber-test.js @@ -718,6 +718,7 @@ describe('ReactDOMFiber', () => { ); }); + // @gate !disableLegacyContext it('should pass portal context when rendering subtree elsewhere', () => { const portalContainer = document.createElement('div'); @@ -752,6 +753,7 @@ describe('ReactDOMFiber', () => { expect(portalContainer.innerHTML).toBe('
bar
'); }); + // @gate !disableLegacyContext it('should update portal context if it changes due to setState', () => { const portalContainer = document.createElement('div'); @@ -796,6 +798,7 @@ describe('ReactDOMFiber', () => { expect(container.innerHTML).toBe(''); }); + // @gate !disableLegacyContext it('should update portal context if it changes due to re-render', () => { const portalContainer = document.createElement('div'); diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index d4c5a0bf8f298..e745835c1601a 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -1624,6 +1624,7 @@ describe('ReactDOMFizzServer', () => { } }); + // @gate !disableLegacyContext it('should can suspend in a class component with legacy context', async () => { class TestProvider extends React.Component { static childContextTypes = { diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js index 5681f0806b434..1481fcd326bb0 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js @@ -44,6 +44,13 @@ describe('ReactDOMServerIntegration', () => { }); describe('legacy context', function () { + // The `itRenders` test abstraction doesn't work with @gate so we have + // to do this instead. + if (gate(flags => flags.disableLegacyContext)) { + test('empty test to stop Jest from being a complainy complainer', () => {}); + return; + } + let PurpleContext, RedContext; beforeEach(() => { class Parent extends React.Component { diff --git a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js index 04cb8bbc1e492..1431205b28f36 100644 --- a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js @@ -775,6 +775,7 @@ describe('ReactErrorBoundaries', () => { assertLog(['ErrorBoundary componentWillUnmount']); }); + // @gate !disableLegacyContext || !__DEV__ it('renders an error state if context provider throws in componentWillMount', () => { class BrokenComponentWillMountWithContext extends React.Component { static childContextTypes = {foo: PropTypes.number}; @@ -799,45 +800,45 @@ describe('ReactErrorBoundaries', () => { expect(container.firstChild.textContent).toBe('Caught an error: Hello.'); }); - if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) { - it('renders an error state if module-style context provider throws in componentWillMount', () => { - function BrokenComponentWillMountWithContext() { - return { - getChildContext() { - return {foo: 42}; - }, - render() { - return
{this.props.children}
; - }, - UNSAFE_componentWillMount() { - throw new Error('Hello'); - }, - }; - } - BrokenComponentWillMountWithContext.childContextTypes = { - foo: PropTypes.number, + // @gate !disableModulePatternComponents + // @gate !disableLegacyContext + it('renders an error state if module-style context provider throws in componentWillMount', () => { + function BrokenComponentWillMountWithContext() { + return { + getChildContext() { + return {foo: 42}; + }, + render() { + return
{this.props.children}
; + }, + UNSAFE_componentWillMount() { + throw new Error('Hello'); + }, }; + } + BrokenComponentWillMountWithContext.childContextTypes = { + foo: PropTypes.number, + }; - const container = document.createElement('div'); - expect(() => - ReactDOM.render( - - - , - container, - ), - ).toErrorDev( - 'Warning: The component appears to be a function component that ' + - 'returns a class instance. ' + - 'Change BrokenComponentWillMountWithContext to a class that extends React.Component instead. ' + - "If you can't use a class try assigning the prototype on the function as a workaround. " + - '`BrokenComponentWillMountWithContext.prototype = React.Component.prototype`. ' + - "Don't use an arrow function since it cannot be called with `new` by React.", - ); + const container = document.createElement('div'); + expect(() => + ReactDOM.render( + + + , + container, + ), + ).toErrorDev( + 'Warning: The component appears to be a function component that ' + + 'returns a class instance. ' + + 'Change BrokenComponentWillMountWithContext to a class that extends React.Component instead. ' + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + '`BrokenComponentWillMountWithContext.prototype = React.Component.prototype`. ' + + "Don't use an arrow function since it cannot be called with `new` by React.", + ); - expect(container.firstChild.textContent).toBe('Caught an error: Hello.'); - }); - } + expect(container.firstChild.textContent).toBe('Caught an error: Hello.'); + }); it('mounts the error message if mounting fails', () => { function renderError(error) { diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js index f3bdb85ab7185..b30293f548b50 100644 --- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js @@ -59,6 +59,7 @@ describe('ReactFunctionComponent', () => { expect(container.textContent).toBe(''); }); + // @gate !disableLegacyContext it('should pass context thru stateless component', () => { class Child extends React.Component { static contextTypes = { @@ -305,6 +306,7 @@ describe('ReactFunctionComponent', () => { // This guards against a regression caused by clearing the current debug fiber. // https://github.com/facebook/react/issues/10831 + // @gate !disableLegacyContext || !__DEV__ it('should warn when giving a function ref with context', () => { function Child() { return null; @@ -375,6 +377,7 @@ describe('ReactFunctionComponent', () => { ]); }); + // @gate !disableLegacyContext it('should receive context', () => { class Parent extends React.Component { static childContextTypes = { diff --git a/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js index f833ed39ed948..fb5c827b3ae27 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactLegacyErrorBoundaries-test.internal.js @@ -800,6 +800,7 @@ describe('ReactLegacyErrorBoundaries', () => { expect(log).toEqual(['ErrorBoundary componentWillUnmount']); }); + // @gate !disableLegacyContext || !__DEV__ it('renders an error state if context provider throws in componentWillMount', () => { class BrokenComponentWillMountWithContext extends React.Component { static childContextTypes = {foo: PropTypes.number}; diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js index 40c8248ee14c6..02f02187cb351 100644 --- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js @@ -340,6 +340,7 @@ describe('ReactDOMServer', () => { expect(markup).toContain('hello, world'); }); + // @gate !disableLegacyContext it('renders with context when using custom constructor', () => { class Component extends React.Component { constructor() { diff --git a/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js b/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js index 288a72818e6bb..49993b556ea22 100644 --- a/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js +++ b/packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js @@ -17,6 +17,7 @@ const renderSubtreeIntoContainer = require('react-dom').unstable_renderSubtreeIntoContainer; describe('renderSubtreeIntoContainer', () => { + // @gate !disableLegacyContext it('should pass context when rendering subtree elsewhere', () => { const portal = document.createElement('div'); @@ -99,6 +100,7 @@ describe('renderSubtreeIntoContainer', () => { } }); + // @gate !disableLegacyContext it('should update context if it changes due to setState', () => { const container = document.createElement('div'); document.body.appendChild(container); @@ -159,6 +161,7 @@ describe('renderSubtreeIntoContainer', () => { expect(portal.firstChild.innerHTML).toBe('changed-changed'); }); + // @gate !disableLegacyContext it('should update context if it changes due to re-render', () => { const container = document.createElement('div'); document.body.appendChild(container); @@ -238,6 +241,7 @@ describe('renderSubtreeIntoContainer', () => { expect(portal.firstChild.innerHTML).toBe('hello'); }); + // @gate !disableLegacyContext it('should get context through non-context-provider parent', () => { const container = document.createElement('div'); document.body.appendChild(container); @@ -281,6 +285,7 @@ describe('renderSubtreeIntoContainer', () => { expect(portal.textContent).toBe('foo'); }); + // @gate !disableLegacyContext it('should get context through middle non-context-provider layer', () => { const container = document.createElement('div'); document.body.appendChild(container); diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js index c044be590a8f6..56a1d6fb7c1a9 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeEvents-test.internal.js @@ -197,6 +197,7 @@ it('handles events', () => { ]); }); +// @gate !disableLegacyContext || !__DEV__ it('handles events on text nodes', () => { expect(RCTEventEmitter.register).toHaveBeenCalledTimes(1); const EventEmitter = RCTEventEmitter.register.mock.calls[0][0]; diff --git a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js index 885955273c967..fbfaba83ff187 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncremental-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncremental-test.js @@ -1683,6 +1683,7 @@ describe('ReactIncremental', () => { expect(instance.state.n).toEqual(3); }); + // @gate !disableLegacyContext it('merges and masks context', async () => { class Intl extends React.Component { static childContextTypes = { @@ -1830,7 +1831,11 @@ describe('ReactIncremental', () => { ]); }); + // @gate !disableLegacyContext it('does not leak own context into context provider', async () => { + if (gate(flags => flags.disableLegacyContext)) { + throw new Error('This test infinite loops when context is disabled.'); + } class Recurse extends React.Component { static contextTypes = { n: PropTypes.number, @@ -1859,49 +1864,50 @@ describe('ReactIncremental', () => { ]); }); - if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) { - it('does not leak own context into context provider (factory components)', async () => { - function Recurse(props, context) { - return { - getChildContext() { - return {n: (context.n || 3) - 1}; - }, - render() { - Scheduler.log('Recurse ' + JSON.stringify(context)); - if (context.n === 0) { - return null; - } - return ; - }, - }; - } - Recurse.contextTypes = { - n: PropTypes.number, - }; - Recurse.childContextTypes = { - n: PropTypes.number, + // @gate !disableModulePatternComponents + // @gate !disableLegacyContext + it('does not leak own context into context provider (factory components)', async () => { + function Recurse(props, context) { + return { + getChildContext() { + return {n: (context.n || 3) - 1}; + }, + render() { + Scheduler.log('Recurse ' + JSON.stringify(context)); + if (context.n === 0) { + return null; + } + return ; + }, }; + } + Recurse.contextTypes = { + n: PropTypes.number, + }; + Recurse.childContextTypes = { + n: PropTypes.number, + }; - ReactNoop.render(); - await expect( - async () => - await waitForAll([ - 'Recurse {}', - 'Recurse {"n":2}', - 'Recurse {"n":1}', - 'Recurse {"n":0}', - ]), - ).toErrorDev([ - 'Warning: The component appears to be a function component that returns a class instance. ' + - 'Change Recurse to a class that extends React.Component instead. ' + - "If you can't use a class try assigning the prototype on the function as a workaround. " + - '`Recurse.prototype = React.Component.prototype`. ' + - "Don't use an arrow function since it cannot be called with `new` by React.", - ]); - }); - } + ReactNoop.render(); + await expect( + async () => + await waitForAll([ + 'Recurse {}', + 'Recurse {"n":2}', + 'Recurse {"n":1}', + 'Recurse {"n":0}', + ]), + ).toErrorDev([ + 'Warning: The component appears to be a function component that returns a class instance. ' + + 'Change Recurse to a class that extends React.Component instead. ' + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + '`Recurse.prototype = React.Component.prototype`. ' + + "Don't use an arrow function since it cannot be called with `new` by React.", + ]); + }); // @gate www + // @gate !disableLegacyContext it('provides context when reusing work', async () => { class Intl extends React.Component { static childContextTypes = { @@ -1955,6 +1961,7 @@ describe('ReactIncremental', () => { ]); }); + // @gate !disableLegacyContext it('reads context when setState is below the provider', async () => { let statefulInst; @@ -2041,6 +2048,7 @@ describe('ReactIncremental', () => { assertLog([]); }); + // @gate !disableLegacyContext it('reads context when setState is above the provider', async () => { let statefulInst; @@ -2135,6 +2143,7 @@ describe('ReactIncremental', () => { ]); }); + // @gate !disableLegacyContext || !__DEV__ it('maintains the correct context when providers bail out due to low priority', async () => { class Root extends React.Component { render() { @@ -2178,6 +2187,7 @@ describe('ReactIncremental', () => { await waitForAll([]); }); + // @gate !disableLegacyContext || !__DEV__ it('maintains the correct context when unwinding due to an error in render', async () => { class Root extends React.Component { componentDidCatch(error) { @@ -2229,6 +2239,7 @@ describe('ReactIncremental', () => { ); }); + // @gate !disableLegacyContext || !__DEV__ it('should not recreate masked context unless inputs have changed', async () => { let scuCounter = 0; @@ -2354,6 +2365,7 @@ describe('ReactIncremental', () => { expect(cduNextProps).toEqual([{children: 'B'}]); }); + // @gate !disableLegacyContext it('updates descendants with new context values', async () => { let instance; @@ -2403,6 +2415,7 @@ describe('ReactIncremental', () => { await waitForAll(['count:1']); }); + // @gate !disableLegacyContext it('updates descendants with multiple context-providing ancestors with new context values', async () => { let instance; @@ -2458,6 +2471,7 @@ describe('ReactIncremental', () => { await waitForAll(['count:1']); }); + // @gate !disableLegacyContext it('should not update descendants with new context values if shouldComponentUpdate returns false', async () => { let instance; @@ -2522,6 +2536,7 @@ describe('ReactIncremental', () => { await waitForAll([]); }); + // @gate !disableLegacyContext it('should update descendants with new context values if setState() is called in the middle of the tree', async () => { let middleInstance; let topInstance; @@ -2667,6 +2682,7 @@ describe('ReactIncremental', () => { }); // We sometimes use Maps with Fibers as keys. + // @gate !disableLegacyContext || !__DEV__ it('does not break with a bad Map polyfill', async () => { const realMapSet = Map.prototype.set; diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index e97476b71b580..2b274484bc625 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -1159,6 +1159,12 @@ describe('ReactIncrementalErrorHandling', () => { expect(ReactNoop.getChildrenAsJSX('f')).toEqual(null); }); + // NOTE: When legacy context is removed, it's probably fine to just delete + // this test. There's plenty of test coverage of stack unwinding in general + // because it's used for new context, suspense, and many other features. + // It has to be tested independently for each feature anyway. So although it + // doesn't look like it, this test is specific to legacy context. + // @gate !disableLegacyContext it('unwinds the context stack correctly on error', async () => { class Provider extends React.Component { static childContextTypes = {message: PropTypes.string}; diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js index 6fc22f00e6d6f..cedf698148ee1 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js @@ -984,6 +984,7 @@ describe('ReactNewContext', () => { expect(ReactNoop).toMatchRenderedOutput(); }); + // @gate !disableLegacyContext it('provider does not bail out if legacy context changed above', async () => { const Context = React.createContext(0); diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index 928ddb8959a5d..78a7ecafd9799 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -11,6 +11,8 @@ ReactDOM = null ReactDOMClient = null act = null +featureFlags = require 'shared/ReactFeatureFlags' + describe 'ReactCoffeeScriptClass', -> container = null root = null @@ -216,36 +218,37 @@ describe 'ReactCoffeeScriptClass', -> test React.createElement(Foo, update: false), 'DIV', 'initial' test React.createElement(Foo, update: true), 'DIV', 'updated' - it 'renders based on context in the constructor', -> - class Foo extends React.Component - @contextTypes: - tag: PropTypes.string - className: PropTypes.string + if !featureFlags.disableLegacyContext + it 'renders based on context in the constructor', -> + class Foo extends React.Component + @contextTypes: + tag: PropTypes.string + className: PropTypes.string - constructor: (props, context) -> - super props, context - @state = - tag: context.tag - className: @context.className + constructor: (props, context) -> + super props, context + @state = + tag: context.tag + className: @context.className - render: -> - Tag = @state.tag - React.createElement Tag, - className: @state.className + render: -> + Tag = @state.tag + React.createElement Tag, + className: @state.className - class Outer extends React.Component - @childContextTypes: - tag: PropTypes.string - className: PropTypes.string + class Outer extends React.Component + @childContextTypes: + tag: PropTypes.string + className: PropTypes.string - getChildContext: -> - tag: 'span' - className: 'foo' + getChildContext: -> + tag: 'span' + className: 'foo' - render: -> - React.createElement Foo + render: -> + React.createElement Foo - test React.createElement(Outer), 'SPAN', 'foo' + test React.createElement(Outer), 'SPAN', 'foo' it 'renders only once when setting state in componentWillMount', -> renderCount = 0 @@ -395,40 +398,41 @@ describe 'ReactCoffeeScriptClass', -> root.unmount() expect(lifeCycles).toEqual ['will-unmount'] - it 'warns when classic properties are defined on the instance, - but does not invoke them.', -> - getInitialStateWasCalled = false - getDefaultPropsWasCalled = false - class Foo extends React.Component - constructor: -> - @contextTypes = {} - @contextType = {} - @propTypes = {} + if !featureFlags.disableLegacyContext + it 'warns when classic properties are defined on the instance, + but does not invoke them.', -> + getInitialStateWasCalled = false + getDefaultPropsWasCalled = false + class Foo extends React.Component + constructor: -> + @contextTypes = {} + @contextType = {} + @propTypes = {} - getInitialState: -> - getInitialStateWasCalled = true - {} + getInitialState: -> + getInitialStateWasCalled = true + {} - getDefaultProps: -> - getDefaultPropsWasCalled = true - {} + getDefaultProps: -> + getDefaultPropsWasCalled = true + {} - render: -> - React.createElement('span', - className: 'foo' - ) + render: -> + React.createElement('span', + className: 'foo' + ) - expect(-> - test React.createElement(Foo), 'SPAN', 'foo' - ).toErrorDev([ - 'getInitialState was defined on Foo, a plain JavaScript class.', - 'getDefaultProps was defined on Foo, a plain JavaScript class.', - 'propTypes was defined as an instance property on Foo.', - 'contextTypes was defined as an instance property on Foo.', - 'contextType was defined as an instance property on Foo.', - ]) - expect(getInitialStateWasCalled).toBe false - expect(getDefaultPropsWasCalled).toBe false + expect(-> + test React.createElement(Foo), 'SPAN', 'foo' + ).toErrorDev([ + 'getInitialState was defined on Foo, a plain JavaScript class.', + 'getDefaultProps was defined on Foo, a plain JavaScript class.', + 'propTypes was defined as an instance property on Foo.', + 'contextTypes was defined as an instance property on Foo.', + 'contextType was defined as an instance property on Foo.', + ]) + expect(getInitialStateWasCalled).toBe false + expect(getDefaultPropsWasCalled).toBe false it 'does not warn about getInitialState() on class components if state is also defined.', -> @@ -515,22 +519,23 @@ describe 'ReactCoffeeScriptClass', -> {withoutStack: true} ) - it 'supports this.context passed via getChildContext', -> - class Bar extends React.Component - @contextTypes: - bar: PropTypes.string - render: -> - React.createElement('div', className: @context.bar) + if !featureFlags.disableLegacyContext + it 'supports this.context passed via getChildContext', -> + class Bar extends React.Component + @contextTypes: + bar: PropTypes.string + render: -> + React.createElement('div', className: @context.bar) - class Foo extends React.Component - @childContextTypes: - bar: PropTypes.string - getChildContext: -> - bar: 'bar-through-context' - render: -> - React.createElement Bar + class Foo extends React.Component + @childContextTypes: + bar: PropTypes.string + getChildContext: -> + bar: 'bar-through-context' + render: -> + React.createElement Bar - test React.createElement(Foo), 'DIV', 'bar-through-context' + test React.createElement(Foo), 'DIV', 'bar-through-context' it 'supports string refs', -> class Foo extends React.Component diff --git a/packages/react/src/__tests__/ReactContextValidator-test.js b/packages/react/src/__tests__/ReactContextValidator-test.js index e4895d5c15bd4..9bccbbc51f3d2 100644 --- a/packages/react/src/__tests__/ReactContextValidator-test.js +++ b/packages/react/src/__tests__/ReactContextValidator-test.js @@ -35,6 +35,7 @@ describe('ReactContextValidator', () => { // TODO: This behavior creates a runtime dependency on propTypes. We should // ensure that this is not required for ES6 classes with Flow. + // @gate !disableLegacyContext it('should filter out context not in contextTypes', () => { class Component extends React.Component { render() { @@ -70,6 +71,7 @@ describe('ReactContextValidator', () => { expect(instance.childRef.current.context).toEqual({foo: 'abc'}); }); + // @gate !disableLegacyContext it('should pass next context to lifecycles', () => { let componentDidMountContext; let componentDidUpdateContext; @@ -148,6 +150,7 @@ describe('ReactContextValidator', () => { expect(componentDidUpdateContext).toEqual({foo: 'def'}); }); + // @gate !disableLegacyContext || !__DEV__ it('should check context types', () => { class Component extends React.Component { render() { @@ -213,6 +216,7 @@ describe('ReactContextValidator', () => { ); }); + // @gate !disableLegacyContext || !__DEV__ it('should check child context types', () => { class Component extends React.Component { getChildContext() { @@ -278,6 +282,7 @@ describe('ReactContextValidator', () => { // TODO (bvaughn) Remove this test and the associated behavior in the future. // It has only been added in Fiber to match the (unintentional) behavior in Stack. + // @gate !disableLegacyContext || !__DEV__ it('should warn (but not error) if getChildContext method is missing', () => { class ComponentA extends React.Component { static childContextTypes = { @@ -314,6 +319,7 @@ describe('ReactContextValidator', () => { // TODO (bvaughn) Remove this test and the associated behavior in the future. // It has only been added in Fiber to match the (unintentional) behavior in Stack. + // @gate !disableLegacyContext it('should pass parent context if getChildContext method is missing', () => { class ParentContextProvider extends React.Component { static childContextTypes = { @@ -474,6 +480,7 @@ describe('ReactContextValidator', () => { expect(renderedContext).toBe(secondContext); }); + // @gate !disableLegacyContext || !__DEV__ it('should warn if both contextType and contextTypes are defined', () => { const Context = React.createContext(); diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 70944b398dcbd..72a632f4dd42a 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -246,36 +246,38 @@ describe('ReactES6Class', () => { test(, 'DIV', 'updated'); }); - it('renders based on context in the constructor', () => { - class Foo extends React.Component { - constructor(props, context) { - super(props, context); - this.state = {tag: context.tag, className: this.context.className}; - } - render() { - const Tag = this.state.tag; - return ; + if (!require('shared/ReactFeatureFlags').disableLegacyContext) { + it('renders based on context in the constructor', () => { + class Foo extends React.Component { + constructor(props, context) { + super(props, context); + this.state = {tag: context.tag, className: this.context.className}; + } + render() { + const Tag = this.state.tag; + return ; + } } - } - Foo.contextTypes = { - tag: PropTypes.string, - className: PropTypes.string, - }; + Foo.contextTypes = { + tag: PropTypes.string, + className: PropTypes.string, + }; - class Outer extends React.Component { - getChildContext() { - return {tag: 'span', className: 'foo'}; - } - render() { - return ; + class Outer extends React.Component { + getChildContext() { + return {tag: 'span', className: 'foo'}; + } + render() { + return ; + } } - } - Outer.childContextTypes = { - tag: PropTypes.string, - className: PropTypes.string, - }; - test(, 'SPAN', 'foo'); - }); + Outer.childContextTypes = { + tag: PropTypes.string, + className: PropTypes.string, + }; + test(, 'SPAN', 'foo'); + }); + } it('renders only once when setting state in componentWillMount', () => { let renderCount = 0; @@ -439,39 +441,41 @@ describe('ReactES6Class', () => { expect(lifeCycles).toEqual(['will-unmount']); }); - it('warns when classic properties are defined on the instance, but does not invoke them.', () => { - let getDefaultPropsWasCalled = false; - let getInitialStateWasCalled = false; - class Foo extends React.Component { - constructor() { - super(); - this.contextTypes = {}; - this.contextType = {}; - this.propTypes = {}; - } - getInitialState() { - getInitialStateWasCalled = true; - return {}; - } - getDefaultProps() { - getDefaultPropsWasCalled = true; - return {}; - } - render() { - return ; + if (!require('shared/ReactFeatureFlags').disableLegacyContext) { + it('warns when classic properties are defined on the instance, but does not invoke them.', () => { + let getDefaultPropsWasCalled = false; + let getInitialStateWasCalled = false; + class Foo extends React.Component { + constructor() { + super(); + this.contextTypes = {}; + this.contextType = {}; + this.propTypes = {}; + } + getInitialState() { + getInitialStateWasCalled = true; + return {}; + } + getDefaultProps() { + getDefaultPropsWasCalled = true; + return {}; + } + render() { + return ; + } } - } - expect(() => test(, 'SPAN', 'foo')).toErrorDev([ - 'getInitialState was defined on Foo, a plain JavaScript class.', - 'getDefaultProps was defined on Foo, a plain JavaScript class.', - 'propTypes was defined as an instance property on Foo.', - 'contextType was defined as an instance property on Foo.', - 'contextTypes was defined as an instance property on Foo.', - ]); - expect(getInitialStateWasCalled).toBe(false); - expect(getDefaultPropsWasCalled).toBe(false); - }); + expect(() => test(, 'SPAN', 'foo')).toErrorDev([ + 'getInitialState was defined on Foo, a plain JavaScript class.', + 'getDefaultProps was defined on Foo, a plain JavaScript class.', + 'propTypes was defined as an instance property on Foo.', + 'contextType was defined as an instance property on Foo.', + 'contextTypes was defined as an instance property on Foo.', + ]); + expect(getInitialStateWasCalled).toBe(false); + expect(getDefaultPropsWasCalled).toBe(false); + }); + } it('does not warn about getInitialState() on class components if state is also defined.', () => { class Foo extends React.Component { @@ -553,24 +557,26 @@ describe('ReactES6Class', () => { ); }); - it('supports this.context passed via getChildContext', () => { - class Bar extends React.Component { - render() { - return
; - } - } - Bar.contextTypes = {bar: PropTypes.string}; - class Foo extends React.Component { - getChildContext() { - return {bar: 'bar-through-context'}; + if (!require('shared/ReactFeatureFlags').disableLegacyContext) { + it('supports this.context passed via getChildContext', () => { + class Bar extends React.Component { + render() { + return
; + } } - render() { - return ; + Bar.contextTypes = {bar: PropTypes.string}; + class Foo extends React.Component { + getChildContext() { + return {bar: 'bar-through-context'}; + } + render() { + return ; + } } - } - Foo.childContextTypes = {bar: PropTypes.string}; - test(, 'DIV', 'bar-through-context'); - }); + Foo.childContextTypes = {bar: PropTypes.string}; + test(, 'DIV', 'bar-through-context'); + }); + } it('supports string refs', () => { class Foo extends React.Component { diff --git a/packages/react/src/__tests__/ReactJSXElementValidator-test.js b/packages/react/src/__tests__/ReactJSXElementValidator-test.js index d2611c14a136a..71753ed0ace20 100644 --- a/packages/react/src/__tests__/ReactJSXElementValidator-test.js +++ b/packages/react/src/__tests__/ReactJSXElementValidator-test.js @@ -302,6 +302,7 @@ describe('ReactJSXElementValidator', () => { ); }); + // @gate !disableLegacyContext || !__DEV__ it('should warn on invalid context types', () => { class NullContextTypeComponent extends React.Component { render() { diff --git a/packages/react/src/__tests__/ReactStrictMode-test.js b/packages/react/src/__tests__/ReactStrictMode-test.js index 800607dd956ed..c0d392a61f2da 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.js @@ -985,6 +985,7 @@ describe('context legacy', () => { jest.restoreAllMocks(); }); + // @gate !disableLegacyContext || !__DEV__ it('should warn if the legacy context API have been used in strict mode', () => { class LegacyContextProvider extends React.Component { getChildContext() { diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index efaac47524efb..f356fd08b609c 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -16,6 +16,7 @@ import ReactDOM = require('react-dom'); import ReactDOMClient = require('react-dom/client'); import ReactDOMTestUtils = require('react-dom/test-utils'); import PropTypes = require('prop-types'); +import ReactFeatureFlags = require('shared/ReactFeatureFlags'); // Before Each @@ -511,9 +512,11 @@ describe('ReactTypeScriptClass', function() { test(React.createElement(Foo, {update: true}), 'DIV', 'updated'); }); - it('renders based on context in the constructor', function() { - test(React.createElement(ProvideChildContextTypes), 'SPAN', 'foo'); - }); + if (!ReactFeatureFlags.disableLegacyContext) { + it('renders based on context in the constructor', function() { + test(React.createElement(ProvideChildContextTypes), 'SPAN', 'foo'); + }); + } it('renders only once when setting state in componentWillMount', function() { renderCount = 0; @@ -592,27 +595,29 @@ describe('ReactTypeScriptClass', function() { expect(lifeCycles).toEqual(['will-unmount']); }); - it( - 'warns when classic properties are defined on the instance, ' + - 'but does not invoke them.', - function() { - getInitialStateWasCalled = false; - getDefaultPropsWasCalled = false; - expect(() => - test(React.createElement(ClassicProperties), 'SPAN', 'foo') - ).toErrorDev([ - 'getInitialState was defined on ClassicProperties, ' + - 'a plain JavaScript class.', - 'getDefaultProps was defined on ClassicProperties, ' + - 'a plain JavaScript class.', - 'propTypes was defined as an instance property on ClassicProperties.', - 'contextTypes was defined as an instance property on ClassicProperties.', - 'contextType was defined as an instance property on ClassicProperties.', - ]); - expect(getInitialStateWasCalled).toBe(false); - expect(getDefaultPropsWasCalled).toBe(false); - } - ); + if (!ReactFeatureFlags.disableLegacyContext) { + it( + 'warns when classic properties are defined on the instance, ' + + 'but does not invoke them.', + function() { + getInitialStateWasCalled = false; + getDefaultPropsWasCalled = false; + expect(() => + test(React.createElement(ClassicProperties), 'SPAN', 'foo') + ).toErrorDev([ + 'getInitialState was defined on ClassicProperties, ' + + 'a plain JavaScript class.', + 'getDefaultProps was defined on ClassicProperties, ' + + 'a plain JavaScript class.', + 'propTypes was defined as an instance property on ClassicProperties.', + 'contextTypes was defined as an instance property on ClassicProperties.', + 'contextType was defined as an instance property on ClassicProperties.', + ]); + expect(getInitialStateWasCalled).toBe(false); + expect(getDefaultPropsWasCalled).toBe(false); + } + ); + } it( 'does not warn about getInitialState() on class components ' + @@ -680,9 +685,11 @@ describe('ReactTypeScriptClass', function() { ); }); - it('supports this.context passed via getChildContext', function() { - test(React.createElement(ProvideContext), 'DIV', 'bar-through-context'); - }); + if (!ReactFeatureFlags.disableLegacyContext) { + it('supports this.context passed via getChildContext', function() { + test(React.createElement(ProvideContext), 'DIV', 'bar-through-context'); + }); + } it('supports string refs', function() { const ref = React.createRef(); diff --git a/packages/react/src/__tests__/createReactClassIntegration-test.js b/packages/react/src/__tests__/createReactClassIntegration-test.js index 5a5abafbb1dd5..b907fafea64f9 100644 --- a/packages/react/src/__tests__/createReactClassIntegration-test.js +++ b/packages/react/src/__tests__/createReactClassIntegration-test.js @@ -291,6 +291,7 @@ describe('create-react-class-integration', () => { expect(instance.state.occupation).toEqual('clown'); }); + // @gate !disableLegacyContext it('renders based on context getInitialState', () => { const Foo = createReactClass({ contextTypes: { diff --git a/scripts/jest/setupTests.www.js b/scripts/jest/setupTests.www.js index c0058cb6e0849..a9ce345e04591 100644 --- a/scripts/jest/setupTests.www.js +++ b/scripts/jest/setupTests.www.js @@ -13,7 +13,6 @@ jest.mock('shared/ReactFeatureFlags', () => { // TODO: Many tests were written before we started running them against the // www configuration. Update those tests so that they work against the www // configuration, too. Then remove these overrides. - wwwFlags.disableLegacyContext = defaultFlags.disableLegacyContext; wwwFlags.disableJavaScriptURLs = defaultFlags.disableJavaScriptURLs; return wwwFlags;