Skip to content
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

fix: normalize expected value in toContainHTML #349

Merged
merged 1 commit into from Mar 25, 2021

Conversation

just-boris
Copy link
Contributor

@just-boris just-boris commented Mar 18, 2021

What:

resolve #347

Why:

Because this is worth fixing

How:

Added getNormalizedHtml function, that passes the content to the HTML parser.

This caused two changes in the test case with invalid HTML: <span data-testid="child"></div> becomes <span data-testid="child"></span>

Checklist:

  • Documentation n/a
  • Tests
  • Updated Type Definitions n/a
  • Ready to be merged

@@ -18,21 +18,23 @@ describe('.toContainHTML', () => {
const nonExistantElement = queryByTestId('not-exists')
const fakeElement = {thisIsNot: 'an html element'}
const stringChildElement = '<span data-testid="child"></span>'
const incorrectStringHtml = '<span data-testid="child"></div>'
const stringChildElementSelfClosing = '<span data-testid="child" />'
// const incorrectStringHtml = '<span data-testid="child"></div>'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new change also normalizes this invalid HTML, so this also now passes:

expect(child).toContainHTML('<span data-testid="child"></div>');  // normalized to `<span data-testid="child"></span>`

@codecov
Copy link

codecov bot commented Mar 18, 2021

Codecov Report

Merging #349 (c0e8a1b) into main (84fe8e0) will not change coverage.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff            @@
##              main      #349   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           23        23           
  Lines          539       545    +6     
  Branches       199       200    +1     
=========================================
+ Hits           539       545    +6     
Impacted Files Coverage Δ
src/to-contain-html.js 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 84fe8e0...c0e8a1b. Read the comment docs.

Comment on lines +12 to +14
if (typeof htmlText !== 'string') {
throw new Error(`.toContainHTML() expects a string value, got ${htmlText}`)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this change, the nonExistantElement tests started failing. This value is basically an equivalent of expect(element).toContainHTML(null) which turned into a string.includes(null), producing false.

Now the htmlText always gets converted to a string, so this extra check is needed to keep the assertions failing where they were before.

@just-boris
Copy link
Contributor Author

just-boris commented Mar 18, 2021

Opened this as a draft, as there are two maybe-major changes, see the comments above.

I am open for a discussion how to proceed with that

@gnapse gnapse self-assigned this Mar 19, 2021
@gnapse
Copy link
Member

gnapse commented Mar 19, 2021

@just-boris Thanks for this! Can you take this PR to a valid non-draft state (e.g. uncomment or remove the commented code) so that I can review. I cannot get a full idea of what's going on or what you are proposing without knowing what about all that commented out code.

@just-boris
Copy link
Contributor Author

@gnapse
Updated the PR. It introduces two notable changes besides fixing the #347

  1. non-string values throw a different error now. It was an assertion error and now this is precise .toContainHTML() expects a string value, got ${htmlText}
  2. Invalid HTML gets normalised now, passing the assertion if the result is the same as the actual content

Copy link
Member

@gnapse gnapse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mostly OK with these changes. I left a comment on the only thing that worries me. Would like to hear what you think before merging this.

Comment on lines -32 to -35
expect(grandparent).not.toContainHTML(incorrectStringHtml)
expect(parent).not.toContainHTML(incorrectStringHtml)
expect(child).not.toContainHTML(incorrectStringHtml)
expect(child).not.toContainHTML(incorrectStringHtml)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to remove the test on the invalid html? What happens after these changes if we give invalid html like the one in this string? It'd be nice to know and add a test for that. And hopefully that what it does is still close to what one would expect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, the tests can stay, just need to flip the direction, as this assertion now passes.

Fixed in the next revision

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it that these tests now pass? I would expect them not to pass. The rendered DOM in this test does contain the invalid html given. 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTML parser ignores unmatching closing tags. Currently we have this content: <span data-testid="child"></div>. After normalization via innerHTML it becomes <span data-testid="child"></span> and this matches the actual content.

With normalization, this test will not pass, for example:

const {container} = render(`<table>
  <tr>
    <td>test</td>
  </tr>
</table>`)
expect(container).toContainHTML('<table>test</table>');

<table>test</table> does not expand to the full table and does not match the real content

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I wonder if we could detect that, and disallow invalid html. This also makes it technically a breaking change, although I'm thinking that I'll pass on that, since it is very unlikely someone was passing invalid html to explicitly expect a failure.

I think this is good to go. Will merge soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is possible without rolling your own parser. Built-in DOM parser does not expose enough information.

I am also wondering about the use-case here. Spotting the typos is nice, but is there any more important case where it is needed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, which is why I said I approve anyway. It's just a bit unintuitive, but I agree that it makes sense since it is how html works anyway. Developing our own parser is out of the question. This matcher is anyway an outlier, in the sense that we do not recommed its use except in some unique circumstances.

@gnapse gnapse merged commit 21ad89b into testing-library:main Mar 25, 2021
@gnapse
Copy link
Member

gnapse commented Mar 25, 2021

@all-contributors please add @just-boris for code, test, bug

@allcontributors
Copy link
Contributor

@gnapse

@just-boris already contributed before to code, test, bug

@github-actions
Copy link

🎉 This PR is included in version 5.11.10 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

toContainHTML does not handle self-closing tags
2 participants