diff --git a/.changeset/chilled-penguins-sin.md b/.changeset/chilled-penguins-sin.md new file mode 100644 index 0000000000..060744a07b --- /dev/null +++ b/.changeset/chilled-penguins-sin.md @@ -0,0 +1,5 @@ +--- +"rrdom": patch +--- + +Ignore invalid DOM attributes when diffing 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);