You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/test/html_equal.js

128 lines
3.1 KiB

import { assert } from 'vitest';
/** @type {HTMLDivElement} */
let _container;
/**
* @param {string} html
* @param {{
* removeDataSvelte?: boolean,
* preserveComments?: boolean,
* }} options
*/
export function normalize_html(html, options = {}) {
const container = (_container ??= document.createElement('div'));
if (!options.preserveComments) {
html = html.replace(/(<!--.*?-->)/g, '');
}
if (options.removeDataSvelte) {
html = html.replace(/(data-svelte-h="[^"]+")/g, '');
}
html = html.replace(/>[ \t\n\r\f]+</g, '><').trim();
container.innerHTML = html;
clean_children(container);
return container.innerHTML.replace(/<\/?noscript\/?>/g, '');
}
/** @param {any} node */
function clean_children(node) {
// sort attributes
const attributes = Array.from(node.attributes).sort((a, b) => (a.name < b.name ? -1 : 1));
attributes.forEach((attr) => {
node.removeAttribute(attr.name);
});
attributes.forEach((attr) => {
node.setAttribute(attr.name, attr.value);
});
let previous = null;
// recurse
[...node.childNodes].forEach((child) => {
if (child.nodeType === 3) {
// text
if (
node.namespaceURI === 'http://www.w3.org/2000/svg' &&
node.tagName !== 'text' &&
node.tagName !== 'tspan'
) {
node.removeChild(child);
}
child.data = child.data.replace(/[ \t\n\r\f]+/g, '\n');
if (previous && previous.nodeType === 3) {
previous.data += child.data;
previous.data = previous.data.replace(/[ \t\n\r\f]+/g, '\n');
node.removeChild(child);
child = previous;
}
} else if (child.nodeType === 8) {
// comment
// do nothing
} else {
clean_children(child);
}
previous = child;
});
// collapse whitespace
if (node.firstChild && node.firstChild.nodeType === 3) {
node.firstChild.data = node.firstChild.data.replace(/^[ \t\n\r\f]+/, '');
if (!node.firstChild.data.length) node.removeChild(node.firstChild);
}
if (node.lastChild && node.lastChild.nodeType === 3) {
node.lastChild.data = node.lastChild.data.replace(/[ \t\n\r\f]+$/, '');
if (!node.lastChild.data.length) node.removeChild(node.lastChild);
}
}
/**
*
* @param {string} actual
* @param {string} expected
* @param {{
* message?: string,
* normalize_html?: {
* removeDataSvelte?: boolean,
* preserveComments?: boolean,
* },
* without_normalize?: boolean,
* }} options
*/
export function assert_html_equal(actual, expected, options = {}) {
if (options.without_normalize) {
actual = actual.replace(/\r\n/g, '\n');
expected = expected.replace(/\r\n/g, '\n');
if (options.normalize_html.removeDataSvelte) {
actual = actual.replace(/(\sdata-svelte-h="[^"]+")/g, '');
expected = expected.replace(/(\sdata-svelte-h="[^"]+")/g, '');
}
} else {
actual = normalize_html(actual, options.normalize_html);
expected = normalize_html(expected, options.normalize_html);
}
try {
assert.equal(actual, expected, options.message);
} catch (err) {
// Remove this function from the stack trace so that the error is shown in the test file
if (Error.captureStackTrace) {
Error.captureStackTrace(err, assert_html_equal);
}
throw err;
}
}