From aa2a5af3c158d18cf07092edd7cd3418f5c2e3d2 Mon Sep 17 00:00:00 2001 From: Yigit Yuce Date: Thu, 5 Sep 2024 17:25:20 +0300 Subject: [PATCH 1/3] fix(dom-extras): add required internal flags to the new nodes to work properly with slot relocation algo #5969 --- src/runtime/dom-extras.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/runtime/dom-extras.ts b/src/runtime/dom-extras.ts index acbc0d0ed3c..c6870a8f38c 100644 --- a/src/runtime/dom-extras.ts +++ b/src/runtime/dom-extras.ts @@ -83,6 +83,12 @@ export const patchSlotAppendChild = (HostElementPrototype: any) => { const slotName = (newChild['s-sn'] = getSlotName(newChild)); const slotNode = getHostSlotNode(this.childNodes, slotName, this.tagName); if (slotNode) { + const slotPlaceholder: d.RenderNode = document.createTextNode('') as any; + slotPlaceholder['s-nr'] = newChild; + (slotNode['s-cr'].parentNode as any).__appendChild(slotPlaceholder); + newChild['s-ol'] = slotPlaceholder; + newChild['s-sh'] = slotNode['s-hn']; + const slotChildNodes = getHostSlotChildNodes(slotNode, slotName); const appendAfter = slotChildNodes[slotChildNodes.length - 1]; const insertedNode = insertBefore(appendAfter.parentNode, newChild, appendAfter.nextSibling); @@ -147,6 +153,7 @@ export const patchSlotPrepend = (HostElementPrototype: HTMLElement) => { slotPlaceholder['s-nr'] = newChild; (slotNode['s-cr'].parentNode as any).__appendChild(slotPlaceholder); newChild['s-ol'] = slotPlaceholder; + newChild['s-sh'] = slotNode['s-hn']; const slotChildNodes = getHostSlotChildNodes(slotNode, slotName); const appendAfter = slotChildNodes[0]; From 8b23068b0d280895fb5f07b126bf4a2c6f8fc6e2 Mon Sep 17 00:00:00 2001 From: Yigit Yuce Date: Mon, 9 Sep 2024 10:40:16 +0300 Subject: [PATCH 2/3] test: add missing tests --- .../cmp.test.tsx | 116 ++++++++++++++++++ .../cmp.tsx | 22 ++++ 2 files changed, 138 insertions(+) create mode 100644 test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx create mode 100644 test/wdio/scoped-slot-insertion-order-after-interaction/cmp.tsx diff --git a/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx b/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx new file mode 100644 index 00000000000..ec12ad58959 --- /dev/null +++ b/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx @@ -0,0 +1,116 @@ +import { Fragment, h } from '@stencil/core'; +import { render } from '@wdio/browser-runner/stencil'; + +describe('scoped-slot-insertion-order-after-interaction', () => { + let host: HTMLScopedSlotInsertionOrderAfterInteractionElement; + + beforeEach(async () => { + render({ + template: () => ( + <> + +

My initial slotted content.

+
+ + + + + + ), + }); + + + const scopedSlotInsertionOrderAfterInteraction = document.querySelector('scoped-slot-insertion-order-after-interaction'); + + // The element to be inserted + const el = document.createElement('p'); + el.innerText = 'The new slotted content.'; + + await $('#appendNodes').waitForExist(); + document.querySelector('#appendNodes').addEventListener('click', () => { + scopedSlotInsertionOrderAfterInteraction.append(el); + }); + + document.querySelector('#appendChildNodes').addEventListener('click', () => { + scopedSlotInsertionOrderAfterInteraction.appendChild(el); + }); + + document.querySelector('#prependNodes').addEventListener('click', () => { + scopedSlotInsertionOrderAfterInteraction.prepend(el); + }); + + host = document.querySelector('scoped-slot-insertion-order-after-interaction'); + }); + + describe('append', () => { + it('inserts a DOM element at the end of the slot', async () => { + expect(host).toBeDefined(); + + await browser.waitUntil(async () => host.children.length === 1); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + + const addButton = $('#appendNodes'); + await addButton.click(); + + await browser.waitUntil(async () => host.children.length === 2); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + expect(host.children[1].textContent).toBe('The new slotted content.'); + + const text = $('p'); + await text.click(); + await browser.waitUntil(async () => host.dataset.counter === '1'); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + expect(host.children[1].textContent).toBe('The new slotted content.'); + }); + }); + + describe('appendChild', () => { + it('inserts a DOM element at the end of the slot', async () => { + expect(host).toBeDefined(); + + await browser.waitUntil(async () => host.children.length === 1); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + + const addButton = $('#appendChildNodes'); + await addButton.click(); + + await browser.waitUntil(async () => host.children.length === 2); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + expect(host.children[1].textContent).toBe('The new slotted content.'); + + const text = $('p'); + await text.click(); + await browser.waitUntil(async () => host.dataset.counter === '1'); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + expect(host.children[1].textContent).toBe('The new slotted content.'); + }); + }); + + describe('prepend', () => { + it('inserts a DOM element at the start of the slot', async () => { + expect(host).toBeDefined(); + + await browser.waitUntil(async () => host.children.length === 1); + expect(host.children[0].textContent).toBe('My initial slotted content.'); + + const addButton = $('#prependNodes'); + await addButton.click(); + + await browser.waitUntil(async () => host.children.length === 2); + expect(host.children[0].textContent).toBe('The new slotted content.'); + expect(host.children[1].textContent).toBe('My initial slotted content.'); + + const text = $('p'); + await text.click(); + await browser.waitUntil(async () => host.dataset.counter === '1'); + expect(host.children[0].textContent).toBe('The new slotted content.'); + expect(host.children[1].textContent).toBe('My initial slotted content.'); + }); + }); +}); diff --git a/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.tsx b/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.tsx new file mode 100644 index 00000000000..ee84347470b --- /dev/null +++ b/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.tsx @@ -0,0 +1,22 @@ +import { Component, h, Host, State } from '@stencil/core'; + +@Component({ + tag: 'scoped-slot-insertion-order-after-interaction', + scoped: true, +}) +export class ScopedSlotInsertionOrderAfterInteraction { + @State() totalCounter = 0; + + render() { + return ( + { + this.totalCounter = this.totalCounter + 1; + }} + > + + + ); + } +} From 28655bc5d269c1a39d48a27e9695579e90c83036 Mon Sep 17 00:00:00 2001 From: Tanner Reits Date: Mon, 9 Sep 2024 10:15:17 -0400 Subject: [PATCH 3/3] format(): prettier --- .../cmp.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx b/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx index ec12ad58959..9f26d686fe6 100644 --- a/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx +++ b/test/wdio/scoped-slot-insertion-order-after-interaction/cmp.test.tsx @@ -25,8 +25,9 @@ describe('scoped-slot-insertion-order-after-interaction', () => { ), }); - - const scopedSlotInsertionOrderAfterInteraction = document.querySelector('scoped-slot-insertion-order-after-interaction'); + const scopedSlotInsertionOrderAfterInteraction = document.querySelector( + 'scoped-slot-insertion-order-after-interaction', + ); // The element to be inserted const el = document.createElement('p');