Support top-layer <dialog> recording & replay (#1503)
* chore: its important to run `yarn build:all` before running `yarn dev` * feat: trigger showModal from rrdom and rrweb * feat: Add support for replaying modal and non modal dialog elements * chore: Update dev script to remove CLEAR_DIST_DIR flag * Get modal recording and replay working * DRY up dialog test and dedupe snapshot images * feat: Refactor dialog test to use updated attribute name * feat: Update dialog test to include rr_open attribute * chore: Add npm dependency happy-dom@14.12.0 * Add more test cases for dialog * Clean up naming * Refactor dialog open code * Revert changed code that doesn't do anything * Add documentation for unimplemented type * chore: Remove unnecessary comments in dialog.test.ts * rename rr_open to rr_openMode * Replace todo with a skipped test * Add better logging for CI * Rename rr_openMode to rr_open_mode rrdom downcases all attribute names which made `rr_openMode` tricky to deal with * Remove unused images * Move after iframe append based on @YunFeng0817's comment https://github.com/rrweb-io/rrweb/pull/1503#discussion_r1666363931 * Remove redundant dialog handling from rrdom. rrdom already handles dialog element creation it's self * Rename variables for dialog handling in rrweb replay module * Update packages/rrdom/src/document.ts --------- Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
This commit is contained in:
@@ -1,10 +1,20 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as http from 'http';
|
||||
import * as url from 'url';
|
||||
import * as path from 'path';
|
||||
import * as puppeteer from 'puppeteer';
|
||||
import { vi, assert, describe, it, beforeAll, afterAll, expect } from 'vitest';
|
||||
import { waitForRAF, getServerURL } from './utils';
|
||||
import * as url from 'url';
|
||||
import {
|
||||
afterAll,
|
||||
assert,
|
||||
beforeAll,
|
||||
beforeEach,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
vi,
|
||||
} from 'vitest';
|
||||
|
||||
import { getServerURL, waitForRAF } from './utils';
|
||||
|
||||
const htmlFolder = path.join(__dirname, 'html');
|
||||
const htmls = fs.readdirSync(htmlFolder).map((filePath) => {
|
||||
@@ -60,6 +70,15 @@ function sanitizeSnapshot(snapshot: string): string {
|
||||
return snapshot.replace(/localhost:[0-9]+/g, 'localhost:3030');
|
||||
}
|
||||
|
||||
async function snapshot(page: puppeteer.Page, code: string): Promise<string> {
|
||||
await waitForRAF(page);
|
||||
const result = (await page.evaluate(`${code}
|
||||
const snapshot = rrwebSnapshot.snapshot(document);
|
||||
JSON.stringify(snapshot, null, 2);
|
||||
`)) as string;
|
||||
return result;
|
||||
}
|
||||
|
||||
function assertSnapshot(snapshot: string): void {
|
||||
expect(sanitizeSnapshot(snapshot)).toMatchSnapshot();
|
||||
}
|
||||
@@ -68,6 +87,7 @@ interface ISuite {
|
||||
server: http.Server;
|
||||
serverURL: string;
|
||||
browser: puppeteer.Browser;
|
||||
page: puppeteer.Page;
|
||||
code: string;
|
||||
}
|
||||
|
||||
@@ -431,6 +451,53 @@ describe('iframe integration tests', function (this: ISuite) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('dialog integration tests', function (this: ISuite) {
|
||||
vi.setConfig({ testTimeout: 30_000 });
|
||||
let server: ISuite['server'];
|
||||
let serverURL: ISuite['serverURL'];
|
||||
let browser: ISuite['browser'];
|
||||
let code: ISuite['code'];
|
||||
let page: ISuite['page'];
|
||||
|
||||
beforeAll(async () => {
|
||||
server = await startServer();
|
||||
serverURL = getServerURL(server);
|
||||
browser = await puppeteer.launch({
|
||||
// headless: false,
|
||||
});
|
||||
|
||||
code = fs.readFileSync(
|
||||
path.resolve(__dirname, '../dist/rrweb-snapshot.umd.cjs'),
|
||||
'utf-8',
|
||||
);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
page = await browser.newPage();
|
||||
page.on('console', (msg) => console.log(msg.text()));
|
||||
await page.goto(`${serverURL}/html/dialog.html`, {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await browser.close();
|
||||
await server.close();
|
||||
});
|
||||
|
||||
it('should capture open attribute for non modal dialogs', async () => {
|
||||
page.evaluate('document.querySelector("dialog").show()');
|
||||
const snapshotResult = await snapshot(page, code);
|
||||
assertSnapshot(snapshotResult);
|
||||
});
|
||||
|
||||
it('should capture open attribute for modal dialogs', async () => {
|
||||
await page.evaluate('document.querySelector("dialog").showModal()');
|
||||
const snapshotResult = await snapshot(page, code);
|
||||
assertSnapshot(snapshotResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shadow DOM integration tests', function (this: ISuite) {
|
||||
vi.setConfig({ testTimeout: 30_000 });
|
||||
let server: ISuite['server'];
|
||||
|
||||
Reference in New Issue
Block a user