Add observers for stylesheet mutations (#177)
* hack together stylesheet observer * Add test coverage for insertRule/deleteRule on stylesheets * Add new observers * update patch based on changes to master * Functioning event recording * Remove print statements * Fix ID usage and mark add vs remove * Correct type Co-authored-by: Jon Perl <perl.jonathan@gmail.com>
This commit is contained in:
@@ -286,7 +286,7 @@ exports[`block 1`] = `
|
||||
\\"attributes\\": {
|
||||
\\"class\\": \\"rr-block\\",
|
||||
\\"rr_width\\": \\"1904px\\",
|
||||
\\"rr_height\\": \\"21px\\"
|
||||
\\"rr_height\\": \\"19px\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 18
|
||||
|
||||
@@ -6,8 +6,8 @@ exports[`async-checkout 1`] = `
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 800,
|
||||
\\"height\\": 600
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -132,8 +132,8 @@ exports[`async-checkout 1`] = `
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 800,
|
||||
\\"height\\": 600
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -204,44 +204,6 @@ exports[`async-checkout 1`] = `
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": [],
|
||||
\\"removes\\": [
|
||||
{
|
||||
\\"parentId\\": 8,
|
||||
\\"id\\": 9
|
||||
}
|
||||
],
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 4,
|
||||
\\"previousId\\": 8,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"span\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 9
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"parentId\\": 9,
|
||||
\\"previousId\\": null,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"test\\",
|
||||
\\"id\\": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
@@ -252,8 +214,8 @@ exports[`custom-event 1`] = `
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 800,
|
||||
\\"height\\": 600
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -331,3 +293,146 @@ exports[`custom-event 1`] = `
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`stylesheet-rules 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 3
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 5
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"input\\",
|
||||
\\"attributes\\": {
|
||||
\\"type\\": \\"text\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 6
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
|
||||
\\"id\\": 7
|
||||
}
|
||||
],
|
||||
\\"id\\": 4
|
||||
}
|
||||
],
|
||||
\\"id\\": 2
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 8,
|
||||
\\"id\\": -1,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"rule\\": \\"body { background: #000; }\\"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": [],
|
||||
\\"removes\\": [],
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 3,
|
||||
\\"previousId\\": null,
|
||||
\\"nextId\\": null,
|
||||
\\"node\\": {
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"style\\",
|
||||
\\"attributes\\": {
|
||||
\\"_cssText\\": \\"body { background: rgb(0, 0, 0); }\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 8,
|
||||
\\"id\\": 8,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"rule\\": \\"body { color: #fff; }\\"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 8,
|
||||
\\"id\\": 8,
|
||||
\\"removes\\": [
|
||||
{
|
||||
\\"index\\": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 8,
|
||||
\\"id\\": 8,
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"rule\\": \\"body { color: #ccc; }\\"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as puppeteer from 'puppeteer';
|
||||
import { assertSnapshot } from './utils';
|
||||
import { assertSnapshot, launchPuppeteer } from './utils';
|
||||
import { Suite } from 'mocha';
|
||||
import { recordOptions } from '../src/types';
|
||||
|
||||
@@ -35,14 +35,7 @@ describe('record integration tests', function(this: ISuite) {
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
this.browser = await puppeteer.launch({
|
||||
defaultViewport: {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
},
|
||||
headless: false,
|
||||
args: ['--no-sandbox'],
|
||||
});
|
||||
this.browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
this.code = fs.readFileSync(bundlePath, 'utf8');
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
eventWithTime,
|
||||
EventType,
|
||||
} from '../src/types';
|
||||
import { assertSnapshot } from './utils';
|
||||
import { assertSnapshot, launchPuppeteer } from './utils';
|
||||
import { Suite } from 'mocha';
|
||||
|
||||
interface ISuite extends Suite {
|
||||
@@ -30,10 +30,7 @@ interface IWindow extends Window {
|
||||
|
||||
describe('record', function(this: ISuite) {
|
||||
before(async () => {
|
||||
this.browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
args: ['--no-sandbox'],
|
||||
});
|
||||
this.browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
this.code = fs.readFileSync(bundlePath, 'utf8');
|
||||
@@ -196,4 +193,32 @@ describe('record', function(this: ISuite) {
|
||||
await this.page.waitFor(50);
|
||||
assertSnapshot(this.events, __filename, 'custom-event');
|
||||
});
|
||||
|
||||
it('captures stylesheet rules', async () => {
|
||||
await this.page.evaluate(() => {
|
||||
const { record } = ((window as unknown) as IWindow).rrweb;
|
||||
|
||||
record({
|
||||
emit: ((window as unknown) as IWindow).emit,
|
||||
});
|
||||
|
||||
const styleElement = document.createElement('style');
|
||||
document.head.appendChild(styleElement);
|
||||
|
||||
const styleSheet = <CSSStyleSheet>styleElement.sheet;
|
||||
const ruleIdx0 = styleSheet.insertRule('body { background: #000; }');
|
||||
setTimeout(() => {
|
||||
styleSheet.insertRule('body { color: #fff; }');
|
||||
}, 0);
|
||||
setTimeout(() => {
|
||||
styleSheet.deleteRule(ruleIdx0);
|
||||
}, 5);
|
||||
setTimeout(() => {
|
||||
styleSheet.insertRule('body { color: #ccc; }');
|
||||
}, 10);
|
||||
});
|
||||
await this.page.waitFor(10);
|
||||
expect(this.events.length).to.equal(7);
|
||||
assertSnapshot(this.events, __filename, 'stylesheet-rules');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
MouseInteractions,
|
||||
} from '../src/types';
|
||||
import { Replayer } from '../src';
|
||||
import { launchPuppeteer } from './utils';
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
@@ -122,10 +123,7 @@ interface ISuite extends Suite {
|
||||
|
||||
describe('replayer', function(this: ISuite) {
|
||||
before(async () => {
|
||||
this.browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
args: ['--no-sandbox'],
|
||||
});
|
||||
this.browser = await launchPuppeteer();
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js');
|
||||
this.code = fs.readFileSync(bundlePath, 'utf8');
|
||||
|
||||
@@ -2,6 +2,18 @@ import { SnapshotState, toMatchSnapshot } from 'jest-snapshot';
|
||||
import { NodeType } from 'rrweb-snapshot';
|
||||
import { assert } from 'chai';
|
||||
import { EventType, IncrementalSource, eventWithTime } from '../src/types';
|
||||
import * as puppeteer from 'puppeteer';
|
||||
|
||||
export async function launchPuppeteer() {
|
||||
return await puppeteer.launch({
|
||||
headless: process.env.PUPPETEER_HEADLESS ? true : false,
|
||||
defaultViewport: {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
},
|
||||
args: ['--no-sandbox'],
|
||||
});
|
||||
}
|
||||
|
||||
function matchSnapshot(actual: string, testFile: string, testTitle: string) {
|
||||
const snapshotState = new SnapshotState(testFile, {
|
||||
|
||||
Reference in New Issue
Block a user