Change:
For consideration. These warnings are already covered by renderers based on react-reconciler. Maybe we don't gain that much by mirroring them in the shallow renderer? Maybe it's not worth the complexity? Particularly with more complicated warnings like the ones being for and .

Discussion:
import React from 'react'; import {isForwardRef} from 'react-is'; <del> import {warnAboutDeprecatedLifecycles} from 'shared/ReactFeatureFlags'; </del> import describeComponentFrame from 'shared/describeComponentFrame'; import getComponentName from 'shared/getComponentName'; import emptyObject from 'fbjs/lib/emptyObject'; import invariant from 'fbjs/lib/invariant'; <del> import lowPriorityWarning from 'shared/lowPriorityWarning'; </del> import shallowEqual from 'fbjs/lib/shallowEqual'; import checkPropTypes from 'prop-types/checkPropTypes'; <del> import warning from 'fbjs/lib/warning'; let didWarnAboutLegacyWillMount; let didWarnAboutLegacyWillReceiveProps; let didWarnAboutLegacyWillUpdate; let didWarnAboutUndefinedDerivedState; let didWarnAboutUninitializedState; let didWarnAboutLegacyLifecyclesAndDerivedState; if (__DEV__) { if (warnAboutDeprecatedLifecycles) { didWarnAboutLegacyWillMount = {}; didWarnAboutLegacyWillReceiveProps = {}; didWarnAboutLegacyWillUpdate = {}; } didWarnAboutUndefinedDerivedState = {}; didWarnAboutUninitializedState = {}; didWarnAboutLegacyLifecyclesAndDerivedState = {}; } </del> class ReactShallowRenderer { static createRenderer = function() {

this._updater, ); <del> if (__DEV__) { if (typeof element.type.getDerivedStateFromProps === 'function') { if ( this._instance.state === null || this._instance.state === undefined ) { const componentName = getName(element.type, this._instance) || 'Unknown'; if (!didWarnAboutUninitializedState[componentName]) { warning( false, '%s: Did not properly initialize state during construction. ' + 'Expected state to be an object, but it was %s.', componentName, this._instance.state === null ? 'null' : 'undefined', ); didWarnAboutUninitializedState[componentName] = true; } } } } </del> this._updateStateFromStaticLifecycle(element.props); if (element.type.hasOwnProperty('contextTypes')) {

const beforeState = this._newState; if (typeof this._instance.componentWillMount === 'function') { <del> if (__DEV__) { // Don't warn about react-lifecycles-compat polyfilled components if ( warnAboutDeprecatedLifecycles && this._instance.componentWillMount.__suppressDeprecationWarning !== true ) { const componentName = getName(element.type, this._instance); if (!didWarnAboutLegacyWillMount[componentName]) { lowPriorityWarning( false, '%s: componentWillMount() is deprecated and will be ' + 'removed in the next major version. Read about the motivations ' + 'behind this change: ' + 'https://fb.me/react-async-component-lifecycle-hooks' + 'nn' + 'As a temporary workaround, you can rename to ' + 'UNSAFE_componentWillMount instead.', componentName, ); didWarnAboutLegacyWillMount[componentName] = true; } } } </del> // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for any component with the new gDSFP. if (typeof element.type.getDerivedStateFromProps !== 'function') {

if (oldProps !== props) { if (typeof this._instance.componentWillReceiveProps === 'function') { <del> if (__DEV__) { if (warnAboutDeprecatedLifecycles) { const componentName = getName(element.type, this._instance); if (!didWarnAboutLegacyWillReceiveProps[componentName]) { lowPriorityWarning( false, '%s: componentWillReceiveProps() is deprecated and ' + 'will be removed in the next major version. Use ' + 'static getDerivedStateFromProps() instead. Read about the ' + 'motivations behind this change: ' + 'https://fb.me/react-async-component-lifecycle-hooks' + 'nn' + 'As a temporary workaround, you can rename to ' + 'UNSAFE_componentWillReceiveProps instead.', componentName, ); didWarnAboutLegacyWillReceiveProps[componentName] = true; } } } </del> // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for any component with the new gDSFP. if (typeof element.type.getDerivedStateFromProps !== 'function') {

if (shouldUpdate) { if (typeof this._instance.componentWillUpdate === 'function') { <del> if (__DEV__) { if (warnAboutDeprecatedLifecycles) { const componentName = getName(element.type, this._instance); if (!didWarnAboutLegacyWillUpdate[componentName]) { lowPriorityWarning( false, '%s: componentWillUpdate() is deprecated and will be ' + 'removed in the next major version. Read about the motivations ' + 'behind this change: ' + 'https://fb.me/react-async-component-lifecycle-hooks' + 'nn' + 'As a temporary workaround, you can rename to ' + 'UNSAFE_componentWillUpdate instead.', componentName, ); didWarnAboutLegacyWillUpdate[componentName] = true; } } } </del> // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for any component with the new gDSFP. if (typeof type.getDerivedStateFromProps !== 'function') {

const {type} = this._element; if (typeof type.getDerivedStateFromProps === 'function') { <del> if (__DEV__) { const instance = this._instance; // If getDerivedStateFromProps() is defined, "unsafe" lifecycles won't be called. // Warn about these lifecycles if they are present. // Don't warn about react-lifecycles-compat polyfilled methods though. let foundWillMountName = null; let foundWillReceivePropsName = null; let foundWillUpdateName = null; if ( typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true ) { foundWillMountName = 'componentWillMount'; } else if (typeof instance.UNSAFE_componentWillMount === 'function') { foundWillMountName = 'UNSAFE_componentWillMount'; } if ( typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true ) { foundWillReceivePropsName = 'componentWillReceiveProps'; } else if ( typeof instance.UNSAFE_componentWillReceiveProps === 'function' ) { foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; } if (typeof instance.componentWillUpdate === 'function') { foundWillUpdateName = 'componentWillUpdate'; } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') { foundWillUpdateName = 'UNSAFE_componentWillUpdate'; } if ( foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null ) { const componentName = getName(type, instance) || 'Component'; if (!didWarnAboutLegacyLifecyclesAndDerivedState[componentName]) { warning( false, 'Unsafe legacy lifecycles will not be called for components using ' + 'the new getDerivedStateFromProps() API.nn' + '%s uses getDerivedStateFromProps() but also contains the following legacy lifecycles:' + '%s%s%snn' + 'The above lifecycles should be removed. Learn more about this warning here:n' + 'https://fb.me/react-async-component-lifecycle-hooks', componentName, foundWillMountName !== null ? `n  ${foundWillMountName}` : '', foundWillReceivePropsName !== null ? `n  ${foundWillReceivePropsName}` : '', foundWillUpdateName !== null ? `n  ${foundWillUpdateName}` : '', ); didWarnAboutLegacyLifecyclesAndDerivedState[componentName] = true; } } } </del> const partialState = type.getDerivedStateFromProps.call( null, props, this._instance.state, ); <del> if (__DEV__) { if (partialState === undefined) { const componentName = getName(type, this._instance); if (!didWarnAboutUndefinedDerivedState[componentName]) { warning( false, '%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName, ); didWarnAboutUndefinedDerivedState[componentName] = componentName; } } } </del> if (partialState != null) { const oldState = this._newState || this._instance.state; const newState = Object.assign({}, oldState, partialState);

<del> /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @emails react-core * @jest-environment node */ 'use strict'; let createRenderer; let React; let ReactFeatureFlags; describe('ReactShallowRenderer', () => { beforeEach(() => { ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.warnAboutDeprecatedLifecycles = true; createRenderer = require('react-test-renderer/shallow').createRenderer; React = require('react'); }); afterEach(() => { jest.resetModules(); }); // TODO (RFC #6) Merge this back into ReactShallowRenderer-test once // the 'warnAboutDeprecatedLifecycles' feature flag has been removed. it('should warn if deprecated lifecycles exist', () => { class ComponentWithWarnings extends React.Component { componentWillReceiveProps() {} componentWillMount() {} componentWillUpdate() {} render() { return null; } } const shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<ComponentWithWarnings />), ).toLowPriorityWarnDev( 'Warning: ComponentWithWarnings: componentWillMount() is deprecated and will ' + 'be removed in the next major version.', ); expect(() => shallowRenderer.render(<ComponentWithWarnings />), ).toLowPriorityWarnDev([ 'Warning: ComponentWithWarnings: componentWillReceiveProps() is deprecated ' + 'and will be removed in the next major version.', 'Warning: ComponentWithWarnings: componentWillUpdate() is deprecated and will ' + 'be removed in the next major version.', ]); // Verify no duplicate warnings shallowRenderer.render(<ComponentWithWarnings />); }); describe('react-lifecycles-compat', () => { const polyfill = require('react-lifecycles-compat'); it('should not warn about deprecated cWM/cWRP for polyfilled components', () => { class PolyfilledComponent extends React.Component { state = {}; static getDerivedStateFromProps() { return null; } render() { return null; } } polyfill(PolyfilledComponent); const shallowRenderer = createRenderer(); shallowRenderer.render(<PolyfilledComponent />); }); }); }); </del>

} const shallowRenderer = createRenderer(); <del> expect(() => shallowRenderer.render(<Component />)).toWarnDev( 'Unsafe legacy lifecycles will not be called for components using the new getDerivedStateFromProps() API.', ); }); it('should warn about deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', () => { let shallowRenderer; class AllLegacyLifecycles extends React.Component { state = {}; static getDerivedStateFromProps() { return null; } componentWillMount() {} UNSAFE_componentWillReceiveProps() {} componentWillUpdate() {} render() { return null; } } shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<AllLegacyLifecycles />)).toWarnDev( 'Unsafe legacy lifecycles will not be called for components using the new getDerivedStateFromProps() API.nn' + 'AllLegacyLifecycles uses getDerivedStateFromProps() but also contains the following legacy lifecycles:n' + '  componentWillMountn' + '  UNSAFE_componentWillReceivePropsn' + '  componentWillUpdatenn' + 'The above lifecycles should be removed. Learn more about this warning here:n' + 'https://fb.me/react-async-component-lifecycle-hooks', ); class WillMount extends React.Component { state = {}; static getDerivedStateFromProps() { return null; } UNSAFE_componentWillMount() {} render() { return null; } } shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<WillMount />)).toWarnDev( 'Unsafe legacy lifecycles will not be called for components using the new getDerivedStateFromProps() API.nn' + 'WillMount uses getDerivedStateFromProps() but also contains the following legacy lifecycles:n' + '  UNSAFE_componentWillMountnn' + 'The above lifecycles should be removed. Learn more about this warning here:n' + 'https://fb.me/react-async-component-lifecycle-hooks', ); class WillMountAndUpdate extends React.Component { state = {}; static getDerivedStateFromProps() { return null; } componentWillMount() {} UNSAFE_componentWillUpdate() {} render() { return null; } } shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<WillMountAndUpdate />)).toWarnDev( 'Unsafe legacy lifecycles will not be called for components using the new getDerivedStateFromProps() API.nn' + 'WillMountAndUpdate uses getDerivedStateFromProps() but also contains the following legacy lifecycles:n' + '  componentWillMountn' + '  UNSAFE_componentWillUpdatenn' + 'The above lifecycles should be removed. Learn more about this warning here:n' + 'https://fb.me/react-async-component-lifecycle-hooks', ); class WillReceiveProps extends React.Component { state = {}; static getDerivedStateFromProps() { return null; } componentWillReceiveProps() {} render() { return null; } } shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<WillReceiveProps />)).toWarnDev( 'Unsafe legacy lifecycles will not be called for components using the new getDerivedStateFromProps() API.nn' + 'WillReceiveProps uses getDerivedStateFromProps() but also contains the following legacy lifecycles:n' + '  componentWillReceivePropsnn' + 'The above lifecycles should be removed. Learn more about this warning here:n' + 'https://fb.me/react-async-component-lifecycle-hooks', ); </del> <ins> shallowRenderer.render(<Component />); </ins> }); it('should only render 1 level deep', () => {

expect(shallowRenderer.getMountedInstance().state).toBeNull(); }); <del> it('should warn if both componentWillReceiveProps and static getDerivedStateFromProps exist', () => { class ComponentWithWarnings extends React.Component { state = {}; static getDerivedStateFromProps(props, prevState) { return null; } UNSAFE_componentWillReceiveProps(nextProps) {} render() { return null; } } const shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<ComponentWithWarnings />)).toWarnDev( 'ComponentWithWarnings uses getDerivedStateFromProps() but also contains the following legacy lifecycles', ); // Should not log duplicate warning shallowRenderer.render(<ComponentWithWarnings />); }); it('should warn if getDerivedStateFromProps returns undefined', () => { class Component extends React.Component { state = {}; static getDerivedStateFromProps() {} render() { return null; } } const shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<Component />)).toWarnDev( 'Component.getDerivedStateFromProps(): A valid state object (or null) must ' + 'be returned. You have returned undefined.', ); // De-duped shallowRenderer.render(<Component />); }); it('should warn if state not initialized before getDerivedStateFromProps', () => { class Component extends React.Component { static getDerivedStateFromProps() { return null; } render() { return null; } } const shallowRenderer = createRenderer(); expect(() => shallowRenderer.render(<Component />)).toWarnDev( 'Component: Did not properly initialize state during construction. ' + 'Expected state to be an object, but it was undefined.', ); // De-duped shallowRenderer.render(<Component />); }); </del> it('should invoke both deprecated and new lifecycles if both are present', () => { const log = [];