Skip to content

Commit

Permalink
additional test cases and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
thescientist13 committed Oct 19, 2024
1 parent ecbe3b4 commit 9a9af77
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 56 deletions.
50 changes: 20 additions & 30 deletions src/wcc.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,27 @@ async function renderComponentRoots(tree, definitions) {
const { tagName } = node;

if (definitions[tagName]) {
console.log('renderComponentRoots', { tagName });
const { moduleURL } = definitions[tagName];
console.log({ node });
const elementInstance = await initializeCustomElement(moduleURL, tagName, node, definitions);
const hasShadow = elementInstance.shadowRoot;
const elementHtml = hasShadow
? elementInstance.getInnerHTML({ includeShadowRoots: true })
: elementInstance.innerHTML;
const elementTree = parseFragment(elementHtml);
const hasLight = elementTree.childNodes > 0;

console.log('elementHtml', { elementHtml });
console.log('elementTree', { elementTree });
console.log('elementTree.childNodes', elementTree.childNodes);
console.log('node.childNodes', node.childNodes);

node.childNodes = node.childNodes.length === 0 && hasLight && !hasShadow
? elementTree.childNodes
: hasShadow
? [...elementTree.childNodes, ...node.childNodes]
: elementTree.childNodes;

if (elementInstance) {
const hasShadow = elementInstance.shadowRoot;
const elementHtml = hasShadow
? elementInstance.getInnerHTML({ includeShadowRoots: true })
: elementInstance.innerHTML;
const elementTree = parseFragment(elementHtml);
const hasLight = elementTree.childNodes > 0;

node.childNodes = node.childNodes.length === 0 && hasLight && !hasShadow
? elementTree.childNodes
: hasShadow
? [...elementTree.childNodes, ...node.childNodes]
: elementTree.childNodes;
} else {
console.warn(`WARNING: customElement <${tagName}> detected but not serialized. You may not have exported it.`);
}
} else {
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it.`);
}
}

Expand Down Expand Up @@ -93,7 +91,7 @@ function registerDependencies(moduleURL, definitions, depth = 0) {
const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
const extension = specifier.split('.').pop();

// TODO would like to decouple .jsx from the core, ideally
// would like to decouple .jsx from the core, ideally
// https://github.com/ProjectEvergreen/wcc/issues/122
if (!isBareSpecifier && ['js', 'jsx', 'ts'].includes(extension)) {
const dependencyModuleURL = new URL(node.source.value, moduleURL);
Expand Down Expand Up @@ -151,7 +149,6 @@ async function getTagName(moduleURL) {

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

if (!tagName) {
const depth = isEntry ? 1 : 0;
Expand All @@ -173,12 +170,7 @@ async function initializeCustomElement(elementURL, tagName, node = {}, definitio
const elementInstance = new element(data); // eslint-disable-line new-cap
let innerHTML = elementInstance.innerHTML || '';

// TODO
// 1. Needs to be recursive
// 2. ~~Needs to handle attributes~~
// 3. Needs to handle duplicate content
// 4. Needs to handle self closing tags
// 5. handle all node types
// support for HTML (Light DOM) Web Components
childNodes.forEach((child) => {
const { nodeName, attrs = [] } = child;

Expand All @@ -203,9 +195,7 @@ async function initializeCustomElement(elementURL, tagName, node = {}, definitio
}
});

console.log({ innerHTML });
elementInstance.innerHTML = innerHTML;
console.log('=================');

attrs.forEach((attr) => {
elementInstance.setAttribute(attr.name, attr.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* User Workspace
* src/
* components/
* caption.js
* picture-frame.js
* pages/
* index.js
Expand All @@ -20,7 +21,7 @@ import { renderToString } from '../../../src/wcc.js';
const expect = chai.expect;

describe('Run WCC For ', function() {
const LABEL = 'HTML Web Component';
const LABEL = 'HTML (Light DOM) Web Components';
let dom;
let pictureFrame;

Expand All @@ -40,7 +41,22 @@ describe('Run WCC For ', function() {
expect(pictureFrame.length).to.equal(1);
});

it('should have the expected title attribute content in a nested <wcc-caption> tag', () => {
it('should have the expected image from userland in the HTML', () => {
const img = pictureFrame[0].querySelectorAll('.picture-frame img');

expect(img.length).to.equal(1);
expect(img[0].getAttribute('alt')).to.equal('Greenwood logo');
expect(img[0].getAttribute('src')).to.equal('https://www.greenwoodjs.io/assets/greenwood-logo-og.png');
});

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

expect(img.length).to.equal(1);
expect(img[0].textContent).to.equal('Author: WCC');
});

it('should have the expected title attribute content in the nested <wcc-caption> tag', () => {
const caption = pictureFrame[0].querySelectorAll('.picture-frame wcc-caption .caption');
const heading = caption[0].querySelectorAll('.heading');

Expand All @@ -49,12 +65,12 @@ describe('Run WCC For ', function() {
expect(heading[0].textContent).to.equal('Greenwood');
});

it('should have the expected image from userland in the HTML', () => {
const img = pictureFrame[0].querySelectorAll('.picture-frame img');
it('should have the expected copyright content in the nested <wcc-caption> tag', () => {
const caption = pictureFrame[0].querySelectorAll('.picture-frame wcc-caption .caption');
const span = caption[0].querySelectorAll('span');

expect(img.length).to.equal(1);
expect(img[0].getAttribute('alt')).to.equal('Greenwood logo');
expect(img[0].getAttribute('src')).to.equal('https://www.greenwoodjs.io/assets/greenwood-logo-og.png');
expect(span.length).to.equal(1);
expect(span[0].textContent).to.equal('© 2024');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ export default class PictureFrame extends HTMLElement {

this.innerHTML = `
<div class="picture-frame">
${this.innerHTML}
<wcc-caption>
<h6 class="heading">${title}</h6>
<span>&copy; 2024</span>
</wcc-caption>
${this.innerHTML}
</div>
`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default class HomePage extends HTMLElement {
src="https://www.greenwoodjs.io/assets/greenwood-logo-og.png"
alt="Greenwood logo"
/>
<span>Author: WCC</span>
</wcc-picture-frame>
`;
}
Expand Down
80 changes: 80 additions & 0 deletions test/cases/no-define/no-define.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Use Case
* Run wcc against a single custom element using with no customElements.define
*
* User Result
* Should run without any errors from the DOM shim.
*
* User Workspace
* src/
* no-define.js
* footer.js
* header.js
*/

import chai from 'chai';
import { renderToString, renderFromHTML } from '../../../src/wcc.js';

const expect = chai.expect;

describe('Run WCC For ', function() {
const LABEL = 'Single Custom Element with no customElements.define';

describe(LABEL, function() {
describe('renderToString', () => {
let rawHtml;
let meta;

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

rawHtml = html;
meta = metadata;
});

it('should not throw an error', function() {
expect(rawHtml).to.equal(undefined);
});

it('should not have any definition', function() {
expect(meta.length).to.equal(0);
});
});

describe('renderFromHTML', () => {
let rawHtml;
let meta;
const contents = `
<html>
<head>
<title>No Export Test</title>
</head>
<body>
<app-no-define-header></app-no-define-header>
<h1>Hello World</h1>
<app-no-define-footer></app-no-define-footer>
</body>
</html>
`;

before(async function() {
const { html, metadata } = await renderFromHTML(contents, [
new URL('./src/footer.js', import.meta.url),
new URL('./src/header.js', import.meta.url)
]);

rawHtml = html;
meta = metadata;
});

it('should not throw an error and return the expected contents', function() {
expect(rawHtml.replace(/ /g, '').replace(/\n/g, '')).to.equal(contents.replace(/ /g, '').replace(/\n/g, ''));
});

// I think this is broken, should actually be equal to 2?
it('should not have any definition', function() {
expect(meta.length).to.equal(0);
});
});
});
});
16 changes: 16 additions & 0 deletions test/cases/no-define/src/footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const template = document.createElement('template');

template.innerHTML = '<footer>This is the footer component.</footer>';

class FooterComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}

connectedCallback() {
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}

customElements.define('app-no-define-footer', FooterComponent);
18 changes: 18 additions & 0 deletions test/cases/no-define/src/header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const template = document.createElement('template');

template.innerHTML = `
<header>This is the header component.</header>
`;

class HeaderComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}

connectedCallback() {
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}

customElements.define('app-no-define-header', HeaderComponent);
15 changes: 15 additions & 0 deletions test/cases/no-define/src/no-define.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const template = document.createElement('template');

template.innerHTML = '<p>This is the NoDefineComponent component.</p>';

// eslint-disable-next-line no-unused-vars
class NoDefineComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}

connectedCallback() {
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
Loading

0 comments on commit 9a9af77

Please sign in to comment.