Skip to content

Commit 8059d96

Browse files
authored
Added support for deprecated addRule & removeRule methods (#1515)
* Added support for deprecated addRule & removeRule methods * Respect addRule default value
1 parent 40bbc25 commit 8059d96

File tree

4 files changed

+229
-0
lines changed

4 files changed

+229
-0
lines changed

.changeset/great-cows-camp.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@rrweb/record": patch
3+
"rrweb": patch
4+
---
5+
6+
Added support for deprecated addRule & removeRule methods

packages/rrweb/src/record/observer.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,17 @@ function initStyleSheetObserver(
659659
),
660660
});
661661

662+
// Support for deprecated addRule method
663+
win.CSSStyleSheet.prototype.addRule = function (
664+
this: CSSStyleSheet,
665+
selector: string,
666+
styleBlock: string,
667+
index: number = this.cssRules.length,
668+
) {
669+
const rule = `${selector} { ${styleBlock} }`;
670+
return win.CSSStyleSheet.prototype.insertRule.apply(this, [rule, index]);
671+
};
672+
662673
// eslint-disable-next-line @typescript-eslint/unbound-method
663674
const deleteRule = win.CSSStyleSheet.prototype.deleteRule;
664675
win.CSSStyleSheet.prototype.deleteRule = new Proxy(deleteRule, {
@@ -688,6 +699,14 @@ function initStyleSheetObserver(
688699
),
689700
});
690701

702+
// Support for deprecated removeRule method
703+
win.CSSStyleSheet.prototype.removeRule = function (
704+
this: CSSStyleSheet,
705+
index: number,
706+
) {
707+
return win.CSSStyleSheet.prototype.deleteRule.apply(this, [index]);
708+
};
709+
691710
let replace: (text: string) => Promise<CSSStyleSheet>;
692711

