Files
rrweb/packages/rrdom/test/polyfill.test.ts
Justin Halsall de755ae577 #853 Second try: fast-forward implementation v2: virtual dom optimization (#895)
* rrdom: add a diff function for properties

* implement diffChildren function and unit tests

* finish basic functions of diff algorithm

* fix several bugs in the diff algorithm

* replace the virtual parent optimization in applyMutation()

* fix: moveAndHover after the diff algorithm is executed

* replace virtual style map with rrdom

cssom version has to be above 0.5.0 to pass virtual style tests

* fix: failed virtual style tests in replayer.test.ts

* fix: failed polyfill tests caused by nodejs compatibility of different versions

* fix: svg viewBox attribute doesn't work

Cause the attribute viewBox is case sensitive, set value for viewbox doesn't work

* feat: replace treeIndex optimization with rrdom

* fix bug of diffProps and disable smooth scrolling animation in fast-forward mode

* feat: add iframe support

* fix: @rollup/plugin-typescript build errors in rrweb-player

Error: @rollup/plugin-typescript TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'

* fix: bug when fast-forward input events and add test for it

* add test for fast-forward scroll events

* fix: custom style rules don't get inserted into some iframe elements

* code style tweak

* fix: enable to diff iframe elements

* fix  the jest error "Unexpected token 'export'"

* try to fix build error of rrweb-player

* correct the attributes definition in rrdom

* fix: custom style rules are not inserted in some iframes

* add support for shadow dom

* add support for MediaInteraction

* add canvas support

* fix unit test error in rrdom

* add support for Text, Comment

* try to refactor RRDom

* refactor RRDom to reduce duplicate code

* rename document-browser to virtual-dom

* increase the test coverage for document.ts and add ownerDocument for it

* Merge branch 'master' into virtual-dom

* add more test for virtual-dom.ts

* use cssstyle in document-nodejs

* fix: bundle error

* improve document-nodejs

* enable to diff scroll positions of an element

* rename rrdom to virtualDom for more readability and make the tree public

* revert unknown change

* improve the css style parser for comments

* improve code style

* update typings

* add handling for the case where legacy_missingNodeRetryMap is not empty

* only import types from rrweb into rrdom

* Apply suggestions from code review

Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>

* Apply suggestions from code review

* fix building error in rrweb

* add a method setDefaultSN to set a default value for a RRNode's __sn

* fix rrweb test error and bump up other packages

* add support for custom property of css styles

* add a switch for virtual-dom optimization

* Apply suggestions from code review

1. add an enum type for NodeType
2. rename nodeType from rrweb-snapshot to RRNodeType
3. rename notSerializedId to unserializedId
4. add comments for some confusing variables

* adapt changes of #865 to virtual-dom and improve the test case for more coverage

* apply review suggestions

https://github.com/rrweb-io/rrweb/pull/853#pullrequestreview-922474953

* tweak the diff algorithm

* add description of the flag useVirtualDom and remove outdated logConfig

* Remove console.log

* Contain changes to document

* Upgrade rollup to 2.70.2

* Revert "Upgrade rollup to 2.70.2"

This reverts commit b1be81a2a76565935c9dc391f31beb7f64d25956.

* Fix type checking rrdom

* Fix typing error while bundling

* Fix tslib error on build

Rollup would output the following error:
`semantic error TS2343: This syntax requires an imported helper named '__spreadArray' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.`

* Increase memory limit for rollup

* Use esbuild for bundling

Speeds up bundling significantly

* Avoid circular dependencies and import un-bundled rrdom

* Fix imports

* Revert back to pre-esbuild

This reverts the following commits:
b7b3c8dbaa551a0129da1477136b1baaad28e6e1
72e23b8e27f9030d911358d3a17fe5ad1b3b5d4f
85d600a20c56cfa764cf1f858932ba14e67b1d23
61e1a5d323212ca8fbe0569e0b3062ddd53fc612

* Set node to lts (12 is no longer supported)

* Speed up bundling and use less memory

This fixes the out of memory errors happening while bundling

* remove __sn from rrdom

* fix typo

* test: add a test case for StyleSheet mutation exceptions while fast-forwarding

* rename Array.prototype.slice.call() to Array.from()

* improve test cases

* fix: PR #887 in 'virtual-dom' branch

* apply justin's suggestion on 'Array.from' refactor

related commit 0f6729d27a323260b36fbe79485a86715c0bc98a

* improve import code structure

Co-authored-by: Yun Feng <yun.feng@anu.edu.au>
2022-05-12 12:01:13 +08:00

