diff --git a/src/runtime/dom-extras.ts b/src/runtime/dom-extras.ts index 9902aff24ff..8dd083e84f4 100644 --- a/src/runtime/dom-extras.ts +++ b/src/runtime/dom-extras.ts @@ -396,14 +396,14 @@ export const patchChildSlotNodes = (elm: HTMLElement) => { patchHostOriginalAccessor('firstChild', elm); Object.defineProperty(elm, 'firstChild', { get() { - return this.childNodes[0]; + return this.childNodes[0] || null; }, }); patchHostOriginalAccessor('lastChild', elm); Object.defineProperty(elm, 'lastChild', { get() { - return this.childNodes[this.childNodes.length - 1]; + return this.childNodes[this.childNodes.length - 1] || null; }, }); @@ -459,7 +459,7 @@ const patchNextSibling = (node: Node) => { const parentNodes = this['s-ol']?.parentNode.childNodes; const index = parentNodes?.indexOf(this); if (parentNodes && index > -1) { - return parentNodes[index + 1]; + return parentNodes[index + 1] || null; } return this.__nextSibling; }, @@ -480,7 +480,7 @@ const patchNextElementSibling = (element: Element) => { const parentEles = this['s-ol']?.parentNode.children; const index = parentEles?.indexOf(this); if (parentEles && index > -1) { - return parentEles[index + 1]; + return parentEles[index + 1] || null; } return this.__nextElementSibling; }, @@ -501,7 +501,7 @@ const patchPreviousSibling = (node: Node) => { const parentNodes = this['s-ol']?.parentNode.childNodes; const index = parentNodes?.indexOf(this); if (parentNodes && index > -1) { - return parentNodes[index - 1]; + return parentNodes[index - 1] || null; } return this.__previousSibling; }, @@ -523,7 +523,7 @@ const patchPreviousElementSibling = (element: Element) => { const index = parentNodes?.indexOf(this); if (parentNodes && index > -1) { - return parentNodes[index - 1]; + return parentNodes[index - 1] || null; } return this.__previousElementSibling; }, @@ -541,7 +541,7 @@ export const patchParentNode = (node: Node) => { patchHostOriginalAccessor('parentNode', node); Object.defineProperty(node, 'parentNode', { get: function () { - return this['s-ol']?.parentNode || this.__parentNode; + return this['s-ol']?.parentNode || this.__parentNode || null; }, set: function (value) { // mock-doc sets parentNode? diff --git a/src/runtime/test/dom-extras.spec.tsx b/src/runtime/test/dom-extras.spec.tsx index 9422201d8e7..c73682e75b4 100644 --- a/src/runtime/test/dom-extras.spec.tsx +++ b/src/runtime/test/dom-extras.spec.tsx @@ -140,4 +140,34 @@ describe('dom-extras - patches for non-shadow dom methods and accessors', () => expect(specPage.root.children[0].__parentNode.tagName).toBe('DIV'); expect(specPage.root.childNodes[0].__parentNode.tagName).toBe('DIV'); }); + + it('returns null (not undefined) for out-of-bounds siblings/children', async () => { + specPage.root.childNodes.forEach((node: Node) => patchSlottedNode(node)); + + const firstSlottedNode = specPage.root.childNodes[0]; + expect(firstSlottedNode.previousSibling).toBeNull(); + + const lastSlottedNode = specPage.root.childNodes[specPage.root.childNodes.length - 1]; + expect(lastSlottedNode.nextSibling).toBeNull(); + + const firstSlottedElement = specPage.root.children[0]; + expect(firstSlottedElement.previousElementSibling).toBeNull(); + + const lastSlottedElement = specPage.root.children[specPage.root.children.length - 1]; + expect(lastSlottedElement.nextElementSibling).toBeNull(); + }); + + it('returns null (not undefined) for firstChild/lastChild on empty patched hosts', async () => { + const emptyPage = await newSpecPage({ + components: [], + html: `
`, + }); + const emptyElm = emptyPage.root; + (emptyElm as any).__childNodes = []; + patchPseudoShadowDom(emptyElm); + + expect(emptyElm.firstChild).toBeNull(); + expect(emptyElm.lastChild).toBeNull(); + }); }); +