Add component stacks to some warnings (#13218)

This commit is contained in:
Dan Abramov
2018-07-17 20:15:03 +01:00
committed by GitHub
parent 21ac62c77a
commit 82c7ca4cca
17 changed files with 65 additions and 110 deletions
+8 -32
View File
@@ -567,7 +567,6 @@ describe('ReactDOMComponent', () => {
}
}).toWarnDev(
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -587,7 +586,6 @@ describe('ReactDOMComponent', () => {
}
}).toWarnDev(
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -1006,7 +1004,6 @@ describe('ReactDOMComponent', () => {
'<BR /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
{withoutStack: true}, // TODO: add a stack
);
expect(returnedValue).not.toContain('</BR>');
});
@@ -1023,7 +1020,6 @@ describe('ReactDOMComponent', () => {
'<IMG /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -1033,7 +1029,6 @@ describe('ReactDOMComponent', () => {
).toWarnDev(
'The `aria` attribute is reserved for future use in React. ' +
'Pass individual `aria-` attributes instead.',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -1056,12 +1051,10 @@ describe('ReactDOMComponent', () => {
expect(() => ReactTestUtils.renderIntoDocument(<bar />)).toWarnDev(
'The tag <bar> is unrecognized in this browser',
{withoutStack: true}, // TODO: add a stack
);
// Test deduplication
expect(() => ReactTestUtils.renderIntoDocument(<foo />)).toWarnDev(
'The tag <foo> is unrecognized in this browser',
{withoutStack: true}, // TODO: add a stack
);
ReactTestUtils.renderIntoDocument(<foo />);
// This is a funny case.
@@ -1073,15 +1066,12 @@ describe('ReactDOMComponent', () => {
// Corner case. Make sure out deduplication logic doesn't break with weird tag.
expect(() =>
ReactTestUtils.renderIntoDocument(<hasOwnProperty />),
).toWarnDev(
[
'<hasOwnProperty /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
'The tag <hasOwnProperty> is unrecognized in this browser',
],
{withoutStack: true}, // TODO: add a stack
);
).toWarnDev([
'<hasOwnProperty /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
'The tag <hasOwnProperty> is unrecognized in this browser',
]);
} finally {
Object.prototype.toString = realToString; // eslint-disable-line no-extend-native
}
@@ -1140,7 +1130,6 @@ describe('ReactDOMComponent', () => {
expect(() => ReactDOM.render(<ShadyComponent />, node)).toWarnDev(
'ShadyComponent is using shady DOM. Using shady DOM with React can ' +
'cause things to break subtly.',
{withoutStack: true}, // TODO: add a stack
);
mountComponent({is: 'custom-shady-div2'});
} finally {
@@ -1161,7 +1150,6 @@ describe('ReactDOMComponent', () => {
expect(() => mountComponent({is: 'custom-shady-div'})).toWarnDev(
'A component is using shady DOM. Using shady DOM with React can ' +
'cause things to break subtly.',
{withoutStack: true}, // TODO: add a stack
);
// No additional warnings are expected
@@ -1209,17 +1197,13 @@ describe('ReactDOMComponent', () => {
it('should validate against use of innerHTML', () => {
expect(() =>
mountComponent({innerHTML: '<span>Hi Jim!</span>'}),
).toWarnDev('Directly setting property `innerHTML` is not permitted. ', {
withoutStack: true, // TODO: add a stack
});
).toWarnDev('Directly setting property `innerHTML` is not permitted. ');
});
it('should validate against use of innerHTML without case sensitivity', () => {
expect(() =>
mountComponent({innerhtml: '<span>Hi Jim!</span>'}),
).toWarnDev('Directly setting property `innerHTML` is not permitted. ', {
withoutStack: true, // TODO: add a stack
});
).toWarnDev('Directly setting property `innerHTML` is not permitted. ');
});
it('should validate use of dangerouslySetInnerHTML', () => {
@@ -1812,13 +1796,11 @@ describe('ReactDOMComponent', () => {
ReactTestUtils.renderIntoDocument(<div onFocusIn={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
expect(() =>
ReactTestUtils.renderIntoDocument(<div onFocusOut={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -1828,13 +1810,11 @@ describe('ReactDOMComponent', () => {
ReactTestUtils.renderIntoDocument(<div onfocusin={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
expect(() =>
ReactTestUtils.renderIntoDocument(<div onfocusout={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -1844,13 +1824,11 @@ describe('ReactDOMComponent', () => {
ReactDOMServer.renderToString(<div onFocusIn={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
expect(() =>
ReactDOMServer.renderToString(<div onFocusOut={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -1860,13 +1838,11 @@ describe('ReactDOMComponent', () => {
ReactDOMServer.renderToString(<div onfocusin={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
expect(() =>
ReactDOMServer.renderToString(<div onfocusout={() => {}} />),
).toWarnDev(
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut.',
{withoutStack: true}, // TODO: add a stack
);
});
@@ -930,7 +930,6 @@ describe('ReactDOMInput', () => {
'both). Decide between using a controlled or uncontrolled input ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
{withoutStack: true}, // TODO: add a stack
);
ReactDOM.unmountComponentAtNode(container);
@@ -958,7 +957,6 @@ describe('ReactDOMInput', () => {
'both). Decide between using a controlled or uncontrolled input ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
{withoutStack: true}, // TODO: add a stack
);
ReactDOM.unmountComponentAtNode(container);
+8 -13
View File
@@ -566,25 +566,21 @@ describe('ReactDOMSelect', () => {
});
it('should warn if selected is set on <option>', () => {
expect(() =>
ReactTestUtils.renderIntoDocument(
function App() {
return (
<select>
<option selected={true} />
<option selected={true} />
</select>,
),
).toWarnDev(
</select>
);
}
expect(() => ReactTestUtils.renderIntoDocument(<App />)).toWarnDev(
'Use the `defaultValue` or `value` props on <select> instead of ' +
'setting `selected` on <option>.',
{withoutStack: true}, // TODO: add a stack
);
ReactTestUtils.renderIntoDocument(
<select>
<option selected={true} />
<option selected={true} />
</select>,
);
ReactTestUtils.renderIntoDocument(<App />);
});
it('should warn if value is null and multiple is true', () => {
@@ -647,7 +643,6 @@ describe('ReactDOMSelect', () => {
'both). Decide between using a controlled or uncontrolled select ' +
'element and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
{withoutStack: true}, // TODO: add a stack
);
ReactTestUtils.renderIntoDocument(
@@ -598,9 +598,7 @@ describe('ReactDOMServerIntegration', () => {
// so that it gets deduplicated later, and doesn't fail the test.
expect(() => {
ReactDOM.render(<nonstandard />, document.createElement('div'));
}).toWarnDev('The tag <nonstandard> is unrecognized in this browser.', {
withoutStack: true, // TODO: add a stack
});
}).toWarnDev('The tag <nonstandard> is unrecognized in this browser.');
const e = await render(<nonstandard foo="bar" />);
expect(e.getAttribute('foo')).toBe('bar');
@@ -142,9 +142,7 @@ describe('ReactDOMServerIntegration', () => {
// so that it gets deduplicated later, and doesn't fail the test.
expect(() => {
ReactDOM.render(<nonstandard />, document.createElement('div'));
}).toWarnDev('The tag <nonstandard> is unrecognized in this browser.', {
withoutStack: true, // TODO: add a stack
});
}).toWarnDev('The tag <nonstandard> is unrecognized in this browser.');
const e = await render(<nonstandard>Text</nonstandard>);
expect(e.tagName).toBe('NONSTANDARD');
@@ -267,7 +267,6 @@ describe('ReactDOMTextarea', () => {
node = renderTextarea(stub, container);
}).toWarnDev(
'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
{withoutStack: true}, // TODO: add a stack
);
expect(node.value).toBe('giraffe');
@@ -320,7 +319,6 @@ describe('ReactDOMTextarea', () => {
node = renderTextarea(<textarea>{17}</textarea>);
}).toWarnDev(
'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
{withoutStack: true}, // TODO: add a stack
);
expect(node.value).toBe('17');
});
@@ -331,7 +329,6 @@ describe('ReactDOMTextarea', () => {
node = renderTextarea(<textarea>{false}</textarea>);
}).toWarnDev(
'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
{withoutStack: true}, // TODO: add a stack
);
expect(node.value).toBe('false');
});
@@ -347,7 +344,6 @@ describe('ReactDOMTextarea', () => {
node = renderTextarea(<textarea>{obj}</textarea>);
}).toWarnDev(
'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
{withoutStack: true}, // TODO: add a stack
);
expect(node.value).toBe('sharkswithlasers');
});
@@ -363,7 +359,6 @@ describe('ReactDOMTextarea', () => {
),
).toWarnDev(
'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
{withoutStack: true}, // TODO: add a stack
);
}).toThrow();
@@ -378,7 +373,6 @@ describe('ReactDOMTextarea', () => {
)),
).toWarnDev(
'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
{withoutStack: true}, // TODO: add a stack
);
}).not.toThrow();
@@ -415,7 +409,6 @@ describe('ReactDOMTextarea', () => {
'both). Decide between using a controlled or uncontrolled textarea ' +
'and remove one of these props. More info: ' +
'https://fb.me/react-controlled-components',
{withoutStack: true}, // TODO: add a stack
);
// No additional warnings are expected
@@ -601,18 +601,15 @@ describe('ReactDOMServer', () => {
</svg>
</div>,
),
).toWarnDev(
[
'Warning: <inPUT /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
// linearGradient doesn't warn
'Warning: <iFrame /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
],
{withoutStack: true},
);
).toWarnDev([
'Warning: <inPUT /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
// linearGradient doesn't warn
'Warning: <iFrame /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
'or lowercase for HTML elements.',
]);
});
it('should warn about contentEditable and children', () => {
+4 -4
View File
@@ -353,7 +353,7 @@ export function createElement(
isCustomComponentTag = isCustomComponent(type, props);
// Should this check be gated by parent namespace? Not sure we want to
// allow <SVG> or <mATH>.
warningWithoutStack(
warning(
isCustomComponentTag || type === type.toLowerCase(),
'<%s /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
@@ -392,7 +392,7 @@ export function createElement(
!Object.prototype.hasOwnProperty.call(warnedUnknownTags, type)
) {
warnedUnknownTags[type] = true;
warningWithoutStack(
warning(
false,
'The tag <%s> is unrecognized in this browser. ' +
'If you meant to render a React component, start its name with ' +
@@ -429,7 +429,7 @@ export function setInitialProperties(
!didWarnShadyDOM &&
(domElement: any).shadyRoot
) {
warningWithoutStack(
warning(
false,
'%s is using shady DOM. Using shady DOM with React can ' +
'cause things to break subtly.',
@@ -821,7 +821,7 @@ export function diffHydratedProperties(
!didWarnShadyDOM &&
(domElement: any).shadyRoot
) {
warningWithoutStack(
warning(
false,
'%s is using shady DOM. Using shady DOM with React can ' +
'cause things to break subtly.',
+2 -3
View File
@@ -11,7 +11,6 @@
import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';
import invariant from 'shared/invariant';
import warning from 'shared/warning';
import warningWithoutStack from 'shared/warningWithoutStack';
import * as DOMPropertyOperations from './DOMPropertyOperations';
import {getFiberCurrentPropsFromNode} from './ReactDOMComponentTree';
@@ -76,7 +75,7 @@ export function initWrapperState(element: Element, props: Object) {
props.defaultChecked !== undefined &&
!didWarnCheckedDefaultChecked
) {
warningWithoutStack(
warning(
false,
'%s contains an input of type %s with both checked and defaultChecked props. ' +
'Input elements must be either controlled or uncontrolled ' +
@@ -94,7 +93,7 @@ export function initWrapperState(element: Element, props: Object) {
props.defaultValue !== undefined &&
!didWarnValueDefaultValue
) {
warningWithoutStack(
warning(
false,
'%s contains an input of type %s with both value and defaultValue props. ' +
'Input elements must be either controlled or uncontrolled ' +
+2 -2
View File
@@ -8,7 +8,7 @@
*/
import React from 'react';
import warningWithoutStack from 'shared/warningWithoutStack';
import warning from 'shared/warning';
let didWarnSelectedSetOnOption = false;
@@ -39,7 +39,7 @@ export function validateProps(element: Element, props: Object) {
// TODO (yungsters): Remove support for `selected` in <option>.
if (__DEV__) {
if (props.selected != null && !didWarnSelectedSetOnOption) {
warningWithoutStack(
warning(
false,
'Use the `defaultValue` or `value` props on <select> instead of ' +
'setting `selected` on <option>.',
+4 -4
View File
@@ -9,7 +9,7 @@
// TODO: direct imports like some-package/src/* are bad. Fix me.
import {getCurrentFiberOwnerNameInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';
import warningWithoutStack from 'shared/warningWithoutStack';
import warning from 'shared/warning';
import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
@@ -49,7 +49,7 @@ function checkSelectPropTypes(props) {
}
const isArray = Array.isArray(props[propName]);
if (props.multiple && !isArray) {
warningWithoutStack(
warning(
false,
'The `%s` prop supplied to <select> must be an array if ' +
'`multiple` is true.%s',
@@ -57,7 +57,7 @@ function checkSelectPropTypes(props) {
getDeclarationErrorAddendum(),
);
} else if (!props.multiple && isArray) {
warningWithoutStack(
warning(
false,
'The `%s` prop supplied to <select> must be a scalar ' +
'value if `multiple` is false.%s',
@@ -158,7 +158,7 @@ export function initWrapperState(element: Element, props: Object) {
props.defaultValue !== undefined &&
!didWarnValueDefaultValue
) {
warningWithoutStack(
warning(
false,
'Select elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
+3 -3
View File
@@ -8,7 +8,7 @@
*/
import invariant from 'shared/invariant';
import warningWithoutStack from 'shared/warningWithoutStack';
import warning from 'shared/warning';
import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
@@ -68,7 +68,7 @@ export function initWrapperState(element: Element, props: Object) {
props.defaultValue !== undefined &&
!didWarnValDefaultVal
) {
warningWithoutStack(
warning(
false,
'Textarea elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
@@ -89,7 +89,7 @@ export function initWrapperState(element: Element, props: Object) {
let children = props.children;
if (children != null) {
if (__DEV__) {
warningWithoutStack(
warning(
false,
'Use the `defaultValue` or `value` props instead of setting ' +
'children on <textarea>.',
+11 -12
View File
@@ -18,6 +18,7 @@ import React from 'react';
import invariant from 'shared/invariant';
import getComponentName from 'shared/getComponentName';
import lowPriorityWarning from 'shared/lowPriorityWarning';
import warning from 'shared/warning';
import warningWithoutStack from 'shared/warningWithoutStack';
import checkPropTypes from 'prop-types/checkPropTypes';
import describeComponentFrame from 'shared/describeComponentFrame';
@@ -1022,7 +1023,7 @@ class ReactDOMServerRenderer {
if (namespace === Namespaces.html) {
// Should this check be gated by parent namespace? Not sure we want to
// allow <SVG> or <mATH>.
warningWithoutStack(
warning(
tag === element.type,
'<%s /> is using incorrect casing. ' +
'Use PascalCase for React components, ' +
@@ -1044,7 +1045,7 @@ class ReactDOMServerRenderer {
props.defaultChecked !== undefined &&
!didWarnDefaultChecked
) {
warningWithoutStack(
warning(
false,
'%s contains an input of type %s with both checked and defaultChecked props. ' +
'Input elements must be either controlled or uncontrolled ' +
@@ -1062,7 +1063,7 @@ class ReactDOMServerRenderer {
props.defaultValue !== undefined &&
!didWarnDefaultInputValue
) {
warningWithoutStack(
warning(
false,
'%s contains an input of type %s with both value and defaultValue props. ' +
'Input elements must be either controlled or uncontrolled ' +
@@ -1097,7 +1098,7 @@ class ReactDOMServerRenderer {
props.defaultValue !== undefined &&
!didWarnDefaultTextareaValue
) {
warningWithoutStack(
warning(
false,
'Textarea elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
@@ -1116,7 +1117,7 @@ class ReactDOMServerRenderer {
let textareaChildren = props.children;
if (textareaChildren != null) {
if (__DEV__) {
warningWithoutStack(
warning(
false,
'Use the `defaultValue` or `value` props instead of setting ' +
'children on <textarea>.',
@@ -1157,20 +1158,18 @@ class ReactDOMServerRenderer {
}
const isArray = Array.isArray(props[propName]);
if (props.multiple && !isArray) {
warningWithoutStack(
warning(
false,
'The `%s` prop supplied to <select> must be an array if ' +
'`multiple` is true.%s',
'`multiple` is true.',
propName,
'', // getDeclarationErrorAddendum(),
);
} else if (!props.multiple && isArray) {
warningWithoutStack(
warning(
false,
'The `%s` prop supplied to <select> must be a scalar ' +
'value if `multiple` is false.%s',
'value if `multiple` is false.',
propName,
'', // getDeclarationErrorAddendum(),
);
}
}
@@ -1180,7 +1179,7 @@ class ReactDOMServerRenderer {
props.defaultValue !== undefined &&
!didWarnDefaultSelectValue
) {
warningWithoutStack(
warning(
false,
'Select elements must be either controlled or uncontrolled ' +
'(specify either the value prop, or the defaultValue prop, but not ' +
+2 -2
View File
@@ -7,7 +7,7 @@
* @flow
*/
import warningWithoutStack from 'shared/warningWithoutStack';
import warning from 'shared/warning';
type PropertyType = 0 | 1 | 2 | 3 | 4 | 5 | 6;
@@ -82,7 +82,7 @@ export function isAttributeNameSafe(attributeName: string): boolean {
}
illegalAttributeNameCache[attributeName] = true;
if (__DEV__) {
warningWithoutStack(false, 'Invalid attribute name: `%s`', attributeName);
warning(false, 'Invalid attribute name: `%s`', attributeName);
}
return false;
}
@@ -10,7 +10,6 @@ import {
possibleRegistrationNames,
} from 'events/EventPluginRegistry';
import warning from 'shared/warning';
import warningWithoutStack from 'shared/warningWithoutStack';
import {
ATTRIBUTE_NAME_CHAR,
@@ -38,7 +37,7 @@ if (__DEV__) {
const lowerCasedName = name.toLowerCase();
if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') {
warningWithoutStack(
warning(
false,
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' +
'All React events are normalized to bubble, so onFocusIn and onFocusOut ' +
@@ -99,7 +98,7 @@ if (__DEV__) {
}
if (lowerCasedName === 'innerhtml') {
warningWithoutStack(
warning(
false,
'Directly setting property `innerHTML` is not permitted. ' +
'For more information, lookup documentation on `dangerouslySetInnerHTML`.',
@@ -109,7 +108,7 @@ if (__DEV__) {
}
if (lowerCasedName === 'aria') {
warningWithoutStack(
warning(
false,
'The `aria` attribute is reserved for future use in React. ' +
'Pass individual `aria-` attributes instead.',
+1 -1
View File
@@ -976,7 +976,7 @@ function updateContextProvider(current, workInProgress, renderExpirationTime) {
? context._calculateChangedBits(oldValue, newValue)
: MAX_SIGNED_31_BIT_INT;
if (__DEV__) {
warningWithoutStack(
warning(
(changedBits & MAX_SIGNED_31_BIT_INT) === changedBits,
'calculateChangedBits: Expected the return value to be a ' +
'31-bit integer. Instead received: %s',
@@ -706,15 +706,18 @@ describe('ReactNewContext', () => {
(a, b) => Math.pow(2, 32) - 1, // Return 32 bit int
);
ReactNoop.render(<Context.Provider value={1} />);
function App(props) {
return <Context.Provider value={props.value} />;
}
ReactNoop.render(<App value={1} />);
ReactNoop.flush();
// Update
ReactNoop.render(<Context.Provider value={2} />);
ReactNoop.render(<App value={2} />);
expect(ReactNoop.flush).toWarnDev(
'calculateChangedBits: Expected the return value to be a 31-bit ' +
'integer. Instead received: 4294967295',
{withoutStack: true}, // TODO: add a stack
);
});