132 lines
4.4 KiB
TypeScript

import { compare } from 'compare-versions';
import { RRDocument, RRNode } from '../src/document-nodejs';
import {
polyfillPerformance,
polyfillRAF,
polyfillEvent,
polyfillNode,
polyfillDocument,
} from '../src/polyfill';
describe('polyfill for nodejs', () => {
it('should polyfill performance api', () => {
if (compare(process.version, 'v16.0.0', '<'))
expect(global.performance).toBeUndefined();
polyfillPerformance();
expect(global.performance).toBeDefined();
expect(performance).toBeDefined();
expect(performance.now).toBeDefined();
expect(performance.now()).toBeCloseTo(
require('perf_hooks').performance.now(),
1e-10,
);
});
it('should not polyfill performance if it already exists', () => {
if (compare(process.version, 'v16.0.0', '>=')) {
const originalPerformance = global.performance;
polyfillPerformance();
expect(global.performance).toBe(originalPerformance);
}
const fakePerformance = (jest.fn() as unknown) as Performance;
global.performance = fakePerformance;
polyfillPerformance();
expect(global.performance).toEqual(fakePerformance);
});
it('should polyfill requestAnimationFrame', () => {
expect(global.requestAnimationFrame).toBeUndefined();
expect(global.cancelAnimationFrame).toBeUndefined();
polyfillRAF();
expect(global.requestAnimationFrame).toBeDefined();
expect(global.cancelAnimationFrame).toBeDefined();
expect(requestAnimationFrame).toBeDefined();
expect(cancelAnimationFrame).toBeDefined();
jest.useFakeTimers();
const AnimationTime = 1_000; // target animation time(unit: ms)
const startTime = Date.now();
let frameCount = 0;
const rafCallback1 = () => {
const currentTime = Date.now();
frameCount++;
if (currentTime - startTime < AnimationTime) {
requestAnimationFrame(rafCallback1);
} else {
expect(frameCount).toBeGreaterThanOrEqual(55);
expect(frameCount).toBeLessThanOrEqual(65);
}
};
requestAnimationFrame(rafCallback1);
// Fast-forward until all timers have been executed
jest.runAllTimers();
let rafHandle;
const rafCallback2 = () => {
rafHandle = requestAnimationFrame(rafCallback2);
};
rafHandle = requestAnimationFrame(rafCallback2);
// If this function doesn't work, recursive function will never end.
cancelAnimationFrame(rafHandle);
jest.runAllTimers();
jest.useRealTimers();
});
it('should not polyfill requestAnimationFrame if it already exists', () => {
const fakeRequestAnimationFrame = (jest.fn() as unknown) as typeof global.requestAnimationFrame;
global.requestAnimationFrame = fakeRequestAnimationFrame;
const fakeCancelAnimationFrame = (jest.fn() as unknown) as typeof global.cancelAnimationFrame;
global.cancelAnimationFrame = fakeCancelAnimationFrame;
polyfillRAF();
expect(global.requestAnimationFrame).toBe(fakeRequestAnimationFrame);
expect(global.cancelAnimationFrame).toBe(fakeCancelAnimationFrame);
});
it('should polyfill Event type', () => {
// if the second version is greater
if (compare(process.version, 'v15.0.0', '<'))
expect(global.Event).toBeUndefined();
polyfillEvent();
expect(global.Event).toBeDefined();
expect(Event).toBeDefined();
});
it('should not polyfill Event type if it already exists', () => {
const fakeEvent = (jest.fn() as unknown) as typeof global.Event;
global.Event = fakeEvent;
polyfillEvent();
expect(global.Event).toBe(fakeEvent);
});
it('should polyfill Node type', () => {
expect(global.Node).toBeUndefined();
polyfillNode();
expect(global.Node).toBeDefined();
expect(Node).toBeDefined();
expect(Node).toEqual(RRNode);
});
it('should not polyfill Node type if it already exists', () => {
const fakeNode = (jest.fn() as unknown) as typeof global.Node;
global.Node = fakeNode;
polyfillNode();
expect(global.Node).toBe(fakeNode);
});
it('should polyfill document object', () => {
expect(global.document).toBeUndefined();
polyfillDocument();
expect(global.document).toBeDefined();
expect(document).toBeDefined();
expect(document).toBeInstanceOf(RRDocument);
});
it('should not polyfill document object if it already exists', () => {
const fakeDocument = (jest.fn() as unknown) as typeof global.document;
global.document = fakeDocument;
polyfillDocument();
expect(global.document).toBe(fakeDocument);
});
});