diff --git a/src/__tests__/to-contain-html.js b/src/__tests__/to-contain-html.js index 6bfd95e..259e1fd 100644 --- a/src/__tests__/to-contain-html.js +++ b/src/__tests__/to-contain-html.js @@ -106,7 +106,15 @@ describe('.toContainHTML', () => { Expected:
non-existant element
Received: - + `) }) + + test('ignores attribute order when comparing HTML', () => { + const {container} = render('link') + const link = container.querySelector('a') + + expect(link).toContainHTML('link') + expect(link).toContainHTML('link') + }) }) diff --git a/src/to-contain-html.js b/src/to-contain-html.js index 30158ee..fd54e70 100644 --- a/src/to-contain-html.js +++ b/src/to-contain-html.js @@ -1,8 +1,26 @@ import {checkHtmlElement} from './utils' +function sortAttributes(root) { + const elements = [root, ...root.querySelectorAll('*')] + for (const el of elements) { + if (!el.attributes || el.attributes.length < 2) continue + const attrs = Array.from(el.attributes).sort((a, b) => + a.name.localeCompare(b.name), + ) + for (const attr of attrs) { + el.removeAttribute(attr.name) + } + for (const attr of attrs) { + el.setAttribute(attr.name, attr.value) + } + } +} + function getNormalizedHtml(container, htmlText) { const div = container.ownerDocument.createElement('div') div.innerHTML = htmlText + // Sort attributes so order differences do not affect matching or messages + sortAttributes(div) return div.innerHTML } @@ -13,8 +31,14 @@ export function toContainHTML(container, htmlText) { throw new Error(`.toContainHTML() expects a string value, got ${htmlText}`) } + const normalizedContainerHtml = getNormalizedHtml( + container, + container.outerHTML, + ) + const normalizedHtmlText = getNormalizedHtml(container, htmlText) + return { - pass: container.outerHTML.includes(getNormalizedHtml(container, htmlText)), + pass: normalizedContainerHtml.includes(normalizedHtmlText), message: () => { return [ this.utils.matcherHint( @@ -24,9 +48,10 @@ export function toContainHTML(container, htmlText) { ), 'Expected:', // eslint-disable-next-line new-cap - ` ${this.utils.EXPECTED_COLOR(htmlText)}`, + ` ${this.utils.EXPECTED_COLOR(normalizedHtmlText)}`, 'Received:', - ` ${this.utils.printReceived(container.cloneNode(true))}`, + // eslint-disable-next-line new-cap + ` ${this.utils.RECEIVED_COLOR(normalizedContainerHtml)}`, ].join('\n') }, }