Skip to content

Commit

Permalink
ValidateDOMNesting tests(#11299) (#11742)
Browse files Browse the repository at this point in the history
*  ValidateDOMNesting tests(#11299)

 * Rewrite tests using only public API.
 * Modified the tests to prevent duplication of code.
 * Code review changes implemented.
 * Removed the .internal from the test file name as
   its now written using public APIs.

* Remove mutation

* Remove unnecessary argument

Now that we pass warnings, we don't need to pass a boolean.

* Move things around a bit, and add component stack assertions
  • Loading branch information
anushreesubramani authored and gaearon committed Dec 7, 2017
1 parent 2d7aafd commit 8256823
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 195 deletions.
184 changes: 0 additions & 184 deletions packages/react-dom/src/__tests__/validateDOMNesting-test.internal.js

This file was deleted.

134 changes: 134 additions & 0 deletions packages/react-dom/src/__tests__/validateDOMNesting-test.js
@@ -0,0 +1,134 @@
/**
* Copyright (c) 2015-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
*/

'use strict';

var React = require('react');
var ReactDOM = require('react-dom');

function normalizeCodeLocInfo(str) {
return str && str.replace(/at .+?:\d+/g, 'at **');
}

function expectWarnings(tags, warnings = []) {
tags = [...tags];
warnings = [...warnings];

let element = null;
if (__DEV__) {
console.error.calls.reset();
}
const container = document.createElement(tags.splice(0, 1));
while (tags.length) {
const Tag = tags.pop();
element = <Tag>{element}</Tag>;
}
ReactDOM.render(element, container);

if (__DEV__) {
expect(console.error.calls.count()).toEqual(warnings.length);
while (warnings.length) {
expect(
normalizeCodeLocInfo(
console.error.calls.argsFor(warnings.length - 1)[0],
),
).toContain(warnings.pop());
}
}
}

describe('validateDOMNesting', () => {
it('allows valid nestings', () => {
spyOnDev(console, 'error');
expectWarnings(['table', 'tbody', 'tr', 'td', 'b']);
expectWarnings(
['body', 'datalist', 'option'],
[
'render(): Rendering components directly into document.body is discouraged',
],
);
expectWarnings(['div', 'a', 'object', 'a']);
expectWarnings(['div', 'p', 'button', 'p']);
expectWarnings(['p', 'svg', 'foreignObject', 'p']);
expectWarnings(['html', 'body', 'div']);

// Invalid, but not changed by browser parsing so we allow them
expectWarnings(['div', 'ul', 'ul', 'li']);
expectWarnings(['div', 'label', 'div']);
expectWarnings(['div', 'ul', 'li', 'section', 'li']);
expectWarnings(['div', 'ul', 'li', 'dd', 'li']);
});

it('prevents problematic nestings', () => {
spyOnDev(console, 'error');
expectWarnings(
['a', 'a'],
[
'validateDOMNesting(...): <a> cannot appear as a descendant of <a>.\n' +
' in a (at **)',
],
);
expectWarnings(
['form', 'form'],
[
'validateDOMNesting(...): <form> cannot appear as a descendant of <form>.\n' +
' in form (at **)',
],
);
expectWarnings(
['p', 'p'],
[
'validateDOMNesting(...): <p> cannot appear as a descendant of <p>.\n' +
' in p (at **)',
],
);
expectWarnings(
['table', 'tr'],
[
'validateDOMNesting(...): <tr> cannot appear as a child of <table>. ' +
'Add a <tbody> to your code to match the DOM tree generated by the browser.\n' +
' in tr (at **)',
],
);
expectWarnings(
['div', 'ul', 'li', 'div', 'li'],
[
'validateDOMNesting(...): <li> cannot appear as a descendant of <li>.\n' +
' in li (at **)\n' +
' in div (at **)\n' +
' in li (at **)\n' +
' in ul (at **)',
],
);
expectWarnings(
['div', 'html'],
[
'validateDOMNesting(...): <html> cannot appear as a child of <div>.\n' +
' in html (at **)',
],
);
expectWarnings(
['body', 'body'],
[
'render(): Rendering components directly into document.body is discouraged',
'validateDOMNesting(...): <body> cannot appear as a child of <body>.\n' +
' in body (at **)',
],
);
expectWarnings(
['svg', 'foreignObject', 'body', 'p'],
[
'validateDOMNesting(...): <body> cannot appear as a child of <foreignObject>.\n' +
' in body (at **)\n' +
' in foreignObject (at **)',
'<foreignObject /> is using uppercase HTML',
],
);
});
});
11 changes: 0 additions & 11 deletions packages/react-dom/src/client/validateDOMNesting.js
Expand Up @@ -482,17 +482,6 @@ if (__DEV__) {

// TODO: turn this into a named export
validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo;

// For testing
validateDOMNesting.isTagValidInContext = function(tag, ancestorInfo) {
ancestorInfo = ancestorInfo || emptyAncestorInfo;
const parentInfo = ancestorInfo.current;
const parentTag = parentInfo && parentInfo.tag;
return (
isTagValidWithParent(tag, parentTag) &&
!findInvalidAncestorForTag(tag, ancestorInfo)
);
};
}

export default validateDOMNesting;

0 comments on commit 8256823

Please sign in to comment.