From 4e1793e0020e2af4a3f9f5e6bc309079a2b67b0b Mon Sep 17 00:00:00 2001 From: Thibaut Gery Date: Thu, 16 Feb 2023 09:20:31 +0100 Subject: [PATCH] :bug:[RUMF-1493] Avoid infinite loop on `form > input[name="host"]` element (#2017) * [REPLAY] Fix freeze Make sure to not count form element with child input as name host as a shadow root * [REPLAY] Refactor unit tests for clarity * [REPLAY] Update test labels for clarity Co-authored-by: Bastien Caudan <1331991+bcaudan@users.noreply.github.com> --------- Co-authored-by: Bastien Caudan <1331991+bcaudan@users.noreply.github.com> --- .../rum-core/src/browser/htmlDomUtils.spec.ts | 43 ++++++++++++++----- packages/rum-core/src/browser/htmlDomUtils.ts | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/packages/rum-core/src/browser/htmlDomUtils.spec.ts b/packages/rum-core/src/browser/htmlDomUtils.spec.ts index 4b7a309428..2fb5dbeb52 100644 --- a/packages/rum-core/src/browser/htmlDomUtils.spec.ts +++ b/packages/rum-core/src/browser/htmlDomUtils.spec.ts @@ -59,21 +59,42 @@ describe('isElementNode', () => { if (!isIE()) { describe('isShadowRoot', () => { - const parent = document.createElement('div') - parent.attachShadow({ mode: 'open' }) - const parameters: Array<[Node, boolean]> = [ - [parent.shadowRoot!, true], - [parent, false], - [document.body, false], - [document.createTextNode('hello'), false], - [document.createComment('hello'), false], + const notShadowDomNodes: Node[] = [ + document, + document.head, + document.body, + document.createElement('div'), + document.createTextNode('hello'), + document.createComment('hello'), ] - parameters.forEach(([element, result]) => { - it(`should return ${String(result)} for "${String(element)}"`, () => { - expect(isNodeShadowRoot(element)).toBe(result) + notShadowDomNodes.forEach((element) => { + it(`should return false for "${String(element.nodeName)}"`, () => { + expect(isNodeShadowRoot(element)).toBe(false) }) }) + + it('should return true for shadow root but not its host', () => { + const parent = document.createElement('div') + const shadowRoot = parent.attachShadow({ mode: 'open' }) + expect(isNodeShadowRoot(parent)).toBe(false) + expect(isNodeShadowRoot(shadowRoot)).toBe(true) + }) + + it('should return false for a[href] despite it has a host property', () => { + const link = document.createElement('a') + link.setAttribute('href', 'http://localhost/some/path') + expect(link.host).toBeTruthy() + expect(isNodeShadowRoot(link)).toBe(false) + }) + + it('should return false for a form with an input[name="host"] despite it has a host property', () => { + const form = document.createElement('form') + const input = document.createElement('input') + input.setAttribute('name', 'host') + form.appendChild(input) + expect(isNodeShadowRoot(form)).toBe(false) + }) }) } diff --git a/packages/rum-core/src/browser/htmlDomUtils.ts b/packages/rum-core/src/browser/htmlDomUtils.ts index 0e05b69f5e..0cd2efe448 100644 --- a/packages/rum-core/src/browser/htmlDomUtils.ts +++ b/packages/rum-core/src/browser/htmlDomUtils.ts @@ -16,7 +16,7 @@ export function isNodeShadowHost(node: Node): node is Element & { shadowRoot: Sh export function isNodeShadowRoot(node: Node): node is ShadowRoot { const shadowRoot = node as ShadowRoot - return !!shadowRoot.host && isElementNode(shadowRoot.host) + return !!shadowRoot.host && shadowRoot.nodeType === Node.DOCUMENT_FRAGMENT_NODE && isElementNode(shadowRoot.host) } export function getChildNodes(node: Node) {