diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index a75d69e3e6..5b5653bf07 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -172,7 +172,7 @@ export function applyCssSplits( if (ix !== 0 && lenCheckOk) { remainder = cssText.substring(0, ix); cssText = cssText.substring(ix); - } else if (j > 1) { + } else if (j > 0) { continue; } if (hackCss) { diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index f1575847ea..3c29dc691e 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -279,6 +279,7 @@ describe('applyCssSplits css rejoiner', function () { }); it('applies css splits correctly', () => { + // happy path applyCssSplits( sn, fullCssText, @@ -291,4 +292,94 @@ describe('applyCssSplits css rejoiner', function () { otherHalfCssText, ); }); + + it('applies css splits correctly even when there are too many child nodes', () => { + let sn3 = { + type: NodeType.Element, + tagName: 'style', + childNodes: [ + { + type: NodeType.Text, + textContent: '', + }, + { + type: NodeType.Text, + textContent: '', + }, + { + type: NodeType.Text, + textContent: '', + }, + ], + } as serializedElementNodeWithId; + applyCssSplits( + sn3, + fullCssText, + [halfCssText.length, fullCssText.length], + false, + mockLastUnusedArg, + ); + expect((sn3.childNodes[0] as textNode).textContent).toEqual(halfCssText); + expect((sn3.childNodes[1] as textNode).textContent).toEqual( + otherHalfCssText, + ); + expect((sn3.childNodes[2] as textNode).textContent).toEqual(''); + }); + + it('maintains entire css text when there are too few child nodes', () => { + let sn1 = { + type: NodeType.Element, + tagName: 'style', + childNodes: [ + { + type: NodeType.Text, + textContent: '', + }, + ], + } as serializedElementNodeWithId; + applyCssSplits( + sn1, + fullCssText, + [halfCssText.length, fullCssText.length], + false, + mockLastUnusedArg, + ); + expect((sn1.childNodes[0] as textNode).textContent).toEqual(fullCssText); + }); + + it('ignores css splits correctly when there is a mismatch in length check', () => { + applyCssSplits(sn, fullCssText, [2, 3], false, mockLastUnusedArg); + expect((sn.childNodes[0] as textNode).textContent).toEqual(fullCssText); + expect((sn.childNodes[1] as textNode).textContent).toEqual(''); + }); + + it('ignores css splits correctly when we indicate a split is invalid with the zero marker', () => { + applyCssSplits( + sn, + fullCssText, + [0, fullCssText.length], + false, + mockLastUnusedArg, + ); + expect((sn.childNodes[0] as textNode).textContent).toEqual(fullCssText); + expect((sn.childNodes[1] as textNode).textContent).toEqual(''); + }); + + it('ignores css splits correctly with negative splits', () => { + applyCssSplits(sn, fullCssText, [-2, -4], false, mockLastUnusedArg); + expect((sn.childNodes[0] as textNode).textContent).toEqual(fullCssText); + expect((sn.childNodes[1] as textNode).textContent).toEqual(''); + }); + + it('ignores css splits correctly with out of order splits', () => { + applyCssSplits( + sn, + fullCssText, + [fullCssText.length * 2, fullCssText.length], + false, + mockLastUnusedArg, + ); + expect((sn.childNodes[0] as textNode).textContent).toEqual(fullCssText); + expect((sn.childNodes[1] as textNode).textContent).toEqual(''); + }); });