import { compare } from 'compare-versions'; import { RRDocument, RRNode } from '../src/document-nodejs'; import { polyfillPerformance, polyfillRAF, polyfillEvent, polyfillNode, polyfillDocument, } from '../src/polyfill'; import { performance as nativePerformance } from 'perf_hooks'; 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(nativePerformance.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); }); });