diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js
index bb8ecc6e81ddf4..12294a9e699eef 100644
--- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js
+++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js
@@ -42,13 +42,6 @@ describe('ReactDOMServer', () => {
expect(response).toMatch(new RegExp('
'));
});
- it('should generate simple markup for attribute with `>` symbol', () => {
- var response = ReactDOMServer.renderToString(
);
- expect(response).toMatch(
- new RegExp('
'),
- );
- });
-
it('should generate comment markup for component returns null', () => {
class NullComponent extends React.Component {
render() {
diff --git a/packages/react-dom/src/__tests__/escapeTextContentForBrowser-test.js b/packages/react-dom/src/__tests__/escapeTextContentForBrowser-test.js
deleted file mode 100644
index 78fedc5b62cc00..00000000000000
--- a/packages/react-dom/src/__tests__/escapeTextContentForBrowser-test.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * 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
- */
-
-'use strict';
-
-describe('escapeTextContentForBrowser', () => {
- // TODO: can we express this test with only public API?
- var escapeTextContentForBrowser = require('../shared/escapeTextContentForBrowser')
- .default;
-
- it('should escape boolean to string', () => {
- expect(escapeTextContentForBrowser(true)).toBe('true');
- expect(escapeTextContentForBrowser(false)).toBe('false');
- });
-
- it('should escape object to string', () => {
- var escaped = escapeTextContentForBrowser({
- toString: function() {
- return 'ponys';
- },
- });
-
- expect(escaped).toBe('ponys');
- });
-
- it('should escape number to string', () => {
- expect(escapeTextContentForBrowser(42)).toBe('42');
- });
-
- it('should escape string', () => {
- var escaped = escapeTextContentForBrowser(
- '',
- );
- expect(escaped).not.toContain('<');
- expect(escaped).not.toContain('>');
- expect(escaped).not.toContain("'");
- expect(escaped).not.toContain('"');
-
- escaped = escapeTextContentForBrowser('&');
- expect(escaped).toBe('&');
- });
-});
diff --git a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js
new file mode 100644
index 00000000000000..a76cacb7fdf651
--- /dev/null
+++ b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js
@@ -0,0 +1,66 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+var React;
+var ReactDOMServer;
+
+describe('escapeTextForBrowser', () => {
+ beforeEach(() => {
+ jest.resetModules();
+ React = require('react');
+ ReactDOMServer = require('react-dom/server');
+ });
+
+ it('ampersand is escaped when passed as text content', () => {
+ var response = ReactDOMServer.renderToString({'&'});
+ expect(response).toMatch('&');
+ });
+
+ it('double quote is escaped when passed as text content', () => {
+ var response = ReactDOMServer.renderToString({'"'});
+ expect(response).toMatch('"');
+ });
+
+ it('single quote is escaped when passed as text content', () => {
+ var response = ReactDOMServer.renderToString({"'"});
+ expect(response).toMatch(''');
+ });
+
+ it('greater than entity is escaped when passed as text content', () => {
+ var response = ReactDOMServer.renderToString({'>'});
+ expect(response).toMatch('>');
+ });
+
+ it('lower than entity is escaped when passed as text content', () => {
+ var response = ReactDOMServer.renderToString({'<'});
+ expect(response).toMatch('<');
+ });
+
+ it('number is correctly passed as text content', () => {
+ var response = ReactDOMServer.renderToString({42});
+ expect(response).toMatch('42');
+ });
+
+ it('number is escaped to string when passed as text content', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
+ });
+
+ it('escape text content representing a script tag', () => {
+ var response = ReactDOMServer.renderToString(
+ {''},
+ );
+ expect(response).toMatch(
+ '<script type='' ' +
+ 'src=""></script>',
+ );
+ });
+});
diff --git a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js
index 4a4489b98714e2..1a0db78037f2d0 100644
--- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js
+++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js
@@ -9,40 +9,67 @@
'use strict';
+var React;
+var ReactDOMServer;
+
describe('quoteAttributeValueForBrowser', () => {
- // TODO: can we express this test with only public API?
- var quoteAttributeValueForBrowser = require('../shared/quoteAttributeValueForBrowser')
- .default;
+ beforeEach(() => {
+ jest.resetModules();
+ React = require('react');
+ ReactDOMServer = require('react-dom/server');
+ });
- it('should escape boolean to string', () => {
- expect(quoteAttributeValueForBrowser(true)).toBe('"true"');
- expect(quoteAttributeValueForBrowser(false)).toBe('"false"');
+ it('ampersand is escaped inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
});
- it('should escape object to string', () => {
- var escaped = quoteAttributeValueForBrowser({
- toString: function() {
- return 'ponys';
- },
- });
+ it('double quote is escaped inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
+ });
+
+ it('single quote is escaped inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
+ });
- expect(escaped).toBe('"ponys"');
+ it('greater than entity is escaped inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
});
- it('should escape number to string', () => {
- expect(quoteAttributeValueForBrowser(42)).toBe('"42"');
+ it('lower than entity is escaped inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
});
- it('should escape string', () => {
- var escaped = quoteAttributeValueForBrowser(
- '',
+ it('number is escaped to string inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
);
+ expect(response).toMatch('
');
+ });
+
+ it('object is passed to a string inside attributes', () => {
+ var sampleObject = {
+ toString: function() {
+ return 'ponys';
+ },
+ };
+
+ var response = ReactDOMServer.renderToString(
+
,
);
- expect(escaped).not.toContain('<');
- expect(escaped).not.toContain('>');
- expect(escaped).not.toContain("'");
- expect(escaped.substr(1, -1)).not.toContain('"');
+ expect(response).toMatch('
');
+ });
- escaped = quoteAttributeValueForBrowser('&');
- expect(escaped).toBe('"&"');
+ it('script tag is escaped inside attributes', () => {
+ var response = ReactDOMServer.renderToString(
+
'} />,
+ );
+ expect(response).toMatch(
+ '
',
+ );
});
});
diff --git a/packages/react-dom/src/client/setTextContent.js b/packages/react-dom/src/client/setTextContent.js
index ffaa3c9b14acdb..0cc8f553c51f36 100644
--- a/packages/react-dom/src/client/setTextContent.js
+++ b/packages/react-dom/src/client/setTextContent.js
@@ -5,10 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
-import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment';
-
-import setInnerHTML from './setInnerHTML';
-import escapeTextContentForBrowser from '../shared/escapeTextContentForBrowser';
import {TEXT_NODE} from '../shared/HTMLNodeType';
/**
@@ -37,16 +33,4 @@ let setTextContent = function(node, text) {
node.textContent = text;
};
-if (ExecutionEnvironment.canUseDOM) {
- if (!('textContent' in document.documentElement)) {
- setTextContent = function(node, text) {
- if (node.nodeType === TEXT_NODE) {
- node.nodeValue = text;
- return;
- }
- setInnerHTML(node, escapeTextContentForBrowser(text));
- };
- }
-}
-
export default setTextContent;
diff --git a/packages/react-dom/src/server/DOMMarkupOperations.js b/packages/react-dom/src/server/DOMMarkupOperations.js
index d85fe050ab905c..b86f6fd6017267 100644
--- a/packages/react-dom/src/server/DOMMarkupOperations.js
+++ b/packages/react-dom/src/server/DOMMarkupOperations.js
@@ -14,7 +14,7 @@ import {
shouldAttributeAcceptBooleanValue,
shouldSetAttribute,
} from '../shared/DOMProperty';
-import quoteAttributeValueForBrowser from '../shared/quoteAttributeValueForBrowser';
+import quoteAttributeValueForBrowser from './quoteAttributeValueForBrowser';
import warning from 'fbjs/lib/warning';
// isAttributeNameSafe() is currently duplicated in DOMPropertyOperations.
diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js
index 60f03527653aed..c76a311aac3b73 100644
--- a/packages/react-dom/src/server/ReactPartialRenderer.js
+++ b/packages/react-dom/src/server/ReactPartialRenderer.js
@@ -26,6 +26,7 @@ import {
createMarkupForProperty,
createMarkupForRoot,
} from './DOMMarkupOperations';
+import escapeTextForBrowser from './escapeTextForBrowser';
import {
Namespaces,
getIntrinsicNamespace,
@@ -34,7 +35,6 @@ import {
import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
import assertValidProps from '../shared/assertValidProps';
import dangerousStyleValue from '../shared/dangerousStyleValue';
-import escapeTextContentForBrowser from '../shared/escapeTextContentForBrowser';
import isCustomComponent from '../shared/isCustomComponent';
import omittedCloseTags from '../shared/omittedCloseTags';
import warnValidStyle from '../shared/warnValidStyle';
@@ -204,7 +204,7 @@ function getNonChildrenInnerMarkup(props) {
} else {
var content = props.children;
if (typeof content === 'string' || typeof content === 'number') {
- return escapeTextContentForBrowser(content);
+ return escapeTextForBrowser(content);
}
}
return null;
@@ -572,13 +572,13 @@ class ReactDOMServerRenderer {
return '';
}
if (this.makeStaticMarkup) {
- return escapeTextContentForBrowser(text);
+ return escapeTextForBrowser(text);
}
if (this.previousWasTextNode) {
- return '' + escapeTextContentForBrowser(text);
+ return '' + escapeTextForBrowser(text);
}
this.previousWasTextNode = true;
- return escapeTextContentForBrowser(text);
+ return escapeTextForBrowser(text);
} else {
var nextChild;
({child: nextChild, context} = resolve(child, context));
diff --git a/packages/react-dom/src/shared/escapeTextContentForBrowser.js b/packages/react-dom/src/server/escapeTextForBrowser.js
similarity index 93%
rename from packages/react-dom/src/shared/escapeTextContentForBrowser.js
rename to packages/react-dom/src/server/escapeTextForBrowser.js
index 8d086dfd72e5b4..5b8245a93592f4 100644
--- a/packages/react-dom/src/shared/escapeTextContentForBrowser.js
+++ b/packages/react-dom/src/server/escapeTextForBrowser.js
@@ -39,9 +39,9 @@
var matchHtmlRegExp = /["'&<>]/;
/**
- * Escape special characters in the given string of html.
+ * Escapes special characters and HTML entities in a given html string.
*
- * @param {string} string The string to escape for inserting into HTML
+ * @param {string} string HTML string to escape for later insertion
* @return {string}
* @public
*/
@@ -98,7 +98,7 @@ function escapeHtml(string) {
* @param {*} text Text value to escape.
* @return {string} An escaped string.
*/
-function escapeTextContentForBrowser(text) {
+function escapeTextForBrowser(text) {
if (typeof text === 'boolean' || typeof text === 'number') {
// this shortcircuit helps perf for types that we know will never have
// special characters, especially given that this function is used often
@@ -108,4 +108,4 @@ function escapeTextContentForBrowser(text) {
return escapeHtml(text);
}
-export default escapeTextContentForBrowser;
+export default escapeTextForBrowser;
diff --git a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js b/packages/react-dom/src/server/quoteAttributeValueForBrowser.js
similarity index 76%
rename from packages/react-dom/src/shared/quoteAttributeValueForBrowser.js
rename to packages/react-dom/src/server/quoteAttributeValueForBrowser.js
index feeeb055a7363a..592aab6a25e978 100644
--- a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js
+++ b/packages/react-dom/src/server/quoteAttributeValueForBrowser.js
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
-import escapeTextContentForBrowser from './escapeTextContentForBrowser';
+import escapeTextForBrowser from './escapeTextForBrowser';
/**
* Escapes attribute value to prevent scripting attacks.
@@ -14,7 +14,7 @@ import escapeTextContentForBrowser from './escapeTextContentForBrowser';
* @return {string} An escaped string.
*/
function quoteAttributeValueForBrowser(value) {
- return '"' + escapeTextContentForBrowser(value) + '"';
+ return '"' + escapeTextForBrowser(value) + '"';
}
export default quoteAttributeValueForBrowser;