diff --git a/package.json b/package.json index e585a91b..0a46068c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "record and replay the web", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "test": "TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.ts", "bundle": "rollup --config" }, "repository": { @@ -21,9 +21,18 @@ }, "homepage": "https://github.com/rrweb-io/rrweb#readme", "devDependencies": { + "@types/chai": "^4.1.6", + "@types/mocha": "^5.2.5", + "@types/node": "^10.11.7", + "@types/puppeteer": "^1.9.0", + "chai": "^4.2.0", + "jest-snapshot": "^23.6.0", + "mocha": "^5.2.0", + "puppeteer": "^1.9.0", "rollup": "^0.66.6", "rollup-plugin-node-resolve": "^3.4.0", "rollup-plugin-typescript": "^1.0.0", + "ts-node": "^7.0.1", "tslib": "^1.9.3", "tslint": "^4.5.1", "typescript": "^3.1.1" diff --git a/test.d.ts b/test.d.ts new file mode 100644 index 00000000..50b01f40 --- /dev/null +++ b/test.d.ts @@ -0,0 +1,26 @@ +declare module 'rollup-plugin-typescript' { + function typescript(): any; + export = typescript; +} + +declare module 'rollup-plugin-node-resolve' { + function resolve(): any; + export = resolve; +} + +declare module 'jest-snapshot' { + export class SnapshotState { + constructor(testFile: string, options: any); + + save(): any; + } + type matchResult = { + pass: boolean; + report(): string; + }; + export function toMatchSnapshot( + received: any, + propertyMatchers?: any, + testName?: string, + ): matchResult; +} diff --git a/test/__snapshots__/integration.ts.snap b/test/__snapshots__/integration.ts.snap new file mode 100644 index 00000000..90287004 --- /dev/null +++ b/test/__snapshots__/integration.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`form 1`] = `"[{\\"type\\":0,\\"data\\":{\\"href\\":\\"about:blank\\"},\\"timestamp\\":1542268800000},{\\"type\\":1,\\"data\\":{\\"width\\":800,\\"height\\":600},\\"timestamp\\":1542268800000},{\\"type\\":2,\\"data\\":{\\"node\\":{\\"type\\":0,\\"childNodes\\":[{\\"type\\":1,\\"name\\":\\"html\\",\\"publicId\\":\\"\\",\\"systemId\\":\\"\\",\\"id\\":2},{\\"type\\":2,\\"tagName\\":\\"html\\",\\"attributes\\":{\\"lang\\":\\"en\\"},\\"childNodes\\":[{\\"type\\":2,\\"tagName\\":\\"head\\",\\"attributes\\":{},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":5},{\\"type\\":2,\\"tagName\\":\\"meta\\",\\"attributes\\":{\\"charset\\":\\"UTF-8\\"},\\"childNodes\\":[],\\"id\\":6},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":7},{\\"type\\":2,\\"tagName\\":\\"meta\\",\\"attributes\\":{\\"name\\":\\"viewport\\",\\"content\\":\\"width=device-width, initial-scale=1.0\\"},\\"childNodes\\":[],\\"id\\":8},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":9},{\\"type\\":2,\\"tagName\\":\\"meta\\",\\"attributes\\":{\\"http-equiv\\":\\"X-UA-Compatible\\",\\"content\\":\\"ie=edge\\"},\\"childNodes\\":[],\\"id\\":10},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":11},{\\"type\\":2,\\"tagName\\":\\"title\\",\\"attributes\\":{},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"form fields\\",\\"id\\":13}],\\"id\\":12},{\\"type\\":3,\\"textContent\\":\\"\\\\n\\",\\"id\\":14}],\\"id\\":4},{\\"type\\":3,\\"textContent\\":\\"\\\\n\\\\n\\",\\"id\\":15},{\\"type\\":2,\\"tagName\\":\\"body\\",\\"attributes\\":{},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":17},{\\"type\\":2,\\"tagName\\":\\"form\\",\\"attributes\\":{},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":19},{\\"type\\":2,\\"tagName\\":\\"label\\",\\"attributes\\":{\\"for\\":\\"text\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":21},{\\"type\\":2,\\"tagName\\":\\"input\\",\\"attributes\\":{\\"type\\":\\"text\\"},\\"childNodes\\":[],\\"id\\":22},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":23}],\\"id\\":20},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":24},{\\"type\\":2,\\"tagName\\":\\"label\\",\\"attributes\\":{\\"for\\":\\"radio\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":26},{\\"type\\":2,\\"tagName\\":\\"input\\",\\"attributes\\":{\\"type\\":\\"radio\\"},\\"childNodes\\":[],\\"id\\":27},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":28}],\\"id\\":25},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":29},{\\"type\\":2,\\"tagName\\":\\"label\\",\\"attributes\\":{\\"for\\":\\"checkbox\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":31},{\\"type\\":2,\\"tagName\\":\\"input\\",\\"attributes\\":{\\"type\\":\\"checkbox\\"},\\"childNodes\\":[],\\"id\\":32},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":33}],\\"id\\":30},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":34},{\\"type\\":2,\\"tagName\\":\\"label\\",\\"attributes\\":{\\"for\\":\\"textarea\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":36},{\\"type\\":2,\\"tagName\\":\\"textarea\\",\\"attributes\\":{\\"name\\":\\"\\",\\"id\\":\\"\\",\\"cols\\":\\"30\\",\\"rows\\":\\"10\\"},\\"childNodes\\":[],\\"id\\":37},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":38}],\\"id\\":35},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":39},{\\"type\\":2,\\"tagName\\":\\"label\\",\\"attributes\\":{\\"for\\":\\"select\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":41},{\\"type\\":2,\\"tagName\\":\\"select\\",\\"attributes\\":{\\"name\\":\\"\\",\\"id\\":\\"\\",\\"value\\":\\"1\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":43},{\\"type\\":2,\\"tagName\\":\\"option\\",\\"attributes\\":{\\"value\\":\\"1\\",\\"selected\\":true},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"1\\",\\"id\\":45}],\\"id\\":44},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":46},{\\"type\\":2,\\"tagName\\":\\"option\\",\\"attributes\\":{\\"value\\":\\"2\\"},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"2\\",\\"id\\":48}],\\"id\\":47},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":49}],\\"id\\":42},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":50}],\\"id\\":40},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\",\\"id\\":51}],\\"id\\":18},{\\"type\\":3,\\"textContent\\":\\"\\\\n\\\\n \\",\\"id\\":52},{\\"type\\":2,\\"tagName\\":\\"script\\",\\"attributes\\":{},\\"childNodes\\":[{\\"type\\":3,\\"textContent\\":\\"\\",\\"id\\":54}],\\"id\\":53},{\\"type\\":3,\\"textContent\\":\\"\\\\n \\\\n \\\\n\\\\n\\\\n\\",\\"id\\":55}],\\"id\\":16}],\\"id\\":3}],\\"id\\":1}},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":5,\\"id\\":22},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"t\\",\\"isChecked\\":false,\\"id\\":22},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"te\\",\\"isChecked\\":false,\\"id\\":22},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"tes\\",\\"isChecked\\":false,\\"id\\":22},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"test\\",\\"isChecked\\":false,\\"id\\":22},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":1,\\"positions\\":[{\\"x\\":204,\\"y\\":117,\\"timeOffset\\":0}]},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":1,\\"id\\":27,\\"x\\":204,\\"y\\":117},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":6,\\"id\\":22},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":5,\\"id\\":27},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":0,\\"id\\":27,\\"x\\":204,\\"y\\":117},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":2,\\"id\\":27,\\"x\\":204,\\"y\\":117},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"on\\",\\"isChecked\\":true,\\"id\\":27},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":1,\\"id\\":32,\\"x\\":228,\\"y\\":117},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":6,\\"id\\":27},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":5,\\"id\\":32},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":0,\\"id\\":32,\\"x\\":228,\\"y\\":117},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":2,\\"id\\":32,\\"x\\":228,\\"y\\":117},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"on\\",\\"isChecked\\":true,\\"id\\":32},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":6,\\"id\\":32},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":2,\\"type\\":5,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"t\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"te\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"tex\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"text\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"texta\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textar\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textare\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textarea\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textarea \\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textarea t\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textarea te\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textarea tes\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"textarea test\\",\\"isChecked\\":false,\\"id\\":37},\\"timestamp\\":1542268800000},{\\"type\\":3,\\"data\\":{\\"source\\":5,\\"text\\":\\"1\\",\\"isChecked\\":false,\\"id\\":42},\\"timestamp\\":1542268800000}]"`; diff --git a/test/html/form.html b/test/html/form.html new file mode 100644 index 00000000..14120fd3 --- /dev/null +++ b/test/html/form.html @@ -0,0 +1,34 @@ + + + + + + + + form fields + + + +
+ + + + + +
+ + + diff --git a/test/integration.ts b/test/integration.ts new file mode 100644 index 00000000..ed799b39 --- /dev/null +++ b/test/integration.ts @@ -0,0 +1,83 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as puppeteer from 'puppeteer'; +import { assert } from 'chai'; +import * as rollup from 'rollup'; +import typescript = require('rollup-plugin-typescript'); +import resolve = require('rollup-plugin-node-resolve'); +import { SnapshotState, toMatchSnapshot } from 'jest-snapshot'; + +function matchSnapshot(actual: string, testFile: string, testTitle: string) { + const snapshotState = new SnapshotState(testFile, { + updateSnapshot: process.env.SNAPSHOT_UPDATE ? 'all' : 'new', + }); + + const matcher = toMatchSnapshot.bind({ + snapshotState, + currentTestName: testTitle, + }); + const result = matcher(actual); + snapshotState.save(); + return result; +} + +describe('record integration tests', () => { + function getHtml(fileName: string): string { + const filePath = path.resolve(__dirname, `./html/${fileName}`); + const html = fs.readFileSync(filePath, 'utf8'); + return html.replace( + '', + ` + + + `, + ); + } + + before(async () => { + this.browser = await puppeteer.launch({ + // headless: false, + executablePath: '/home/yanzhen/Desktop/chrome-linux/chrome', + }); + + const bundle = await rollup.rollup({ + input: path.resolve(__dirname, '../src/record/index.ts'), + plugins: [typescript(), resolve()], + }); + const { code } = await bundle.generate({ + name: 'record', + format: 'iife', + }); + this.code = code; + }); + + after(async () => { + await this.browser.close(); + }); + + it('can record form interactions', async () => { + const page: puppeteer.Page = await this.browser.newPage(); + await page.goto('about:blank'); + await page.setContent(getHtml.call(this, 'form.html')); + + await page.type('input[type="text"]', 'test'); + await page.click('input[type="radio"]'); + await page.click('input[type="checkbox"]'); + await page.type('textarea', 'textarea test'); + await page.select('select', '1'); + + const snapshots = await page.evaluate('window.snapshots'); + const result = matchSnapshot(JSON.stringify(snapshots), __filename, 'form'); + assert(result.pass, result.pass ? '' : result.report()); + }).timeout(5000); +}); diff --git a/tsconfig.json b/tsconfig.json index 70ab5ce2..0fd4e84f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,5 +12,5 @@ }, "compileOnSave": true, "exclude": ["test"], - "include": ["src", "index.d.ts"] + "include": ["src", "index.d.ts", "test.d.ts"] }