@webqit/oohtml
Version:
A suite of new DOM features that brings language support for modern UI development paradigms: a component-based architecture, data binding, and reactivity.
217 lines (187 loc) • 9.68 kB
JavaScript
/**
* @imports
*/
import { expect } from 'chai';
import { createDocument, createDocumentPrefixed, mockRemoteFetch, delay } from './index.js';
describe(`HTML Imports`, function() {
describe( `Basic...`, function() {
const head = `
<template def="temp0">
<p>Hello world Export</p>
<p>Hellort</p>
</template>`;
const body = `
<import ref="temp0#"></import>`;
const { document } = createDocument( head, body );
it ( `The document object and <template> elements should expose an "import" property`, async function() {
expect( document ).to.have.property( 'import' );
} );
it ( `<import> element be automatically resolved: import default export...`, async function() {
expect( document.body.children ).to.have.length( 2 );
expect( document.body.firstElementChild.nodeName ).to.eq( 'P' );
} );
it( `<import> element be resolved again: after having mutated an export right at its module.`, async function() {
const templateEl = document.querySelector( 'template' );
let added = document.createElement( 'div' );
templateEl.content.appendChild( added );
console.log('\n\n\n\n', document.body.outerHTML);
expect( document.body.children ).to.have.length( 3 );
} );
} );
describe( `Dynamic...`, function() {
const head = `
<template wq-def="temp0">
<!-- ------- -->
<p>Hello world Export</p>
<p>Hellort</p>
<input wq-def="input" />
<template wq-def="temp1">
<textarea wq-def="input"></textarea>
<template wq-def="temp2">
<select wq-def="input"></select>
</template>
</template>
<!-- ------- -->
<template wq-def="_landing1">
<div wq-def="main.html">a</div>
<template wq-def="_landing2">
<div wq-def="main.html">b</div>
<template wq-def="_docs">
<div wq-def="main.html">c</div>
</template>
</template>
</template>
<!-- ------- -->
<template wq-def="landing1" wq-extends="_landing1">
<div wq-def="README.md">1</div>
<template wq-def="landing2" wq-extends="_landing2">
<div wq-def="README.md">2</div>
<template wq-def="docs" wq-extends="_docs">
<div wq-def="README.md">3</div>
</template>
</template>
</template>
<!-- ------- -->
</template>`;
const body = `
<wq-import wq-ref="temp0/uuu"></wq-import>`;
const { document } = createDocumentPrefixed( 'wq', head, body );
const importEl = document.querySelector( 'wq-import' );
it ( `<import> element should not be resolved: no match for given import ID...`, async function() {
expect( document.body.firstElementChild.nodeName ).to.eq( 'WQ-IMPORT' );
} );
it ( `<import> element should be automatically resolved: new import ID is set...`, async function() {
importEl.setAttribute( 'wq-ref', 'temp0#input' );
expect( document.body.firstElementChild.nodeName ).to.eq( 'INPUT' );
} );
it ( `<import> element should be automatically resolved: new moduleref is set - nested...`, async function() {
importEl.setAttribute( 'wq-ref', 'temp0/temp1#input' );
expect( document.body.firstElementChild.nodeName ).to.eq( 'TEXTAREA' );
} );
it ( `<import> element should be automatically resolved: moduleref is unset - should now be inherited from <body>...`, async function() {
importEl.setAttribute( 'wq-ref', '#input' );
expect( document.body.firstElementChild.nodeName ).to.eq( 'WQ-IMPORT' );
document.body.setAttribute( 'wq-importscontext', 'temp0/temp1/temp2' );
expect( document.body.firstElementChild.nodeName ).to.eq( 'SELECT' );
} );
it ( `<import> element should be automatically resolved: moduleref at <body> is changed...`, async function() {
document.body.setAttribute( 'wq-importscontext', 'temp0' );
expect( document.body.firstElementChild.nodeName ).to.eq( 'INPUT' );
} );
it ( `<import> element should be automatically RESTORED: slotted element is removed from DOM...`, async function() {
document.body.querySelector( 'input' ).remove();
expect( document.body.firstElementChild.nodeName ).to.eq( 'WQ-IMPORT' );
} );
} );
describe( `Remote...`, function() {
it( `<import> element from nested remote modules.`, async function() {
this.timeout( 10000 );
const head = ``, body = ``, timeout = 2000;
const window = createDocument( head, body, window => {
// Define a remote response
const contents0 = `
<template def="temp1" src="/temp1.html" loading="lazy"></template>`;
const contents1 = `
<p>Hello world Export</p>
<p>Hellort</p>
<template def="temp22">
</template>`;
mockRemoteFetch( window, { '/temp0.html': contents0, '/temp1.html': contents1 }, timeout );
} ), document = window.document;
// Add a remote module
const templateEl = document.createElement( 'template' );
templateEl.setAttribute( 'def', 'temp0' );
templateEl.setAttribute( 'src', '/temp0.html' );
document.head.appendChild( templateEl );
// Add the import element to with a view to waiting for the remote module
const importEl = document.createElement( 'import' );
importEl.setAttribute( 'ref', 'temp0/temp1' );
document.body.appendChild( importEl );
// Should stil be waiting...
expect( document.body.firstElementChild.nodeName ).to.eq( 'IMPORT' );
// When remote request must have completed
await delay( ( timeout * 2 ) + 150 );
expect( document.body.firstElementChild.nodeName ).to.eq( 'P' );
expect( document.body.lastElementChild.nodeName ).to.eq( 'P' );
} );
} );
describe( `Hydration...`, function() {
it ( `Server-resolved <import> element should maintain relationship with slotted elements...`, async function() {
const head = `
<template def="temp0">
<input def="input" />
<template def="temp1">
<textarea def="input"></textarea>
<template def="temp2">
<select def="input"></select>
</template>
</template>
</template>`;
const body = `
<div importscontext="temp0/temp1">
<textarea def="input"></textarea>
<!--<import ref="#input" data-nodecount="1"></import>-->
</div>`;
const { document } = createDocument( head, body, window => window.webqit.env = 'client' );
await delay( 20 );
const routingElement = document.body.firstElementChild;
expect( routingElement.firstElementChild.nodeName ).to.eq( 'TEXTAREA' );
document.import( 'temp0/temp1', temp1 => {
const textarea = temp1.defs[ '#input' ];
textarea.remove();
expect( routingElement.firstElementChild.nodeName ).to.eq( 'IMPORT' );
temp1.content.prepend( textarea );
expect( routingElement.firstElementChild.nodeName ).to.eq( 'TEXTAREA' );
routingElement.firstElementChild.remove();
expect( routingElement.firstElementChild.nodeName ).to.eq( 'IMPORT' );
} );
} );
it ( `Server-resolved <import> element should maintain relationship with slotted elements...`, async function() {
const head = `
<template def="temp0">
<input def="input" />
<template def="temp1">
<textarea def="input"></textarea>
<template def="temp2">
<select def="input"></select>
</template>
</template>
</template>`;
const body = `
<div importscontext="temp0/temp1">
<textarea def="input"></textarea>
<!--<import ref="#input" data-nodecount="1"></import>-->
</div>`;
const { document } = createDocument( head, body, window => window.webqit.env = 'client' );
await delay( 20 );
const routingElement = document.body.firstElementChild;
expect( routingElement.firstElementChild.nodeName ).to.eq( 'TEXTAREA' );
routingElement.setAttribute( 'importscontext', 'temp0/temp1/temp2' );
expect( routingElement.firstElementChild.nodeName ).to.eq( 'SELECT' );
routingElement.removeChild( routingElement.firstElementChild );
expect( routingElement.firstElementChild.nodeName ).to.eq( 'IMPORT' );
routingElement.setAttribute( 'importscontext', 'temp0' );
expect( routingElement.firstElementChild.nodeName ).to.eq( 'INPUT' );
} );
} );
} );