From 273842bc5b3f33bf45ad3d64184eb1cb0f328487 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Mon, 26 Aug 2024 13:04:54 -0230 Subject: [PATCH] fix(rrdom): Ignore invalid DOM attributes when diffing (#213) We encountered an issue where replays with invalid attributes (e.g. `@click`) would break rendering the replay after seeking. The exception bubbles up to [here](https://github.com/rrweb-io/rrweb/blob/62093d4385a09eb0980c2ac02d97eea5ce2882be/packages/rrweb/src/replay/index.ts#L270-L279), which means the replay will continue to play, but the replay mirror will be incomplete. Closes https://github.com/getsentry/team-replay/issues/458 --- packages/rrdom/src/diff.ts | 11 ++++++++++- packages/rrdom/test/diff.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/rrdom/src/diff.ts b/packages/rrdom/src/diff.ts index 10acb4f419..5cff5dc724 100644 --- a/packages/rrdom/src/diff.ts +++ b/packages/rrdom/src/diff.ts @@ -354,7 +354,16 @@ function diffProps( } }; } else if (newTree.tagName === 'IFRAME' && name === 'srcdoc') continue; - else oldTree.setAttribute(name, newValue); + else { + try { + oldTree.setAttribute(name, newValue); + } catch (err) { + // We want to continue diffing so we quietly catch + // this exception. Otherwise, this can throw and bubble up to + // the `ReplayerEvents.Flush` listener and break rendering + console.warn(err); + } + } } for (const { name } of Array.from(oldAttributes)) diff --git a/packages/rrdom/test/diff.test.ts b/packages/rrdom/test/diff.test.ts index ff817a1627..e250ef8f06 100644 --- a/packages/rrdom/test/diff.test.ts +++ b/packages/rrdom/test/diff.test.ts @@ -335,6 +335,32 @@ describe('diff algorithm for rrdom', () => { expect((node as Node as HTMLElement).className).toBe('node'); }); + it('ignores invalid attributes', () => { + const tagName = 'DIV'; + const node = document.createElement(tagName); + const sn = Object.assign({}, elementSn, { + attributes: { '@click': 'foo' }, + tagName, + }); + mirror.add(node, sn); + + const rrDocument = new RRDocument(); + const rrNode = rrDocument.createElement(tagName); + const sn2 = Object.assign({}, elementSn, { + attributes: { '@click': 'foo' }, + tagName, + }); + rrDocument.mirror.add(rrNode, sn2); + + rrNode.attributes = { id: 'node1', class: 'node', '@click': 'foo' }; + diff(node, rrNode, replayer); + expect((node as Node as HTMLElement).id).toBe('node1'); + expect((node as Node as HTMLElement).className).toBe('node'); + expect('@click' in (node as Node as HTMLElement)).toBe(false); + expect(warn).toHaveBeenCalledTimes(1); + warn.mockClear(); + }); + it('can update exist properties', () => { const tagName = 'DIV'; const node = document.createElement(tagName);