* Chore: Add move most types from rrweb to @rrweb/types package * Split off type imports * Split off type import to its own line * Get vite to generate type definitions * Apply formatting changes * noEmit not allowed in tsconfig, moved it to build step * Migrate rrdom-nodejs build to vite * Apply formatting changes * Migrate rrweb-snapshot to vite * Unify configs * Chore: Migrate rrdom to vite Turns out what we where doing by overwriting `public textContent: string | undefined` as a getter in a subclass is something that isn't allowed in typescript. Because we where using `// @ts-ignore` to hide this error our bundler chose to allow the overwrite. Vite choses to disallow the overwrite making all subclasses' `textContent` undefined. To mitigate this we're using an abstract class, which does allow sub classes to decide if they wan't to use getters or not. * Chore: Migrate rrweb to vite WIP * build:browser was removed (for now) * BREAKING: moved rrweb-plugin-console to its own npm module This removes console from rrweb-all.js * Support cjs files in startServer * Move canvas-webrtc plugin to its own package * Chore: move sequential-id plugin to its own package * Chore: Configure rrweb's vite bundling * `Id` had lowercase `d` before, making it lowercase again * Test: Move console tests to their own package * remove unused utils from rrdom * pull in latest version of master something when wrong earlier when resolving merge conflicts, this should be correct * Fix type casting issue in diff.ts * Fix typo * Fix duplicate entries in package.json and tsconfig.json * Apply formatting changes * Update dependencies in package.json files * Update dependencies to use Vite 5.2.8 in package.json files * Get tests passing for rrdom `apply virtual style rules to node` tests need to be moved to rrweb to avoid circular dependencies * Fix image loading issue in integration tests * Move pack/unpack to its own @rrweb/packer module * Get tests to work in rrdom-nodejs * Port tests in rrweb-snapshot to vitest and fix them * Fix tests for rrweb-plugin-console-record * Add @rrweb/all package * Fix publint and attw errors for rrdom and @rrweb/types * Use shared vitest.config.ts in rrweb-snapshot package * Fix publint and attw issues for rrweb-snapshot * Export `ReplayPlugin` type directly from rrweb * Fix publint and attw issues for packages * Fix publint & attw issue. I was bumping into this issue:3729bc2a3c/docs/problems/NoResolution.mdAnd had to choose one of these three methods described here: https://github.com/andrewbranch/example-subpath-exports-ts-compat?tab=readme-ov-file#typescript-friendly-strategies-for-packagejson-subpath-exports-compatibility And I ended up going for the method described here:1ffe3425b0/examples/node_modules/package-json-redirects (package-json-redirects)The redirect method seemed the least invasive and most effective. * Fix publint & attw issue. I was bumping into this issue:3729bc2a3c/docs/problems/NoResolution.mdAnd had to choose one of these three methods described here: https://github.com/andrewbranch/example-subpath-exports-ts-compat?tab=readme-ov-file#typescript-friendly-strategies-for-packagejson-subpath-exports-compatibility And I ended up going for the method described here:1ffe3425b0/examples/node_modules/package-json-redirects (package-json-redirects)The redirect method seemed the least invasive and most effective. * move some rrdom tests that require rrweb to rrweb package * Use pre-jest 29 syntax for snapshotting * get rrweb passing publint and attw * const enum does not work with isolated modules flag * Fix script tag type in webgl.test.ts.snap and update rrweb.umd.cjs path in webgl.test.ts * Fix paths * Move tests for console record plugin and fix bundle path * Fix tests for rrweb * pack integration tests were moved to @rrweb/all * Update rrweb bundle path in test files * Fix flaky scroll emit from test * Migrate rrweb's tests over to vitest and make them pass * Make sure benchmarks & updating tests work * Remove jest from rrweb * Fix paths * always use rrweb's own cssom * Update tsconfig.json for rrweb-plugin-sequential-id-record Fixes this error: Error: @rrweb/rrweb-plugin-sequential-id-record:prepublish: tsconfig.json(9,5): error TS6377: Cannot write file '/home/runner/work/rrweb/rrweb/tsconfig.tsbuildinfo' because it will overwrite '.tsbuildinfo' file generated by referenced project '/home/runner/work/rrweb/rrweb/packages/rrweb' * Add tsbuildinfo config to extended tsconfig files * Move rrdom over to vitest * Apply formatting changes * Update rrweb imports to use the new package structure * extend rrweb-snapshot's tsconfig from monorepo base config * extend @rrweb/types's tsconfig from monorepo base config * extend rrdom's tsconfig from monorepo base config * extend rrdom-nodejs's tsconfig from monorepo base config * extend web-extension's tsconfig from monorepo base config * unify tsconfigs * Continue when tests fail * Add stricter type checking * Add check-types global command * remove jest * Remove unused code * Add check-types command to build script * Fix linting issues * Add setup Chrome action for CI/CD workflow * Update puppeteer version in package.json for rrweb * Update Chrome setup in CI/CD workflow * Update Chrome setup in CI/CD workflow * Add Chrome setup and test cache location * Update CI/CD workflow to test chrome cache location * Add chrome installation step to CI/CD workflow * Update Puppeteer configuration for headless testing * Update dependencies and workflow configuration * Use same version of chrome on CI as is run locally * Use version of chrome that seems to work with rrdom tests * Try using puppeteerrc to define chrome version * Add .cache directory to .gitignore * Move global flag to vitest config * Update puppeteer version to 20.9.0 * Update console log messages in rrweb-plugin-console-record for new puppeteer version * Remove redundant Chrome setup from CI/CD workflow * Add minification and umd for all built files * Update import paths for rrweb dist files * Add @rrweb/replay and @rrweb/record * Add script to lint packages * Apply formatting changes * exclude styles export from typescript package type checking * WIP Move rrweb-player over to vite * Apply formatting changes * chore: Update rrweb plugin import paths * Remove rollup from rrweb-player * Fix typing issues * Fix typing issues * chore: Update rrweb-player to use vite for build process * Apply formatting changes * chore: Export Player class in rrweb-player/src/main.ts Makes attw happy * Apply formatting changes * Gets wiped by yarn workspaces-to-typescript-project-references * Add .eslintignore and .eslintrc.cjs files for rrweb-player package * Apply formatting changes * Update dependencies in rrweb-player/package.json * Apply formatting changes * chore: Update eslint configuration for rrweb-player package * Apply formatting changes * chore: Remove unused files from rrweb-player package * Apply formatting changes * chore: Update rrweb-player import path to use rrweb-player.cjs * chore: Update addEventListener signature in rrweb-player * Apply formatting changes * Add .eslintignore and update .gitignore files for to root * Apply formatting changes * Update documentation * Update @rrweb/types package description * Apply formatting changes * Update build and run commands in CONTRIBUTING.md * Apply formatting changes * Update package versions to 2.0.0-alpha.13 * Apply formatting changes * Apply formatting changes * Fix import statement in media/index.ts * Apply formatting changes * chore: Update .gitignore to exclude build and dist directories * Apply formatting changes * Apply formatting changes * Migrate setTimeout to vitest * Apply formatting changes * Apply formatting changes * Fix isNativeShadowDom function signature in utils.ts * try out jsr * Apply formatting changes * Update package versions to 2.0.0-alpha.14 * Apply formatting changes * Fix name of rrwebSnapshot object * Apply formatting changes * Remove unused lock files * Apply formatting changes * Update rrweb bundle path to use umd.cjs format * Apply formatting changes * Trigger tests to run again * Rename snapshots for vitest * Apply formatting changes * Ping CI * Apply formatting changes * Ping CI * Apply formatting changes * Ignore files generated by svelte-kit for prettier * Correct Player object
227 lines
7.1 KiB
TypeScript
227 lines
7.1 KiB
TypeScript
/**
|
|
* @vitest-environment jsdom
|
|
*/
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { describe, it, beforeEach, expect } from 'vitest';
|
|
import {
|
|
adaptCssForReplay,
|
|
buildNodeWithSN,
|
|
createCache,
|
|
} from '../src/rebuild';
|
|
import { NodeType } from '../src/types';
|
|
import { createMirror, Mirror } from '../src/utils';
|
|
|
|
function getDuration(hrtime: [number, number]) {
|
|
const [seconds, nanoseconds] = hrtime;
|
|
return seconds * 1000 + nanoseconds / 1000000;
|
|
}
|
|
|
|
describe('rebuild', function () {
|
|
let cache: ReturnType<typeof createCache>;
|
|
let mirror: Mirror;
|
|
|
|
beforeEach(() => {
|
|
mirror = createMirror();
|
|
cache = createCache();
|
|
});
|
|
|
|
describe('rr_dataURL', function () {
|
|
it('should rebuild dataURL', function () {
|
|
const dataURI =
|
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
|
const node = buildNodeWithSN(
|
|
{
|
|
id: 1,
|
|
tagName: 'img',
|
|
type: NodeType.Element,
|
|
attributes: {
|
|
rr_dataURL: dataURI,
|
|
src: 'http://example.com/image.png',
|
|
},
|
|
childNodes: [],
|
|
},
|
|
{
|
|
doc: document,
|
|
mirror,
|
|
hackCss: false,
|
|
cache,
|
|
},
|
|
) as HTMLImageElement;
|
|
expect(node?.src).toBe(dataURI);
|
|
});
|
|
});
|
|
|
|
describe('shadowDom', function () {
|
|
it('rebuild shadowRoot without siblings', function () {
|
|
const node = buildNodeWithSN(
|
|
{
|
|
id: 1,
|
|
tagName: 'div',
|
|
type: NodeType.Element,
|
|
attributes: {},
|
|
childNodes: [
|
|
{
|
|
id: 2,
|
|
tagName: 'div',
|
|
type: NodeType.Element,
|
|
attributes: {},
|
|
childNodes: [],
|
|
isShadow: true,
|
|
},
|
|
],
|
|
isShadowHost: true,
|
|
},
|
|
{
|
|
doc: document,
|
|
mirror,
|
|
hackCss: false,
|
|
cache,
|
|
},
|
|
) as HTMLDivElement;
|
|
expect(node.shadowRoot?.childNodes.length).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe('add hover class to hover selector related rules', function () {
|
|
it('will do nothing to css text without :hover', () => {
|
|
const cssText = 'body { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(cssText);
|
|
});
|
|
|
|
it('can add hover class to css text', () => {
|
|
const cssText = '.a:hover { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'.a:hover, .a.\\:hover { color: white }',
|
|
);
|
|
});
|
|
|
|
it('can correctly add hover when in middle of selector', () => {
|
|
const cssText = 'ul li a:hover img { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'ul li a:hover img, ul li a.\\:hover img { color: white }',
|
|
);
|
|
});
|
|
|
|
it('can correctly add hover on multiline selector', () => {
|
|
const cssText = `ul li.specified a:hover img,
|
|
ul li.multiline
|
|
b:hover
|
|
img,
|
|
ul li.specified c:hover img {
|
|
color: white
|
|
}`;
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
`ul li.specified a:hover img, ul li.specified a.\\:hover img,
|
|
ul li.multiline
|
|
b:hover
|
|
img, ul li.multiline
|
|
b.\\:hover
|
|
img,
|
|
ul li.specified c:hover img, ul li.specified c.\\:hover img {
|
|
color: white
|
|
}`,
|
|
);
|
|
});
|
|
|
|
it('can add hover class within media query', () => {
|
|
const cssText = '@media screen { .m:hover { color: white } }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'@media screen { .m:hover, .m.\\:hover { color: white } }',
|
|
);
|
|
});
|
|
|
|
it('can add hover class when there is multi selector', () => {
|
|
const cssText = '.a, .b:hover, .c { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'.a, .b:hover, .b.\\:hover, .c { color: white }',
|
|
);
|
|
});
|
|
|
|
it('can add hover class when there is a multi selector with the same prefix', () => {
|
|
const cssText = '.a:hover, .a:hover::after { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'.a:hover, .a.\\:hover, .a:hover::after, .a.\\:hover::after { color: white }',
|
|
);
|
|
});
|
|
|
|
it('can add hover class when :hover is not the end of selector', () => {
|
|
const cssText = 'div:hover::after { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'div:hover::after, div.\\:hover::after { color: white }',
|
|
);
|
|
});
|
|
|
|
it('can add hover class when the selector has multi :hover', () => {
|
|
const cssText = 'a:hover b:hover { color: white }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'a:hover b:hover, a.\\:hover b.\\:hover { color: white }',
|
|
);
|
|
});
|
|
|
|
it('will ignore :hover in css value', () => {
|
|
const cssText = '.a::after { content: ":hover" }';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(cssText);
|
|
});
|
|
|
|
it('can adapt media rules to replay context', () => {
|
|
const cssText =
|
|
'@media only screen and (min-device-width : 1200px) { .a { width: 10px; }}';
|
|
expect(adaptCssForReplay(cssText, cache)).toEqual(
|
|
'@media only screen and (min-width : 1200px) { .a { width: 10px; }}',
|
|
);
|
|
});
|
|
|
|
// this benchmark is unreliable when run in parallel with other tests
|
|
it.skip('benchmark', () => {
|
|
const cssText = fs.readFileSync(
|
|
path.resolve(__dirname, './css/benchmark.css'),
|
|
'utf8',
|
|
);
|
|
const start = process.hrtime();
|
|
adaptCssForReplay(cssText, cache);
|
|
const end = process.hrtime(start);
|
|
const duration = getDuration(end);
|
|
expect(duration).toBeLessThan(100);
|
|
});
|
|
|
|
it('should be a lot faster to add a hover class to a previously processed css string', () => {
|
|
const factor = 100;
|
|
|
|
let cssText = fs.readFileSync(
|
|
path.resolve(__dirname, './css/benchmark.css'),
|
|
'utf8',
|
|
);
|
|
|
|
const start = process.hrtime();
|
|
adaptCssForReplay(cssText, cache);
|
|
const end = process.hrtime(start);
|
|
|
|
const cachedStart = process.hrtime();
|
|
adaptCssForReplay(cssText, cache);
|
|
const cachedEnd = process.hrtime(cachedStart);
|
|
|
|
expect(getDuration(cachedEnd) * factor).toBeLessThan(getDuration(end));
|
|
});
|
|
});
|
|
|
|
it('should not incorrectly interpret escaped quotes', () => {
|
|
// the ':hover' in the below is a decoy which is not part of the selector,
|
|
// previously that part was being incorrectly consumed by the selector regex
|
|
const should_not_modify =
|
|
".tailwind :is(.before\\:content-\\[\\'\\'\\])::before { --tw-content: \":hover\"; content: var(--tw-content); }.tailwind :is(.\\[\\&\\>li\\]\\:before\\:content-\\[\\'-\\'\\] > li)::before { color: pink; }";
|
|
expect(adaptCssForReplay(should_not_modify, cache)).toEqual(
|
|
should_not_modify,
|
|
);
|
|
});
|
|
|
|
it('should not incorrectly interpret at rules', () => {
|
|
// the ':hover' in the below is a decoy which is not part of the selector,
|
|
const should_not_modify =
|
|
'@import url("https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,700;1,400&display=:hover");';
|
|
expect(adaptCssForReplay(should_not_modify, cache)).toEqual(
|
|
should_not_modify,
|
|
);
|
|
});
|
|
});
|