693712
if (win.CSSStyleSheet.prototype.replace) {

packages/rrweb/test/__snapshots__/record.test.ts.snap

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2196,6 +2196,146 @@ exports[`record > captures stylesheet rules 1`] = `
21962196
]"
21972197
`;
21982198

2199+
exports[`record > captures stylesheet rules with deprecated addRule & removeRule properties 1`] = `
2200+
"[
2201+
{
2202+
\\"type\\": 4,
2203+
\\"data\\": {
2204+
\\"href\\": \\"about:blank\\",
2205+
\\"width\\": 1920,
2206+
\\"height\\": 1080
2207+
}
2208+
},
2209+
{
2210+
\\"type\\": 2,
2211+
\\"data\\": {
2212+
\\"node\\": {
2213+
\\"type\\": 0,
2214+
\\"childNodes\\": [
2215+
{
2216+
\\"type\\": 1,
2217+
\\"name\\": \\"html\\",
2218+
\\"publicId\\": \\"\\",
2219+
\\"systemId\\": \\"\\",
2220+
\\"id\\": 2
2221+
},
2222+
{
2223+
\\"type\\": 2,
2224+
\\"tagName\\": \\"html\\",
2225+
\\"attributes\\": {},
2226+
\\"childNodes\\": [
2227+
{
2228+
\\"type\\": 2,
2229+
\\"tagName\\": \\"head\\",
2230+
\\"attributes\\": {},
2231+
\\"childNodes\\": [],
2232+
\\"id\\": 4
2233+
},
2234+
{
2235+
\\"type\\": 2,
2236+
\\"tagName\\": \\"body\\",
2237+
\\"attributes\\": {},
2238+
\\"childNodes\\": [
2239+
{
2240+
\\"type\\": 3,
2241+
\\"textContent\\": \\"\\\\n \\",
2242+
\\"id\\": 6
2243+
},
2244+
{
2245+
\\"type\\": 2,
2246+
\\"tagName\\": \\"input\\",
2247+
\\"attributes\\": {
2248+
\\"type\\": \\"text\\",
2249+
\\"size\\": \\"40\\"
2250+
},
2251+
\\"childNodes\\": [],
2252+
\\"id\\": 7
2253+
},
2254+
{
2255+
\\"type\\": 3,
2256+
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
2257+
\\"id\\": 8
2258+
}
2259+
],
2260+
\\"id\\": 5
2261+
}
2262+
],
2263+
\\"id\\": 3
2264+
}
2265+
],
2266+
\\"id\\": 1
2267+
},
2268+
\\"initialOffset\\": {
2269+
\\"left\\": 0,
2270+
\\"top\\": 0
2271+
}
2272+
}
2273+
},
2274+
{
2275+
\\"type\\": 3,
2276+
\\"data\\": {
2277+
\\"source\\": 0,
2278+
\\"texts\\": [],
2279+
\\"attributes\\": [],
2280+
\\"removes\\": [],
2281+
\\"adds\\": [
2282+
{
2283+
\\"parentId\\": 4,
2284+
\\"nextId\\": null,
2285+
\\"node\\": {
2286+
\\"type\\": 2,
2287+
\\"tagName\\": \\"style\\",
2288+
\\"attributes\\": {
2289+
\\"_cssText\\": \\"body { background: rgb(0, 0, 0); }\\"
2290+
},
2291+
\\"childNodes\\": [],
2292+
\\"id\\": 9
2293+
}
2294+
}
2295+
]
2296+
}
2297+
},
2298+
{
2299+
\\"type\\": 3,
2300+
\\"data\\": {
2301+
\\"source\\": 8,
2302+
\\"id\\": 9,
2303+
\\"adds\\": [
2304+
{
2305+
\\"rule\\": \\"body { color: #fff; }\\",
2306+
\\"index\\": 1
2307+
}
2308+
]
2309+
}
2310+
},
2311+
{
2312+
\\"type\\": 3,
2313+
\\"data\\": {
2314+
\\"source\\": 8,
2315+
\\"id\\": 9,
2316+
\\"removes\\": [
2317+
{
2318+
\\"index\\": 0
2319+
}
2320+
]
2321+
}
2322+
},
2323+
{
2324+
\\"type\\": 3,
2325+
\\"data\\": {
2326+
\\"source\\": 8,
2327+
\\"id\\": 9,
2328+
\\"adds\\": [
2329+
{
2330+
\\"rule\\": \\"body { color: #ccc; }\\",
2331+
\\"index\\": 1
2332+
}
2333+
]
2334+
}
2335+
}
2336+
]"
2337+
`;
2338+
21992339
exports[`record > captures stylesheets in iframes with \`blob:\` url 1`] = `
22002340
"[
22012341
{

packages/rrweb/test/record.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ describe('record', function (this: ISuite) {
297297
// begin: pre-serialization
298298
const ruleIdx0 = styleSheet.insertRule('body { background: #000; }');
299299
const ruleIdx1 = styleSheet.insertRule('body { background: #111; }');
300+
300301
styleSheet.deleteRule(ruleIdx1);
301302
// end: pre-serialization
302303
setTimeout(() => {
@@ -328,6 +329,69 @@ describe('record', function (this: ISuite) {
328329
rule: 'body { color: #fff; }',
329330
},
330331
]);
332+
expect((addRules[1].data as styleSheetRuleData).adds).toEqual([
333+
{
334+
rule: 'body { color: #ccc; }',
335+
},
336+
]);
337+
expect(removeRuleCount).toEqual(1);
338+
await assertSnapshot(ctx.events);
339+
});
340+
341+
it('captures stylesheet rules with deprecated addRule & removeRule properties', async () => {
342+
await ctx.page.evaluate(() => {
343+
const { record } = (window as unknown as IWindow).rrweb;
344+
345+
record({
346+
emit: (window as unknown as IWindow).emit,
347+
});
348+
349+
const styleElement = document.createElement('style');
350+
document.head.appendChild(styleElement);
351+
352+
const styleSheet = <CSSStyleSheet>styleElement.sheet;
353+
// begin: pre-serialization
354+
const ruleIdx0 = styleSheet.addRule('body', 'background: #000;');
355+
const ruleIdx1 = styleSheet.addRule('body', 'background: #111;');
356+
357+
styleSheet.removeRule(ruleIdx1);
358+
// end: pre-serialization
359+
setTimeout(() => {
360+
styleSheet.addRule('body', 'color: #fff;');
361+
}, 0);
362+
setTimeout(() => {
363+
styleSheet.removeRule(ruleIdx0);
364+
}, 5);
365+
setTimeout(() => {
366+
styleSheet.addRule('body', 'color: #ccc;');
367+
}, 10);
368+
});
369+
await ctx.page.waitForTimeout(50);
370+
const styleSheetRuleEvents = ctx.events.filter(
371+
(e) =>
372+
e.type === EventType.IncrementalSnapshot &&
373+
e.data.source === IncrementalSource.StyleSheetRule,
374+
);
375+
const addRules = styleSheetRuleEvents.filter((e) =>
376+
Boolean((e.data as styleSheetRuleData).adds),
377+
);
378+
const removeRuleCount = styleSheetRuleEvents.filter((e) =>
379+
Boolean((e.data as styleSheetRuleData).removes),
380+
).length;
381+
// pre-serialization insert/delete should be ignored
382+
expect(addRules.length).toEqual(2);
383+
expect((addRules[0].data as styleSheetRuleData).adds).toEqual([
384+
{
385+
index: 1,
386+
rule: 'body { color: #fff; }',
387+
},
388+
]);
389+
expect((addRules[1].data as styleSheetRuleData).adds).toEqual([
390+
{
391+
index: 1,
392+
rule: 'body { color: #ccc; }',
393+
},
394+
]);
331395
expect(removeRuleCount).toEqual(1);
332396
await assertSnapshot(ctx.events);
333397
});

0 commit comments

Comments
 (0)