Skip to content

Commit

Permalink
HTML parity test cases and Light DOM edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
thescientist13 committed Oct 19, 2024
1 parent 9a9af77 commit f070203
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 29 deletions.
78 changes: 52 additions & 26 deletions src/wcc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ import { importAttributes } from 'acorn-import-attributes';
import { transform } from 'sucrase';
import fs from 'fs';

const VOID_ELEMENTS = [
'area',
'base',
'br',
'col',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'menuitem',
'meta',
'param',
'source',
'track',
'wbr'
];

function getParse(html) {
return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
? parse
Expand Down Expand Up @@ -147,6 +166,38 @@ async function getTagName(moduleURL) {
return tagName;
}

function renderLightDomChildren(childNodes, iHTML = '') {
let innerHTML = iHTML;

childNodes.forEach((child) => {
const { nodeName, attrs = [], value } = child;

if (nodeName !== '#text') {
innerHTML += `<${nodeName}`;

if (attrs.length > 0) {
attrs.forEach(attr => {
innerHTML += ` ${attr.name}="${attr.value}"`;
});
}

innerHTML += '>';

if (child.childNodes.length > 0) {
innerHTML = renderLightDomChildren(child.childNodes, innerHTML);
}

innerHTML += VOID_ELEMENTS.includes(nodeName)
? ''
: `</${nodeName}>`;
} else if (nodeName === '#text') {
innerHTML += value;
}
});

return innerHTML;
}

async function initializeCustomElement(elementURL, tagName, node = {}, definitions = [], isEntry, props = {}) {
const { attrs = [], childNodes = [] } = node;

Expand All @@ -168,34 +219,9 @@ async function initializeCustomElement(elementURL, tagName, node = {}, definitio

if (element) {
const elementInstance = new element(data); // eslint-disable-line new-cap
let innerHTML = elementInstance.innerHTML || '';

// support for HTML (Light DOM) Web Components
childNodes.forEach((child) => {
const { nodeName, attrs = [] } = child;

if (nodeName !== '#text') {
innerHTML += `<${nodeName}`;

if (attrs.length > 0) {
attrs.forEach(attr => {
innerHTML += ` ${attr.name}="${attr.value}"`;
});
}

innerHTML += '>';

child.childNodes.forEach((c) => {
if (c.nodeName === '#text') {
innerHTML += c.value;
}
});

innerHTML += `</${nodeName}>`;
}
});

elementInstance.innerHTML = innerHTML;
elementInstance.innerHTML = renderLightDomChildren(childNodes);

attrs.forEach((attr) => {
elementInstance.setAttribute(attr.name, attr.value);
Expand Down
13 changes: 13 additions & 0 deletions test/cases/html-web-components/expected.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<wcc-picture-frame title="Greenwood">
<div class="picture-frame">
<img src="https://www.greenwoodjs.io/assets/greenwood-logo-og.png" alt="Greenwood logo">
<br>
<span>Author: <span>WCC</span></span>
<wcc-caption>
<div class="caption">
<h6 class="heading">Greenwood</h6>
<span>© 2024</span>
</div>
</wcc-caption>
</div>
</wcc-picture-frame>
13 changes: 11 additions & 2 deletions test/cases/html-web-components/html-web-components.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
import chai from 'chai';
import { JSDOM } from 'jsdom';
import fs from 'fs/promises';
import { renderToString } from '../../../src/wcc.js';

const expect = chai.expect;
Expand All @@ -24,12 +25,16 @@ describe('Run WCC For ', function() {
const LABEL = 'HTML (Light DOM) Web Components';
let dom;
let pictureFrame;
let expectedHtml;
let actualHtml;

before(async function() {
const { html } = await renderToString(new URL('./src/pages/index.js', import.meta.url));

dom = new JSDOM(html);
actualHtml = html;
dom = new JSDOM(actualHtml);
pictureFrame = dom.window.document.querySelectorAll('wcc-picture-frame');
expectedHtml = await fs.readFile(new URL('./expected.html', import.meta.url), 'utf-8');
});

describe(LABEL, function() {
Expand All @@ -50,7 +55,7 @@ describe('Run WCC For ', function() {
});

it('should have the expected Author name <span> from userland in the HTML', () => {
const img = pictureFrame[0].querySelectorAll('.picture-frame img + span');
const img = pictureFrame[0].querySelectorAll('.picture-frame img + br + span');

expect(img.length).to.equal(1);
expect(img[0].textContent).to.equal('Author: WCC');
Expand All @@ -72,5 +77,9 @@ describe('Run WCC For ', function() {
expect(span.length).to.equal(1);
expect(span[0].textContent).to.equal('© 2024');
});

it('should have the expected recursively generated HTML', () => {
expect(expectedHtml.replace(/ /g, '').replace(/\n/g, '')).to.equal(actualHtml.replace(/ /g, '').replace(/\n/g, ''));
});
});
});
3 changes: 2 additions & 1 deletion test/cases/html-web-components/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export default class HomePage extends HTMLElement {
src="https://www.greenwoodjs.io/assets/greenwood-logo-og.png"
alt="Greenwood logo"
/>
<span>Author: WCC</span>
<br/>
<span>Author: <span>WCC</span></span>
</wcc-picture-frame>
`;
}
Expand Down

0 comments on commit f070203

Please sign in to comment.