From a8785a5358f48902d3dba0d741a578dc4760d5dd Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Wed, 8 Nov 2017 00:59:57 -0300 Subject: [PATCH 01/10] Rename escapeText util. Test quoteAttributeValueForBrowser through ReactDOMServer API --- .../__tests__/ReactServerRendering-test.js | 9 --- .../escapeTextContentForBrowser-test.js | 48 ------------ .../quoteAttributeValueForBrowser-test.js | 77 +++++++++++++------ .../react-dom/src/client/setTextContent.js | 13 ---- .../src/server/ReactPartialRenderer.js | 10 +-- ...TextContentForBrowser.js => escapeText.js} | 4 +- .../shared/quoteAttributeValueForBrowser.js | 4 +- 7 files changed, 62 insertions(+), 103 deletions(-) delete mode 100644 packages/react-dom/src/__tests__/escapeTextContentForBrowser-test.js rename packages/react-dom/src/shared/{escapeTextContentForBrowser.js => escapeText.js} (97%) diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js index c83c7023072aa..e299299f3eb2e 100644 --- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js @@ -56,15 +56,6 @@ describe('ReactDOMServer', () => { ); }); - 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 78fedc5b62cc0..0000000000000 --- 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__/quoteAttributeValueForBrowser-test.js b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js index 4a4489b98714e..f8b00c13d2ef7 100644 --- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js +++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js @@ -9,40 +9,69 @@ 'use strict'; +var ExecutionEnvironment; +var React; +var ReactDOMServer; + +var ROOT_ATTRIBUTE_NAME; + describe('quoteAttributeValueForBrowser', () => { - // TODO: can we express this test with only public API? - var quoteAttributeValueForBrowser = require('../shared/quoteAttributeValueForBrowser') - .default; - it('should escape boolean to string', () => { - expect(quoteAttributeValueForBrowser(true)).toBe('"true"'); - expect(quoteAttributeValueForBrowser(false)).toBe('"false"'); + beforeEach(() => { + jest.resetModules(); + React = require('react'); + + ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); + ExecutionEnvironment.canUseDOM = false; + ReactDOMServer = require('react-dom/server'); + + // TODO: can we express this test with only public API? + var DOMProperty = require('../shared/DOMProperty'); + ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; }); - it('should escape object to string', () => { - var escaped = quoteAttributeValueForBrowser({ - toString: function() { - return 'ponys'; - }, - }); + it('ampersand is escaped inside attributes', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp( + '', + ), + ); + }); - expect(escaped).toBe('"ponys"'); + it('double quote is escaped inside attributes', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp( + '', + ), + ); }); - it('should escape number to string', () => { - expect(quoteAttributeValueForBrowser(42)).toBe('"42"'); + it('single quote is escaped inside attributes', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp( + '', + ), + ); }); - it('should escape string', () => { - var escaped = quoteAttributeValueForBrowser( - '', + it('greater than entity is escaped inside attributes', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp( + '', + ), ); - expect(escaped).not.toContain('<'); - expect(escaped).not.toContain('>'); - expect(escaped).not.toContain("'"); - expect(escaped.substr(1, -1)).not.toContain('"'); + }); - escaped = quoteAttributeValueForBrowser('&'); - expect(escaped).toBe('"&"'); + it('lower than entity is escaped inside attributes', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp( + '', + ), + ); }); }); diff --git a/packages/react-dom/src/client/setTextContent.js b/packages/react-dom/src/client/setTextContent.js index cc246a52eb641..6fb7e78bb64ad 100644 --- a/packages/react-dom/src/client/setTextContent.js +++ b/packages/react-dom/src/client/setTextContent.js @@ -8,7 +8,6 @@ import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'; import setInnerHTML from './setInnerHTML'; -import escapeTextContentForBrowser from '../shared/escapeTextContentForBrowser'; import {TEXT_NODE} from '../shared/HTMLNodeType'; /** @@ -37,16 +36,4 @@ var 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/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index 5568ab504ef28..627a474ca5d05 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -33,7 +33,7 @@ import { import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes'; import assertValidProps from '../shared/assertValidProps'; import dangerousStyleValue from '../shared/dangerousStyleValue'; -import escapeTextContentForBrowser from '../shared/escapeTextContentForBrowser'; +import escapeText from '../shared/escapeText'; import isCustomComponent from '../shared/isCustomComponent'; import omittedCloseTags from '../shared/omittedCloseTags'; import warnValidStyle from '../shared/warnValidStyle'; @@ -209,7 +209,7 @@ function getNonChildrenInnerMarkup(props) { } else { var content = props.children; if (typeof content === 'string' || typeof content === 'number') { - return escapeTextContentForBrowser(content); + return escapeText(content); } } return null; @@ -574,13 +574,13 @@ class ReactDOMServerRenderer { return ''; } if (this.makeStaticMarkup) { - return escapeTextContentForBrowser(text); + return escapeText(text); } if (this.previousWasTextNode) { - return '' + escapeTextContentForBrowser(text); + return '' + escapeText(text); } this.previousWasTextNode = true; - return escapeTextContentForBrowser(text); + return escapeText(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/shared/escapeText.js similarity index 97% rename from packages/react-dom/src/shared/escapeTextContentForBrowser.js rename to packages/react-dom/src/shared/escapeText.js index 8d086dfd72e5b..193028b42ac24 100644 --- a/packages/react-dom/src/shared/escapeTextContentForBrowser.js +++ b/packages/react-dom/src/shared/escapeText.js @@ -98,7 +98,7 @@ function escapeHtml(string) { * @param {*} text Text value to escape. * @return {string} An escaped string. */ -function escapeTextContentForBrowser(text) { +function escapeTextContent(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 escapeTextContent; diff --git a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js b/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js index feeeb055a7363..64efe4097bb18 100644 --- a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js +++ b/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import escapeTextContentForBrowser from './escapeTextContentForBrowser'; +import escapeText from './escapeText'; /** * 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 '"' + escapeText(value) + '"'; } export default quoteAttributeValueForBrowser; From 4214c61b9fd97ab008fa3b4cb6978533956b4c8f Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Wed, 8 Nov 2017 01:20:50 -0300 Subject: [PATCH 02/10] Fix lint errors --- packages/react-dom/src/client/setTextContent.js | 3 --- packages/react-dom/src/shared/escapeText.js | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/react-dom/src/client/setTextContent.js b/packages/react-dom/src/client/setTextContent.js index 6fb7e78bb64ad..2c1c262a51fee 100644 --- a/packages/react-dom/src/client/setTextContent.js +++ b/packages/react-dom/src/client/setTextContent.js @@ -5,9 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'; - -import setInnerHTML from './setInnerHTML'; import {TEXT_NODE} from '../shared/HTMLNodeType'; /** diff --git a/packages/react-dom/src/shared/escapeText.js b/packages/react-dom/src/shared/escapeText.js index 193028b42ac24..d7708b0e52a68 100644 --- a/packages/react-dom/src/shared/escapeText.js +++ b/packages/react-dom/src/shared/escapeText.js @@ -98,7 +98,7 @@ function escapeHtml(string) { * @param {*} text Text value to escape. * @return {string} An escaped string. */ -function escapeTextContent(text) { +function escapeText(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 escapeTextContent(text) { return escapeHtml(text); } -export default escapeTextContent; +export default escapeText; From e6da94136764d9592c565284dac8be5ef04c4c64 Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Fri, 10 Nov 2017 15:13:15 -0300 Subject: [PATCH 03/10] Prettier reformatting --- .../__tests__/quoteAttributeValueForBrowser-test.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js index f8b00c13d2ef7..66d68ec53a11c 100644 --- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js +++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js @@ -16,7 +16,6 @@ var ReactDOMServer; var ROOT_ATTRIBUTE_NAME; describe('quoteAttributeValueForBrowser', () => { - beforeEach(() => { jest.resetModules(); React = require('react'); @@ -40,7 +39,7 @@ describe('quoteAttributeValueForBrowser', () => { }); it('double quote is escaped inside attributes', () => { - var response = ReactDOMServer.renderToString(); + var response = ReactDOMServer.renderToString(); expect(response).toMatch( new RegExp( '', @@ -60,18 +59,14 @@ describe('quoteAttributeValueForBrowser', () => { it('greater than entity is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( - new RegExp( - '', - ), + new RegExp(''), ); }); it('lower than entity is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( - new RegExp( - '', - ), + new RegExp(''), ); }); }); From 472785652cfaaaa97b9929642caf2054e7c4fc85 Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Fri, 10 Nov 2017 15:22:01 -0300 Subject: [PATCH 04/10] Change syntax to prevent prettier escape doble quote --- .../src/__tests__/quoteAttributeValueForBrowser-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js index 66d68ec53a11c..b802ee63f8ff3 100644 --- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js +++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js @@ -39,7 +39,7 @@ describe('quoteAttributeValueForBrowser', () => { }); it('double quote is escaped inside attributes', () => { - var response = ReactDOMServer.renderToString(); + var response = ReactDOMServer.renderToString(); expect(response).toMatch( new RegExp( '', From 52b3f907d32205ffcd4043c41d860383059e8153 Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Mon, 20 Nov 2017 19:23:51 -0300 Subject: [PATCH 05/10] Name and description gardening. Add tests for escapeTextForBrowser. Add missing tests --- .../__tests__/escapeTextForBrowser-test.js | 89 +++++++++++++++++++ .../quoteAttributeValueForBrowser-test.js | 38 +++++++- .../src/server/ReactPartialRenderer.js | 10 +-- ...{escapeText.js => escapeTextForBrowser.js} | 8 +- .../shared/quoteAttributeValueForBrowser.js | 4 +- 5 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 packages/react-dom/src/__tests__/escapeTextForBrowser-test.js rename packages/react-dom/src/shared/{escapeText.js => escapeTextForBrowser.js} (93%) 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 0000000000000..d60c790860f2b --- /dev/null +++ b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js @@ -0,0 +1,89 @@ +/** + * 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 ExecutionEnvironment; +var React; +var ReactDOMServer; + +var ROOT_ATTRIBUTE_NAME; + +describe('escapeTextForBrowser', () => { + beforeEach(() => { + jest.resetModules(); + React = require('react'); + + ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); + ExecutionEnvironment.canUseDOM = false; + ReactDOMServer = require('react-dom/server'); + + var DOMProperty = require('../shared/DOMProperty'); + ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; + }); + + it('ampersand is escaped when passed as text content', () => { + var response = ReactDOMServer.renderToString({'&'}); + expect(response).toMatch( + new RegExp('&'), + ); + }); + + it('double quote is escaped when passed as text content', () => { + var response = ReactDOMServer.renderToString({'"'}); + expect(response).toMatch( + new RegExp('"'), + ); + }); + + it('single quote is escaped when passed as text content', () => { + var response = ReactDOMServer.renderToString({"'"}); + expect(response).toMatch( + new RegExp('''), + ); + }); + + it('greater than entity is escaped when passed as text content', () => { + var response = ReactDOMServer.renderToString({'>'}); + expect(response).toMatch( + new RegExp('>'), + ); + }); + + it('lower than entity is escaped when passed as text content', () => { + var response = ReactDOMServer.renderToString({'<'}); + expect(response).toMatch( + new RegExp('<'), + ); + }); + + it('number is correctly passed as text content', () => { + var response = ReactDOMServer.renderToString({42}); + expect(response).toMatch( + new RegExp('42'), + ); + }); + + it('number is escaped to string when passed as text content', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp(''), + ); + }); + + it('escape text content representing a script tag', () => { + var response = ReactDOMServer.renderToString( + {''}, + ); + expect(response).not.toContain(''); + expect(response).not.toContain("'"); + expect(response.substr(1, -1)).not.toContain('"'); + }); +}); diff --git a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js index b802ee63f8ff3..a19bb4f9b33ce 100644 --- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js +++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js @@ -24,7 +24,6 @@ describe('quoteAttributeValueForBrowser', () => { ExecutionEnvironment.canUseDOM = false; ReactDOMServer = require('react-dom/server'); - // TODO: can we express this test with only public API? var DOMProperty = require('../shared/DOMProperty'); ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; }); @@ -69,4 +68,41 @@ describe('quoteAttributeValueForBrowser', () => { new RegExp(''), ); }); + + it('number is escaped to string inside attributes', () => { + var response = ReactDOMServer.renderToString(); + expect(response).toMatch( + new RegExp(''), + ); + }); + + it('object is passed to a string inside attributes', () => { + var sampleObject = { + toString: function() { + return 'ponys'; + }, + }; + + var response = ReactDOMServer.renderToString( + , + ); + expect(response).toMatch( + new RegExp( + '', + ), + ); + }); + + it('script tag is escaped inside attributes', () => { + var response = ReactDOMServer.renderToString( + '} />, + ); + expect(response).toMatch( + new RegExp( + '', + ), + ); + }); }); diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index 627a474ca5d05..8c6595ab3f656 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -33,7 +33,7 @@ import { import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes'; import assertValidProps from '../shared/assertValidProps'; import dangerousStyleValue from '../shared/dangerousStyleValue'; -import escapeText from '../shared/escapeText'; +import escapeTextForBrowser from '../shared/escapeTextForBrowser'; import isCustomComponent from '../shared/isCustomComponent'; import omittedCloseTags from '../shared/omittedCloseTags'; import warnValidStyle from '../shared/warnValidStyle'; @@ -209,7 +209,7 @@ function getNonChildrenInnerMarkup(props) { } else { var content = props.children; if (typeof content === 'string' || typeof content === 'number') { - return escapeText(content); + return escapeTextForBrowser(content); } } return null; @@ -574,13 +574,13 @@ class ReactDOMServerRenderer { return ''; } if (this.makeStaticMarkup) { - return escapeText(text); + return escapeTextForBrowser(text); } if (this.previousWasTextNode) { - return '' + escapeText(text); + return '' + escapeTextForBrowser(text); } this.previousWasTextNode = true; - return escapeText(text); + return escapeTextForBrowser(text); } else { var nextChild; ({child: nextChild, context} = resolve(child, context)); diff --git a/packages/react-dom/src/shared/escapeText.js b/packages/react-dom/src/shared/escapeTextForBrowser.js similarity index 93% rename from packages/react-dom/src/shared/escapeText.js rename to packages/react-dom/src/shared/escapeTextForBrowser.js index d7708b0e52a68..5b8245a93592f 100644 --- a/packages/react-dom/src/shared/escapeText.js +++ b/packages/react-dom/src/shared/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 escapeText(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 escapeText(text) { return escapeHtml(text); } -export default escapeText; +export default escapeTextForBrowser; diff --git a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js b/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js index 64efe4097bb18..592aab6a25e97 100644 --- a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js +++ b/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import escapeText from './escapeText'; +import escapeTextForBrowser from './escapeTextForBrowser'; /** * Escapes attribute value to prevent scripting attacks. @@ -14,7 +14,7 @@ import escapeText from './escapeText'; * @return {string} An escaped string. */ function quoteAttributeValueForBrowser(value) { - return '"' + escapeText(value) + '"'; + return '"' + escapeTextForBrowser(value) + '"'; } export default quoteAttributeValueForBrowser; From 095dd7017280c0d9b34667f4e212fd2d9aaf07f5 Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Mon, 20 Nov 2017 19:46:37 -0300 Subject: [PATCH 06/10] Improve script tag as text content test --- .../src/__tests__/escapeTextForBrowser-test.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js index d60c790860f2b..a0e81669f4eb6 100644 --- a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js +++ b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js @@ -81,9 +81,12 @@ describe('escapeTextForBrowser', () => { var response = ReactDOMServer.renderToString( {''}, ); - expect(response).not.toContain(''); - expect(response).not.toContain("'"); - expect(response.substr(1, -1)).not.toContain('"'); + expect(response).toMatch( + new RegExp( + '<script type='' src=""></script>', + ), + ); }); }); From 895a01cbfdc7e6c8d93a4e0d203314c7513ba9c6 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 23 Nov 2017 22:05:18 +0000 Subject: [PATCH 07/10] Update escapeTextForBrowser-test.js --- .../__tests__/escapeTextForBrowser-test.js | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js index a0e81669f4eb6..88968b4df0c00 100644 --- a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js +++ b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js @@ -9,71 +9,62 @@ 'use strict'; -var ExecutionEnvironment; var React; var ReactDOMServer; -var ROOT_ATTRIBUTE_NAME; - describe('escapeTextForBrowser', () => { beforeEach(() => { jest.resetModules(); React = require('react'); - - ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); - ExecutionEnvironment.canUseDOM = false; ReactDOMServer = require('react-dom/server'); - - var DOMProperty = require('../shared/DOMProperty'); - ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; }); it('ampersand is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'&'}); expect(response).toMatch( - new RegExp('&'), + new RegExp('&'), ); }); it('double quote is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'"'}); expect(response).toMatch( - new RegExp('"'), + new RegExp('"'), ); }); it('single quote is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({"'"}); expect(response).toMatch( - new RegExp('''), + new RegExp('''), ); }); it('greater than entity is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'>'}); expect(response).toMatch( - new RegExp('>'), + new RegExp('>'), ); }); it('lower than entity is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'<'}); expect(response).toMatch( - new RegExp('<'), + new RegExp('<'), ); }); it('number is correctly passed as text content', () => { var response = ReactDOMServer.renderToString({42}); expect(response).toMatch( - new RegExp('42'), + new RegExp('42'), ); }); it('number is escaped to string when passed as text content', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( - new RegExp(''), + new RegExp(''), ); }); @@ -83,9 +74,8 @@ describe('escapeTextForBrowser', () => { ); expect(response).toMatch( new RegExp( - '<script type='' src=""></script>', + '<script type='' ' + + 'src=""></script>', ), ); }); From 3a36d1afc199b1072e0792d54681fbfc5b67a800 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 23 Nov 2017 22:06:53 +0000 Subject: [PATCH 08/10] Update quoteAttributeValueForBrowser-test.js --- .../quoteAttributeValueForBrowser-test.js | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js index a19bb4f9b33ce..e1ca87be26164 100644 --- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js +++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js @@ -9,30 +9,21 @@ 'use strict'; -var ExecutionEnvironment; var React; var ReactDOMServer; -var ROOT_ATTRIBUTE_NAME; - describe('quoteAttributeValueForBrowser', () => { beforeEach(() => { jest.resetModules(); React = require('react'); - - ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); - ExecutionEnvironment.canUseDOM = false; ReactDOMServer = require('react-dom/server'); - - var DOMProperty = require('../shared/DOMProperty'); - ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; }); it('ampersand is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( new RegExp( - '', + '', ), ); }); @@ -41,7 +32,7 @@ describe('quoteAttributeValueForBrowser', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( new RegExp( - '', + '', ), ); }); @@ -50,7 +41,7 @@ describe('quoteAttributeValueForBrowser', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( new RegExp( - '', + '', ), ); }); @@ -58,21 +49,21 @@ describe('quoteAttributeValueForBrowser', () => { it('greater than entity is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( - new RegExp(''), + new RegExp(''), ); }); it('lower than entity is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( - new RegExp(''), + new RegExp(''), ); }); it('number is escaped to string inside attributes', () => { var response = ReactDOMServer.renderToString(); expect(response).toMatch( - new RegExp(''), + new RegExp(''), ); }); @@ -88,7 +79,7 @@ describe('quoteAttributeValueForBrowser', () => { ); expect(response).toMatch( new RegExp( - '', + '', ), ); }); @@ -99,9 +90,9 @@ describe('quoteAttributeValueForBrowser', () => { ); expect(response).toMatch( new RegExp( - '', + '', ), ); }); From 058babeec4ce117a3abe21f21308c332c9bcc6c5 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 23 Nov 2017 22:15:26 +0000 Subject: [PATCH 09/10] Simplify tests --- .../__tests__/escapeTextForBrowser-test.js | 32 ++++---------- .../quoteAttributeValueForBrowser-test.js | 42 ++++--------------- 2 files changed, 17 insertions(+), 57 deletions(-) diff --git a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js index 88968b4df0c00..a76cacb7fdf65 100644 --- a/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js +++ b/packages/react-dom/src/__tests__/escapeTextForBrowser-test.js @@ -21,51 +21,37 @@ describe('escapeTextForBrowser', () => { it('ampersand is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'&'}); - expect(response).toMatch( - new RegExp('&'), - ); + expect(response).toMatch('&'); }); it('double quote is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'"'}); - expect(response).toMatch( - new RegExp('"'), - ); + expect(response).toMatch('"'); }); it('single quote is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({"'"}); - expect(response).toMatch( - new RegExp('''), - ); + expect(response).toMatch('''); }); it('greater than entity is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'>'}); - expect(response).toMatch( - new RegExp('>'), - ); + expect(response).toMatch('>'); }); it('lower than entity is escaped when passed as text content', () => { var response = ReactDOMServer.renderToString({'<'}); - expect(response).toMatch( - new RegExp('<'), - ); + expect(response).toMatch('<'); }); it('number is correctly passed as text content', () => { var response = ReactDOMServer.renderToString({42}); - expect(response).toMatch( - new RegExp('42'), - ); + expect(response).toMatch('42'); }); it('number is escaped to string when passed as text content', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp(''), - ); + expect(response).toMatch(''); }); it('escape text content representing a script tag', () => { @@ -73,10 +59,8 @@ describe('escapeTextForBrowser', () => { {''}, ); expect(response).toMatch( - new RegExp( - '<script type='' ' + + '<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 e1ca87be26164..1a0db78037f2d 100644 --- a/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js +++ b/packages/react-dom/src/__tests__/quoteAttributeValueForBrowser-test.js @@ -21,50 +21,32 @@ describe('quoteAttributeValueForBrowser', () => { it('ampersand is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp( - '', - ), - ); + expect(response).toMatch(''); }); it('double quote is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp( - '', - ), - ); + expect(response).toMatch(''); }); it('single quote is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp( - '', - ), - ); + expect(response).toMatch(''); }); it('greater than entity is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp(''), - ); + expect(response).toMatch(''); }); it('lower than entity is escaped inside attributes', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp(''), - ); + expect(response).toMatch(''); }); it('number is escaped to string inside attributes', () => { var response = ReactDOMServer.renderToString(); - expect(response).toMatch( - new RegExp(''), - ); + expect(response).toMatch(''); }); it('object is passed to a string inside attributes', () => { @@ -77,11 +59,7 @@ describe('quoteAttributeValueForBrowser', () => { var response = ReactDOMServer.renderToString( , ); - expect(response).toMatch( - new RegExp( - '', - ), - ); + expect(response).toMatch(''); }); it('script tag is escaped inside attributes', () => { @@ -89,11 +67,9 @@ describe('quoteAttributeValueForBrowser', () => { '} />, ); expect(response).toMatch( - new RegExp( - '', - ), + 'data-reactroot=""/>', ); }); }); From f6f503d4bb4cd1daea9e67a66a10c2f5feb17c71 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 23 Nov 2017 22:28:44 +0000 Subject: [PATCH 10/10] Move utilities to server folder --- packages/react-dom/src/server/DOMMarkupOperations.js | 2 +- packages/react-dom/src/server/ReactPartialRenderer.js | 2 +- .../react-dom/src/{shared => server}/escapeTextForBrowser.js | 0 .../src/{shared => server}/quoteAttributeValueForBrowser.js | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename packages/react-dom/src/{shared => server}/escapeTextForBrowser.js (100%) rename packages/react-dom/src/{shared => server}/quoteAttributeValueForBrowser.js (100%) diff --git a/packages/react-dom/src/server/DOMMarkupOperations.js b/packages/react-dom/src/server/DOMMarkupOperations.js index d85fe050ab905..b86f6fd601726 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 83077cc47eea6..c76a311aac3b7 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 escapeTextForBrowser from '../shared/escapeTextForBrowser'; import isCustomComponent from '../shared/isCustomComponent'; import omittedCloseTags from '../shared/omittedCloseTags'; import warnValidStyle from '../shared/warnValidStyle'; diff --git a/packages/react-dom/src/shared/escapeTextForBrowser.js b/packages/react-dom/src/server/escapeTextForBrowser.js similarity index 100% rename from packages/react-dom/src/shared/escapeTextForBrowser.js rename to packages/react-dom/src/server/escapeTextForBrowser.js diff --git a/packages/react-dom/src/shared/quoteAttributeValueForBrowser.js b/packages/react-dom/src/server/quoteAttributeValueForBrowser.js similarity index 100% rename from packages/react-dom/src/shared/quoteAttributeValueForBrowser.js rename to packages/react-dom/src/server/quoteAttributeValueForBrowser.js