rrvideo: improve the video quality and add a progress bar for the CLI tool (#1197)
* refactor rrvideo: use playwright rather than puppeteer * add a progress bar for the tool * add tests for cli.ts * fix build error * add change log * update readme file * Apply a scaling method to improve the resolution of the output video
This commit is contained in:
45
packages/rrvideo/test/cli.test.ts
Normal file
45
packages/rrvideo/test/cli.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { execSync } from 'child_process';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import exampleEvents from './events/example';
|
||||
|
||||
describe('should be able to run cli', () => {
|
||||
beforeAll(() => {
|
||||
fs.mkdirSync(path.resolve(__dirname, './generated'));
|
||||
fs.writeJsonSync(
|
||||
path.resolve(__dirname, './generated/example.json'),
|
||||
exampleEvents,
|
||||
{
|
||||
spaces: 2,
|
||||
},
|
||||
);
|
||||
});
|
||||
afterAll(async () => {
|
||||
await fs.remove(path.resolve(__dirname, './generated'));
|
||||
});
|
||||
|
||||
it('should throw error without input path', () => {
|
||||
expect(() => {
|
||||
execSync('node ./build/cli.js', { stdio: 'pipe' });
|
||||
}).toThrowError(/.*please pass --input to your rrweb events file.*/);
|
||||
});
|
||||
|
||||
it('should generate a video without output path', () => {
|
||||
execSync('node ./build/cli.js --input ./test/generated/example.json', {
|
||||
stdio: 'pipe',
|
||||
});
|
||||
const outputFile = path.resolve(__dirname, '../rrvideo-output.webm');
|
||||
expect(fs.existsSync(outputFile)).toBe(true);
|
||||
fs.removeSync(outputFile);
|
||||
});
|
||||
|
||||
it('should generate a video with specific output path', () => {
|
||||
const outputFile = path.resolve(__dirname, './generated/output.webm');
|
||||
execSync(
|
||||
`node ./build/cli.js --input ./test/generated/example.json --output ${outputFile}`,
|
||||
{ stdio: 'pipe' },
|
||||
);
|
||||
expect(fs.existsSync(outputFile)).toBe(true);
|
||||
fs.removeSync(outputFile);
|
||||
});
|
||||
});
|
||||
147
packages/rrvideo/test/events/example.ts
Normal file
147
packages/rrvideo/test/events/example.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { EventType, IncrementalSource } from '@rrweb/types';
|
||||
import type { eventWithTime } from '@rrweb/types';
|
||||
|
||||
const now = Date.now();
|
||||
const events: eventWithTime[] = [
|
||||
{
|
||||
type: EventType.DomContentLoaded,
|
||||
data: {},
|
||||
timestamp: now,
|
||||
},
|
||||
{
|
||||
type: EventType.Load,
|
||||
data: {},
|
||||
timestamp: now + 100,
|
||||
},
|
||||
{
|
||||
type: EventType.Meta,
|
||||
data: {
|
||||
href: 'http://localhost',
|
||||
width: 1000,
|
||||
height: 800,
|
||||
},
|
||||
timestamp: now + 100,
|
||||
},
|
||||
// full snapshot:
|
||||
{
|
||||
data: {
|
||||
node: {
|
||||
id: 1,
|
||||
type: 0,
|
||||
childNodes: [
|
||||
{ id: 2, name: 'html', type: 1, publicId: '', systemId: '' },
|
||||
{
|
||||
id: 3,
|
||||
type: 2,
|
||||
tagName: 'html',
|
||||
attributes: { lang: 'en' },
|
||||
childNodes: [
|
||||
{
|
||||
id: 4,
|
||||
type: 2,
|
||||
tagName: 'head',
|
||||
attributes: {},
|
||||
childNodes: [],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 2,
|
||||
tagName: 'body',
|
||||
attributes: {},
|
||||
childNodes: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
initialOffset: { top: 0, left: 0 },
|
||||
},
|
||||
type: EventType.FullSnapshot,
|
||||
timestamp: now + 100,
|
||||
},
|
||||
// mutation that adds select elements
|
||||
{
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Mutation,
|
||||
texts: [],
|
||||
attributes: [],
|
||||
removes: [],
|
||||
adds: [
|
||||
{
|
||||
parentId: 5,
|
||||
nextId: null,
|
||||
node: {
|
||||
type: 2,
|
||||
tagName: 'select',
|
||||
childNodes: [],
|
||||
attributes: {},
|
||||
id: 26,
|
||||
},
|
||||
},
|
||||
{
|
||||
parentId: 26,
|
||||
nextId: null,
|
||||
node: {
|
||||
type: 2,
|
||||
tagName: 'option',
|
||||
attributes: { value: 'valueC' },
|
||||
childNodes: [],
|
||||
id: 27,
|
||||
},
|
||||
},
|
||||
{
|
||||
parentId: 27,
|
||||
nextId: null,
|
||||
node: { type: 3, textContent: 'C', id: 28 },
|
||||
},
|
||||
{
|
||||
parentId: 26,
|
||||
nextId: 27,
|
||||
node: {
|
||||
type: 2,
|
||||
tagName: 'option',
|
||||
attributes: { value: 'valueB', selected: true },
|
||||
childNodes: [],
|
||||
id: 29,
|
||||
},
|
||||
},
|
||||
{
|
||||
parentId: 26,
|
||||
nextId: 29,
|
||||
node: {
|
||||
type: 2,
|
||||
tagName: 'option',
|
||||
attributes: { value: 'valueA' },
|
||||
childNodes: [],
|
||||
id: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
parentId: 30,
|
||||
nextId: null,
|
||||
node: { type: 3, textContent: 'A', id: 31 },
|
||||
},
|
||||
{
|
||||
parentId: 29,
|
||||
nextId: null,
|
||||
node: { type: 3, textContent: 'B', id: 32 },
|
||||
},
|
||||
],
|
||||
},
|
||||
timestamp: now + 200,
|
||||
},
|
||||
// input event
|
||||
{
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Input,
|
||||
text: 'valueA',
|
||||
isChecked: false,
|
||||
id: 26,
|
||||
},
|
||||
timestamp: now + 300,
|
||||
},
|
||||
];
|
||||
|
||||
export default events;
|
||||
3
packages/rrvideo/test/tsconfig.json
Normal file
3
packages/rrvideo/test/tsconfig.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"compilerOptions": {}
|
||||
}
|
||||
Reference in New Issue
Block a user