From e235b3a7ecf0934c95f20d5ea1c1ce82aa4f4d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A5l=20Edman?= Date: Wed, 13 Dec 2023 14:42:53 +0100 Subject: [PATCH] fix custom element connectedCallback triggered too soon before fake element was registered --- app/assets/public/custom-element.html | 17 +++++++++++++++++ lib/Document.js | 11 ++++++++++- lib/elementFactory.js | 8 +++++--- test/custom-elements-test.js | 13 +++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) mode change 100644 => 100755 app/assets/public/custom-element.html diff --git a/app/assets/public/custom-element.html b/app/assets/public/custom-element.html old mode 100644 new mode 100755 index e06468d7..7239ffee --- a/app/assets/public/custom-element.html +++ b/app/assets/public/custom-element.html @@ -38,6 +38,23 @@

Test custom element

+ +
+ +
+ diff --git a/lib/Document.js b/lib/Document.js index e4e7f360..eb1dda17 100644 --- a/lib/Document.js +++ b/lib/Document.js @@ -175,8 +175,12 @@ module.exports = class Document extends Node { if ($elm.nodeType) $elm = $($elm); if (!$elm.length) return; + const tag = $elm[0].name; + const loaded = this[loadedSymbol]; - let mockElement = loaded.find((mockedElm) => mockedElm.$elm[0] === $elm[0]); + + let mockElement = loaded.find((mockedElm) => mockedElm?.$elm[0] === $elm[0]); + if (mockElement) { return mockElement; } @@ -184,6 +188,11 @@ module.exports = class Document extends Node { mockElement = this[kElementFactory].create($elm); loaded.push(mockElement); + + if (this[kElementFactory].isCustom(tag) && mockElement.connectedCallback) { + mockElement.connectedCallback(); + } + return mockElement; } }; diff --git a/lib/elementFactory.js b/lib/elementFactory.js index 5e0ee25e..d6206534 100644 --- a/lib/elementFactory.js +++ b/lib/elementFactory.js @@ -55,9 +55,7 @@ module.exports = class ElementFactory { if (tagName in definitions) return new definitions[tagName](document, $elm); const custom = this.custom; if (tagName in custom) { - const elm = new custom[tagName](document, $elm); - if (elm.connectedCallback) elm.connectedCallback(); - return elm; + return new custom[tagName](document, $elm); } return new HTMLElement(document, $elm); @@ -70,4 +68,8 @@ module.exports = class ElementFactory { get(name) { return this.custom[name]; } + + isCustom(name) { + return !!this.custom[name]; + } }; diff --git a/test/custom-elements-test.js b/test/custom-elements-test.js index fecffe5b..9d90168d 100644 --- a/test/custom-elements-test.js +++ b/test/custom-elements-test.js @@ -33,4 +33,17 @@ describe("Custom elements", () => { page.window.customElements.define("me-button", class Me {}); }).to.throw(DOMException, "Failed to execute 'define' on 'CustomElementRegistry': the name \"me-button\" has already been used with this registry"); }); + + it("allows custom element to set innerHTML on child", async () => { + const page = await browser.navigateTo("/custom-element.html"); + page.runScripts(); + + const greeting = page.document.getElementsByClassName("greeting")[0]; + expect(greeting.innerHTML).to.equal("

No greeting yet

"); + + const btn = page.document.getElementsByClassName("greet")[0]; + btn.click(); + + expect(greeting.innerHTML).to.equal("

Hello

"); + }); });