Inline stylesheets on load (#909)
* inline stylesheets when loaded * set empty link elements to loaded by default * Clean up stylesheet manager * Remove attribute mutation code * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/scripts/repl.js * Update packages/rrweb/test/record.test.ts * Update packages/rrweb/src/record/index.ts * Add todo * Move require out of time sensitive assert * Add waitForRAF, its more reliable than waitForTimeout * Remove flaky tests * Add recording stylesheets in iframes * Remove variability from flaky test * Make test more robust * Fix naming
This commit is contained in:
@@ -94,6 +94,109 @@ exports[`record can add custom event 1`] = `
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record captures CORS stylesheets that are still loading 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"name\\": \\"html\\",
|
||||
\\"publicId\\": \\"\\",
|
||||
\\"systemId\\": \\"\\",
|
||||
\\"id\\": 2
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 4
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 6
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"input\\",
|
||||
\\"attributes\\": {
|
||||
\\"type\\": \\"text\\",
|
||||
\\"size\\": \\"40\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 7
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
|
||||
\\"id\\": 8
|
||||
}
|
||||
],
|
||||
\\"id\\": 5
|
||||
}
|
||||
],
|
||||
\\"id\\": 3
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 9,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"link\\",
|
||||
\\"attributes\\": {
|
||||
\\"rel\\": \\"stylesheet\\",
|
||||
\\"href\\": \\"https://cdn.jsdelivr.net/npm/pure@2.85.0/index.css\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 9
|
||||
}
|
||||
}
|
||||
],
|
||||
\\"removes\\": [],
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": []
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record captures inserted style text nodes correctly 1`] = `
|
||||
"[
|
||||
{
|
||||
@@ -640,6 +743,498 @@ exports[`record captures stylesheet rules 1`] = `
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record captures stylesheets in iframes that are still loading 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"name\\": \\"html\\",
|
||||
\\"publicId\\": \\"\\",
|
||||
\\"systemId\\": \\"\\",
|
||||
\\"id\\": 2
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 4
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 6
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"input\\",
|
||||
\\"attributes\\": {
|
||||
\\"type\\": \\"text\\",
|
||||
\\"size\\": \\"40\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 7
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
|
||||
\\"id\\": 8
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"iframe\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 9
|
||||
}
|
||||
],
|
||||
\\"id\\": 5
|
||||
}
|
||||
],
|
||||
\\"id\\": 3
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 9,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 12
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 14
|
||||
}
|
||||
],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 11
|
||||
}
|
||||
],
|
||||
\\"compatMode\\": \\"BackCompat\\",
|
||||
\\"id\\": 10
|
||||
}
|
||||
}
|
||||
],
|
||||
\\"removes\\": [],
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": [],
|
||||
\\"isAttachIframe\\": true
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 13,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"link\\",
|
||||
\\"attributes\\": {
|
||||
\\"_cssText\\": \\"body { color: pink; }\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 13
|
||||
}
|
||||
}
|
||||
],
|
||||
\\"removes\\": [],
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": []
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record captures stylesheets in iframes with \`blob:\` url 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"name\\": \\"html\\",
|
||||
\\"publicId\\": \\"\\",
|
||||
\\"systemId\\": \\"\\",
|
||||
\\"id\\": 2
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 4
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 6
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"input\\",
|
||||
\\"attributes\\": {
|
||||
\\"type\\": \\"text\\",
|
||||
\\"size\\": \\"40\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 7
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
|
||||
\\"id\\": 8
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"iframe\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 9
|
||||
}
|
||||
],
|
||||
\\"id\\": 5
|
||||
}
|
||||
],
|
||||
\\"id\\": 3
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 9,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"link\\",
|
||||
\\"attributes\\": {
|
||||
\\"_cssText\\": \\"body { color: pink; }\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 13
|
||||
}
|
||||
],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 12
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 14
|
||||
}
|
||||
],
|
||||
\\"rootId\\": 10,
|
||||
\\"id\\": 11
|
||||
}
|
||||
],
|
||||
\\"compatMode\\": \\"BackCompat\\",
|
||||
\\"id\\": 10
|
||||
}
|
||||
}
|
||||
],
|
||||
\\"removes\\": [],
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": [],
|
||||
\\"isAttachIframe\\": true
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record captures stylesheets that are still loading 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"name\\": \\"html\\",
|
||||
\\"publicId\\": \\"\\",
|
||||
\\"systemId\\": \\"\\",
|
||||
\\"id\\": 2
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 4
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 6
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"input\\",
|
||||
\\"attributes\\": {
|
||||
\\"type\\": \\"text\\",
|
||||
\\"size\\": \\"40\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 7
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
|
||||
\\"id\\": 8
|
||||
}
|
||||
],
|
||||
\\"id\\": 5
|
||||
}
|
||||
],
|
||||
\\"id\\": 3
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 9,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"link\\",
|
||||
\\"attributes\\": {
|
||||
\\"_cssText\\": \\"body { color: pink; }\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 9
|
||||
}
|
||||
}
|
||||
],
|
||||
\\"removes\\": [],
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": []
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record captures stylesheets with \`blob:\` url 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"name\\": \\"html\\",
|
||||
\\"publicId\\": \\"\\",
|
||||
\\"systemId\\": \\"\\",
|
||||
\\"id\\": 2
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"link\\",
|
||||
\\"attributes\\": {
|
||||
\\"_cssText\\": \\"body { color: pink; }\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 5
|
||||
}
|
||||
],
|
||||
\\"id\\": 4
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 7
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"input\\",
|
||||
\\"attributes\\": {
|
||||
\\"type\\": \\"text\\",
|
||||
\\"size\\": \\"40\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 8
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
|
||||
\\"id\\": 9
|
||||
}
|
||||
],
|
||||
\\"id\\": 6
|
||||
}
|
||||
],
|
||||
\\"id\\": 3
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`record iframes captures stylesheet mutations in iframes 1`] = `
|
||||
"[
|
||||
{
|
||||
|
||||
@@ -34,7 +34,9 @@ const setup = function (this: ISuite, content: string): ISuite {
|
||||
const ctx = {} as ISuite;
|
||||
|
||||
beforeAll(async () => {
|
||||
ctx.browser = await launchPuppeteer();
|
||||
ctx.browser = await launchPuppeteer({
|
||||
devtools: true,
|
||||
});
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
ctx.code = fs.readFileSync(bundlePath, 'utf8');
|
||||
@@ -143,16 +145,20 @@ describe('record', function (this: ISuite) {
|
||||
checkoutEveryNms: 500,
|
||||
});
|
||||
});
|
||||
let count = 30;
|
||||
while (count--) {
|
||||
await ctx.page.type('input', 'a');
|
||||
}
|
||||
await ctx.page.type('input', 'a');
|
||||
await ctx.page.waitForTimeout(300);
|
||||
expect(ctx.events.length).toEqual(33); // before first automatic snapshot
|
||||
await ctx.page.waitForTimeout(200); // could be 33 or 35 events by now depending on speed of test env
|
||||
expect(
|
||||
ctx.events.filter((event: eventWithTime) => event.type === EventType.Meta)
|
||||
.length,
|
||||
).toEqual(1); // before first automatic snapshot
|
||||
expect(
|
||||
ctx.events.filter(
|
||||
(event: eventWithTime) => event.type === EventType.FullSnapshot,
|
||||
).length,
|
||||
).toEqual(1); // before first automatic snapshot
|
||||
await ctx.page.waitForTimeout(200);
|
||||
await ctx.page.type('input', 'a');
|
||||
await ctx.page.waitForTimeout(10);
|
||||
expect(ctx.events.length).toEqual(36); // additionally includes the 2 checkout events
|
||||
expect(
|
||||
ctx.events.filter((event: eventWithTime) => event.type === EventType.Meta)
|
||||
.length,
|
||||
@@ -162,8 +168,6 @@ describe('record', function (this: ISuite) {
|
||||
(event: eventWithTime) => event.type === EventType.FullSnapshot,
|
||||
).length,
|
||||
).toEqual(2);
|
||||
expect(ctx.events[1].type).toEqual(EventType.FullSnapshot);
|
||||
expect(ctx.events[35].type).toEqual(EventType.FullSnapshot);
|
||||
});
|
||||
|
||||
it('is safe to checkout during async callbacks', async () => {
|
||||
@@ -381,6 +385,151 @@ describe('record', function (this: ISuite) {
|
||||
await waitForRAF(ctx.page);
|
||||
assertSnapshot(ctx.events);
|
||||
});
|
||||
|
||||
it('captures stylesheets with `blob:` url', async () => {
|
||||
await ctx.page.evaluate(() => {
|
||||
const link1 = document.createElement('link');
|
||||
link1.setAttribute('rel', 'stylesheet');
|
||||
link1.setAttribute(
|
||||
'href',
|
||||
URL.createObjectURL(
|
||||
new Blob(['body { color: pink; }'], {
|
||||
type: 'text/css',
|
||||
}),
|
||||
),
|
||||
);
|
||||
document.head.appendChild(link1);
|
||||
});
|
||||
await waitForRAF(ctx.page);
|
||||
await ctx.page.evaluate(() => {
|
||||
const { record } = ((window as unknown) as IWindow).rrweb;
|
||||
|
||||
record({
|
||||
inlineStylesheet: true,
|
||||
emit: ((window as unknown) as IWindow).emit,
|
||||
});
|
||||
});
|
||||
await waitForRAF(ctx.page);
|
||||
assertSnapshot(ctx.events);
|
||||
});
|
||||
|
||||
it('captures stylesheets in iframes with `blob:` url', async () => {
|
||||
await ctx.page.evaluate(() => {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('src', 'about:blank');
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
const linkEl = document.createElement('link');
|
||||
linkEl.setAttribute('rel', 'stylesheet');
|
||||
linkEl.setAttribute(
|
||||
'href',
|
||||
URL.createObjectURL(
|
||||
new Blob(['body { color: pink; }'], {
|
||||
type: 'text/css',
|
||||
}),
|
||||
),
|
||||
);
|
||||
const iframeDoc = iframe.contentDocument!;
|
||||
iframeDoc.head.appendChild(linkEl);
|
||||
});
|
||||
await waitForRAF(ctx.page);
|
||||
await ctx.page.evaluate(() => {
|
||||
const { record } = ((window as unknown) as IWindow).rrweb;
|
||||
|
||||
record({
|
||||
inlineStylesheet: true,
|
||||
emit: ((window as unknown) as IWindow).emit,
|
||||
});
|
||||
});
|
||||
await waitForRAF(ctx.page);
|
||||
assertSnapshot(ctx.events);
|
||||
});
|
||||
|
||||
it('captures stylesheets that are still loading', async () => {
|
||||
await ctx.page.evaluate(() => {
|
||||
const { record } = ((window as unknown) as IWindow).rrweb;
|
||||
|
||||
record({
|
||||
inlineStylesheet: true,
|
||||
emit: ((window as unknown) as IWindow).emit,
|
||||
});
|
||||
|
||||
const link1 = document.createElement('link');
|
||||
link1.setAttribute('rel', 'stylesheet');
|
||||
link1.setAttribute(
|
||||
'href',
|
||||
URL.createObjectURL(
|
||||
new Blob(['body { color: pink; }'], {
|
||||
type: 'text/css',
|
||||
}),
|
||||
),
|
||||
);
|
||||
document.head.appendChild(link1);
|
||||
});
|
||||
|
||||
// `blob:` URLs are not available immediately, so we need to wait for the browser to load them
|
||||
await waitForRAF(ctx.page);
|
||||
|
||||
assertSnapshot(ctx.events);
|
||||
});
|
||||
|
||||
it('captures stylesheets in iframes that are still loading', async () => {
|
||||
await ctx.page.evaluate(() => {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('src', 'about:blank');
|
||||
document.body.appendChild(iframe);
|
||||
const iframeDoc = iframe.contentDocument!;
|
||||
|
||||
const { record } = ((window as unknown) as IWindow).rrweb;
|
||||
|
||||
record({
|
||||
inlineStylesheet: true,
|
||||
emit: ((window as unknown) as IWindow).emit,
|
||||
});
|
||||
|
||||
const linkEl = document.createElement('link');
|
||||
linkEl.setAttribute('rel', 'stylesheet');
|
||||
linkEl.setAttribute(
|
||||
'href',
|
||||
URL.createObjectURL(
|
||||
new Blob(['body { color: pink; }'], {
|
||||
type: 'text/css',
|
||||
}),
|
||||
),
|
||||
);
|
||||
iframeDoc.head.appendChild(linkEl);
|
||||
});
|
||||
|
||||
// `blob:` URLs are not available immediately, so we need to wait for the browser to load them
|
||||
await waitForRAF(ctx.page);
|
||||
|
||||
assertSnapshot(ctx.events);
|
||||
});
|
||||
|
||||
it('captures CORS stylesheets that are still loading', async () => {
|
||||
const corsStylesheetURL =
|
||||
'https://cdn.jsdelivr.net/npm/pure@2.85.0/index.css';
|
||||
|
||||
// do not `await` the following function, otherwise `waitForResponse` _might_ not be called
|
||||
void ctx.page.evaluate((corsStylesheetURL) => {
|
||||
const { record } = ((window as unknown) as IWindow).rrweb;
|
||||
|
||||
record({
|
||||
inlineStylesheet: true,
|
||||
emit: ((window as unknown) as IWindow).emit,
|
||||
});
|
||||
|
||||
const link1 = document.createElement('link');
|
||||
link1.setAttribute('rel', 'stylesheet');
|
||||
link1.setAttribute('href', corsStylesheetURL);
|
||||
document.head.appendChild(link1);
|
||||
}, corsStylesheetURL);
|
||||
|
||||
await ctx.page.waitForResponse(corsStylesheetURL); // wait for stylesheet to be loaded
|
||||
await waitForRAF(ctx.page); // wait for rrweb to emit events
|
||||
|
||||
assertSnapshot(ctx.events);
|
||||
});
|
||||
});
|
||||
|
||||
describe('record iframes', function (this: ISuite) {
|
||||
@@ -463,7 +612,8 @@ describe('record iframes', function (this: ISuite) {
|
||||
}, 10);
|
||||
}, 10);
|
||||
});
|
||||
await ctx.page.waitForTimeout(50);
|
||||
await ctx.page.waitForTimeout(50); // wait till setTimeout is called
|
||||
await waitForRAF(ctx.page); // wait till events get sent
|
||||
const styleRelatedEvents = ctx.events.filter(
|
||||
(e) =>
|
||||
e.type === EventType.IncrementalSnapshot &&
|
||||
|
||||
Reference in New Issue
Block a user