Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ beforeEach(() => {
clearRegister();
});

function waitForMacroTask(fn) {
// waiting for the macro-task first, then micro-task
return new Promise((resolve) => {
setTimeout(() => {
resolve();
});
}).then(() => fn());
async function microTask() {
await Promise.resolve();
}

/** Actually waits a macro-task and then a micro-task, for reasons unspecified. */
async function macroTask() {
await new Promise((resolve) => setTimeout(resolve, 0));
await microTask();
}

// TODO [#3331]: remove lwc:dynamic portion of these tests in 246

it('should call the loader using lwc:dynamic', () => {
it('should call the loader using lwc:dynamic', async () => {
// note, using `x-` prefix instead of `x/` because these are
// handled by `registerForLoad`
registerForLoad('x-ctor', DynamicCtor);
Expand All @@ -37,57 +38,58 @@ it('should call the loader using lwc:dynamic', () => {
const elm = createElement('x-dynamic', { is: LwcDynamicContainer });
document.body.appendChild(elm);

return Promise.resolve().then(() => {
const child = elm.shadowRoot.querySelector('x-ctor');
expect(child).toBeNull();
// first rendered with ctor set to undefined (nothing)
elm.enableCtor();
return waitForMacroTask(() => {
// second rendered with ctor set to x-ctor
const ctorElm = elm.shadowRoot.querySelector('x-ctor');
expect(ctorElm).not.toBeNull();
const span = ctorElm.shadowRoot.querySelector('span');
expect(span).not.toBeNull();
expect(span.textContent).toBe('ctor_html');
elm.enableAlter();
return waitForMacroTask(() => {
// third rendered with ctor set to x-alter
const alterElm = elm.shadowRoot.querySelector('x-ctor');
expect(alterElm).not.toBeNull();
const span = alterElm.shadowRoot.querySelector('span');
expect(span).not.toBeNull();
expect(span.textContent).toBe('alter_html');
elm.disableAll();
return waitForMacroTask(() => {
// third rendered with ctor set to null (nothing)
const child = elm.shadowRoot.querySelector('x-ctor');
expect(child).toBeNull();
});
});
});
});
const child = elm.shadowRoot.querySelector('x-ctor');
expect(child).toBeNull();
// first rendered with ctor set to undefined (nothing)
elm.enableCtor();

await macroTask();

// second rendered with ctor set to x-ctor
const ctorElm = elm.shadowRoot.querySelector('x-ctor');
expect(ctorElm).not.toBeNull();
const ctorElmSpan = ctorElm.shadowRoot.querySelector('span');
expect(ctorElmSpan).not.toBeNull();
expect(ctorElmSpan.textContent).toBe('ctor_html');
elm.enableAlter();

await macroTask();

// third rendered with ctor set to x-alter
const alterElm = elm.shadowRoot.querySelector('x-ctor');
expect(alterElm).not.toBeNull();
const afterElmSpan = alterElm.shadowRoot.querySelector('span');
expect(afterElmSpan).not.toBeNull();
expect(afterElmSpan.textContent).toBe('alter_html');
elm.disableAll();

await macroTask();

// third rendered with ctor set to null (nothing)
expect(elm.shadowRoot.querySelector('x-ctor')).toBeNull();
});

it('should not reuse DOM elements using lwc:dynamic', () => {
it('should not reuse DOM elements using lwc:dynamic', async () => {
registerForLoad('x-ctor', DynamicCtor);
registerForLoad('x-alter', AlterCtor);

const elm = createElement('x-dynamic', { is: LwcDynamicContainer });
elm.enableCtor();
document.body.appendChild(elm);

return waitForMacroTask(() => {
const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();
return waitForMacroTask(() => {
const alterElm = elm.shadowRoot.querySelector('x-ctor');
expect(alterElm).not.toBe(childElm);
});
});
await macroTask();

const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();

await macroTask();

const alterElm = elm.shadowRoot.querySelector('x-ctor');
expect(alterElm).not.toBe(childElm);
});

it('should not cache DOM elements using lwc:dynamic', () => {
it('should not cache DOM elements using lwc:dynamic', async () => {
registerForLoad('x-ctor', DynamicCtor);
registerForLoad('x-alter', AlterCtor);

Expand All @@ -96,18 +98,20 @@ it('should not cache DOM elements using lwc:dynamic', () => {
document.body.appendChild(elm);

// from ctor to alter back to ctor, new elements should be created
return waitForMacroTask(() => {
const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();
return waitForMacroTask(() => {
elm.enableCtor();
return waitForMacroTask(() => {
const secondCtorElm = elm.shadowRoot.querySelector('x-ctor');
expect(secondCtorElm).not.toBe(childElm);
});
});
});
await macroTask();

const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();

await macroTask();

elm.enableCtor();

await macroTask();

const secondCtorElm = elm.shadowRoot.querySelector('x-ctor');
expect(secondCtorElm).not.toBe(childElm);
});

describe('slotted content using lwc:dynamic', () => {
Expand All @@ -119,7 +123,7 @@ describe('slotted content using lwc:dynamic', () => {
consoleSpy.reset();
});

it('reallocate slotted content after changing constructor', () => {
it('reallocate slotted content after changing constructor', async () => {
const elm = createElement('x-dynamic-slotted', { is: LwcDynamicSlotted });
elm.ctor = ContainerFoo;

Expand All @@ -137,26 +141,22 @@ describe('slotted content using lwc:dynamic', () => {
// Swap construstor and check if nodes have been reallocated.
elm.ctor = ContainerBar;

return Promise.resolve().then(() => {
expect(
elm.shadowRoot.querySelector('[data-id="slot-default"]').assignedSlot
).toBeDefined();
expect(elm.shadowRoot.querySelector('[data-id="slot-bar"]').assignedSlot).toBeDefined();

if (process.env.NATIVE_SHADOW) {
// `slot-foo` is not rendered in synthetic shadow
expect(elm.shadowRoot.querySelector('[data-id="slot-foo"]').assignedSlot).toBe(
null
);
}
expect(consoleSpy.calls.error.length).toEqual(0);
});
await microTask();

expect(elm.shadowRoot.querySelector('[data-id="slot-default"]').assignedSlot).toBeDefined();
expect(elm.shadowRoot.querySelector('[data-id="slot-bar"]').assignedSlot).toBeDefined();

if (process.env.NATIVE_SHADOW) {
// `slot-foo` is not rendered in synthetic shadow
expect(elm.shadowRoot.querySelector('[data-id="slot-foo"]').assignedSlot).toBe(null);
}
expect(consoleSpy.calls.error.length).toEqual(0);
});
});

// Using <lwc:component lwc:is={}>

it('should call the loader', () => {
it('should call the loader', async () => {
// note, using `x-` prefix instead of `x/` because these are
// handled by `registerForLoad`
registerForLoad('x-ctor', DynamicCtor);
Expand All @@ -165,77 +165,79 @@ it('should call the loader', () => {
const elm = createElement('x-dynamic', { is: DynamicContainer });
document.body.appendChild(elm);

return Promise.resolve().then(() => {
const child = elm.shadowRoot.querySelector('x-ctor');
expect(child).toBeNull();
// first rendered with ctor set to undefined (nothing)
elm.enableCtor();
return waitForMacroTask(() => {
// second rendered with ctor set to x-ctor
const ctorElm = elm.shadowRoot.querySelector('x-ctor');
expect(ctorElm).not.toBeNull();
const span = ctorElm.shadowRoot.querySelector('span');
expect(span).not.toBeNull();
expect(span.textContent).toBe('ctor_html');
elm.enableAlter();
return waitForMacroTask(() => {
// third rendered with ctor set to x-alter
const alterElm = elm.shadowRoot.querySelector('x-alter');
expect(alterElm).not.toBeNull();
const span = alterElm.shadowRoot.querySelector('span');
expect(span).not.toBeNull();
expect(span.textContent).toBe('alter_html');
elm.disableAll();
return waitForMacroTask(() => {
// third rendered with ctor set to null (nothing)
const child = elm.shadowRoot.querySelector('x-ctor');
expect(child).toBeNull();
});
});
});
});
await microTask();

const child = elm.shadowRoot.querySelector('x-ctor');
expect(child).toBeNull();
// first rendered with ctor set to undefined (nothing)
elm.enableCtor();

await macroTask();

// second rendered with ctor set to x-ctor
const ctorElm = elm.shadowRoot.querySelector('x-ctor');
expect(ctorElm).not.toBeNull();
const ctorElmSpan = ctorElm.shadowRoot.querySelector('span');
expect(ctorElmSpan).not.toBeNull();
expect(ctorElmSpan.textContent).toBe('ctor_html');
elm.enableAlter();

await macroTask();

// third rendered with ctor set to x-alter
const alterElm = elm.shadowRoot.querySelector('x-alter');
expect(alterElm).not.toBeNull();
const afterElmSpan = alterElm.shadowRoot.querySelector('span');
expect(afterElmSpan).not.toBeNull();
expect(afterElmSpan.textContent).toBe('alter_html');
elm.disableAll();

await macroTask();

// third rendered with ctor set to null (nothing)
expect(elm.shadowRoot.querySelector('x-ctor')).toBeNull();
});

it('should not reuse DOM elements', () => {
it('should not reuse DOM elements', async () => {
registerForLoad('x-ctor', DynamicCtor);
registerForLoad('x-alter', AlterCtor);

const elm = createElement('x-dynamic', { is: DynamicContainer });
elm.enableCtor();
document.body.appendChild(elm);

return waitForMacroTask(() => {
const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();
return waitForMacroTask(() => {
const alterElm = elm.shadowRoot.querySelector('x-alter');
expect(alterElm).not.toBe(childElm);
});
});
await macroTask();
const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();
await macroTask();
const alterElm = elm.shadowRoot.querySelector('x-alter');
expect(alterElm).not.toBe(childElm);
});

it('should not cache DOM elements', () => {
it('should not cache DOM elements', async () => {
registerForLoad('x-ctor', DynamicCtor);
registerForLoad('x-alter', AlterCtor);

const elm = createElement('x-dynamic', { is: DynamicContainer });
elm.enableCtor();
document.body.appendChild(elm);

// from ctor to alter back to ctor, new elements should be created
return waitForMacroTask(() => {
const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();
return waitForMacroTask(() => {
elm.enableCtor();
return waitForMacroTask(() => {
const secondCtorElm = elm.shadowRoot.querySelector('x-ctor');
expect(secondCtorElm).not.toBe(childElm);
});
});
});

await macroTask();

const childElm = elm.shadowRoot.querySelector('x-ctor');
expect(childElm).not.toBeNull();
elm.enableAlter();

await macroTask();

elm.enableCtor();

await macroTask();

const secondCtorElm = elm.shadowRoot.querySelector('x-ctor');
expect(secondCtorElm).not.toBe(childElm);
});

describe('slotted content', () => {
Expand All @@ -247,7 +249,7 @@ describe('slotted content', () => {
consoleSpy.reset();
});

it('reallocate slotted content after changing constructor', () => {
it('reallocate slotted content after changing constructor', async () => {
const elm = createElement('x-dynamic-slotted', { is: DynamicSlotted });
elm.ctor = ContainerFoo;

Expand All @@ -265,19 +267,15 @@ describe('slotted content', () => {
// Swap constructor and check if nodes have been reallocated.
elm.ctor = ContainerBar;

return Promise.resolve().then(() => {
expect(
elm.shadowRoot.querySelector('[data-id="slot-default"]').assignedSlot
).toBeDefined();
expect(elm.shadowRoot.querySelector('[data-id="slot-bar"]').assignedSlot).toBeDefined();

if (process.env.NATIVE_SHADOW) {
// `slot-foo` is not rendered in synthetic shadow
expect(elm.shadowRoot.querySelector('[data-id="slot-foo"]').assignedSlot).toBe(
null
);
}
expect(consoleSpy.calls.error.length).toEqual(0);
});
await microTask();

expect(elm.shadowRoot.querySelector('[data-id="slot-default"]').assignedSlot).toBeDefined();
expect(elm.shadowRoot.querySelector('[data-id="slot-bar"]').assignedSlot).toBeDefined();

if (process.env.NATIVE_SHADOW) {
// `slot-foo` is not rendered in synthetic shadow
expect(elm.shadowRoot.querySelector('[data-id="slot-foo"]').assignedSlot).toBe(null);
}
expect(consoleSpy.calls.error.length).toEqual(0);
});
});