-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Drop .textContent IE8 polyfill and rewrite escaping tests against public API #11331
Drop .textContent IE8 polyfill and rewrite escaping tests against public API #11331
Conversation
var testElement = document.createElement('div');
testElement.innerHTML = escapeTextContentForBrowser('&');
expect(testElement.innerHTML).toEqual('&'); Does not actually test If you want to test this in-terms of the public API I'm guessing it would be a better idea to do something along the lines of React.render(<div>{'&'}</div>, target);
target.firstChild.textContent === '&'; |
@syranide true that, as I described above the function I'm trying to test only runs in My best bet is to work again on this PR, mock up the |
@jeremenichelli I'm pretty sure it's used for SSR too, which I'm guessing would be the actual way to test this (my code doesn't actually test it I realize 😄). It should be used for SSR at least. |
Ah that's a good catch @syranide, I don't know how SSR works in React to be honest, but if it passes the I'm travelling to Buenos Aires for NodeConfAR now, so updates on this PR will have to wait til next week. |
If you're confident something is only used in IE8, let's change this PR to delete that instead. |
@gaearon I'm 100% sure this only applies in IE8 cases (which implemented
The only thing I need to know is if this condition passes while server side rendering:
If other contributors or users make sure SSRR doesn't need this, I will go on that path for sure. |
SSR doesn't need this. |
After some investigation, I noticed that Also it's used by Ideally the new roadmap would be to delete the We can re-check if the server tests satisfies the approach for quoted attributes and open a new issue. Let me know if you agree with this new direction. |
Sounds reasonable to me. |
dd7feec
to
a8785a5
Compare
Just updated this PR. I want to clarify the changes first.
A final note is that while doing this I didn't noticed tests for |
IMHO, that seems like a bad idea. There are many different ways to escape text/strings for the DOM, this is just one of them. At best it's confusing, at worst someone may use it to escape something they shouldn't (CSS, etc). EDIT: Although since it's being used for Also, I don't understand how it can only be used by @gaearon I'm also not sure why the current implementation is there, we had a far simpler and faster one "a long time ago"? Unrelated but the description of |
Hey, thanks for letting me know about this, @jeremenichelli! I haven't figured out how exactly to test I didn't realize I could use ReactDOMServer API. Now I've taken a look at your PR and your tests for It's awesome that you have done it! It's OK to merge this if approved, I'll be totally fine with it too! 👍 |
Thanks @andrevargas 💛 @syranide do you agree with changing the name to |
@syranide Do you plan to continue reviewing this PR? |
@gaearon Sorry, no time this week (full-day business meetings) and I'm not really on-top of your internal guidelines well enough to suggest something more than what I've already done I feel. My intention was just to add what I know/felt was missing seeing as I've touched this code before.
Sure. The implementation of |
@syranide well it's a small gardening, and it wouldn't harm the PR talk if we agree on one ahead of new commits. How about |
We're pretty separate from any internal guidelines by now. I fully trust your intuition here. :-) That said totally understand if you can't find the time. I'll try to dig in next week. |
@gaearon Just unusually busy this week, should have time this weekend :) |
it('should escape boolean to string', () => { | ||
expect(quoteAttributeValueForBrowser(true)).toBe('"true"'); | ||
expect(quoteAttributeValueForBrowser(false)).toBe('"false"'); | ||
// TODO: can we express this test with only public API? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can. Just embed it here :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lol, forgot to take it out.
expect(escapeTextContentForBrowser(false)).toBe('false'); | ||
}); | ||
|
||
it('should escape object to string', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which of the new tests verifies this?
}); | ||
|
||
it('should escape number to string', () => { | ||
expect(quoteAttributeValueForBrowser(42)).toBe('"42"'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question.
}); | ||
|
||
it('should escape string', () => { | ||
var escaped = quoteAttributeValueForBrowser( | ||
'<script type=\'\' src=""></script>', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test where this is literally the argument value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gaearon I'm thinking of creating tests for escapeText through the ReactDOMServer.renderToString API like these ones, do you think that it would make sense to write them? Also, if you do, shouldn't this test be placed there where the script would actually run?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking of creating tests for escapeText thourgh the ReactDOMServer.renderToString API like these ones
Sounds goood.
Also, if you do, shouldn't this test be placed there where the script would actually run?
Not sure what you mean. We just want to verify <script>
can't be injected as attribute value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, will add test on both escapeText and quoteAttribute tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above comments: let's make sure there is a corresponding test for each case we used to test before.
|
||
escaped = quoteAttributeValueForBrowser('&'); | ||
expect(escaped).toBe('"&"'); | ||
it('number is escaped to string inside attributes', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gaearon from here, tests for number, object and script tags on attributes have been added back. Above tests for text content in nodes contemplate these cases too, let me know if you ahve any more concerns or something that I might have missed.
|
||
escaped = quoteAttributeValueForBrowser('&'); | ||
expect(escaped).toBe('"&"'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the nice thing about these old tests is they didn't assert how we escape, only that we do escape. Which opens the door for changing that in the future.
Maybe it's not too important though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I didn't like form this test is that thy are just testing a switch
JavaScript statement by doing it directly from the module. These internal modules pass thourgh other checks and algorithms when applied, so someone could modify that code, prevent the script to actually escape the characters and test would still pass, something that won't happen now 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe an ideal test would actually create a DOM node, put content into innerHTML
and then assert that it only has a text node child with expected content?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that could be one way. Though werid since this is used only on the server package, maybe adding cases from renderToStaticMarkup
would be valuable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though werid since this is used only on the server package
Not sure what you mean. The end goal of rendering to a string is that the HTML shows up in somebody's browser :-) This is exactly what an integration test should verify: that what shows up in the browser would have been consistent with what we expect (as opposed to a dangerous script tag).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understood it better after writing my response but didn't want to edit it.
Yeah I guess that would mimic the text string from server to node conversion better than just testing the string. Let me know if you are planning on migrating to that. I might think about revisiting these tests in the future if necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you'd like to send a PR for this, happy to review. I'm not 100% sure it's the right approach but it seems to make sense to me.
…lic API (facebook#11331) * Rename escapeText util. Test quoteAttributeValueForBrowser through ReactDOMServer API * Fix lint errors * Prettier reformatting * Change syntax to prevent prettier escape doble quote * Name and description gardening. Add tests for escapeTextForBrowser. Add missing tests * Improve script tag as text content test * Update escapeTextForBrowser-test.js * Update quoteAttributeValueForBrowser-test.js * Simplify tests * Move utilities to server folder
…lic API (facebook#11331) * Rename escapeText util. Test quoteAttributeValueForBrowser through ReactDOMServer API * Fix lint errors * Prettier reformatting * Change syntax to prevent prettier escape doble quote * Name and description gardening. Add tests for escapeTextForBrowser. Add missing tests * Improve script tag as text content test * Update escapeTextForBrowser-test.js * Update quoteAttributeValueForBrowser-test.js * Simplify tests * Move utilities to server folder
…lic API (facebook#11331) * Rename escapeText util. Test quoteAttributeValueForBrowser through ReactDOMServer API * Fix lint errors * Prettier reformatting * Change syntax to prevent prettier escape doble quote * Name and description gardening. Add tests for escapeTextForBrowser. Add missing tests * Improve script tag as text content test * Update escapeTextForBrowser-test.js * Update quoteAttributeValueForBrowser-test.js * Simplify tests * Move utilities to server folder
I want to put some explanation about this test rewrite since I think the outcome might not be what was intended in #11299
escapeTextContentForBrowser
is used inclient/setTextContent.js
only whentextContent
is not supported for DOM elements, which only happens in IE8 (caniuse.com reference http://caniuse.com/#feat=textcontent) a browser version that is no longer supported (https://reactjs.org/blog/2016/01/12/discontinuing-ie8-support.html).To actually move this test to run over
ReactDOM.render
andReact.createElement
it would be necessary to mock up the entireglobal.document
object, assignnull
todocument.documentElement.textContent
, require React packages and then test this util through React element rendering. If authors and contributors think this should be the way to go I can start working again on this approach.Considering that this part of the code might not be running anywhere today in React web applications, my suggestion would be to not add this heavy lifting on the tests, reconsider modifying these tests by merging the changes I've made and actually start thinking about removing
escapeTextContentForBrowser
from the codebase.Since the support was dropped almost two years ago and we should start considering removing IE8 code.
Looking forward to read others take on this :)