From c24e0c6a2fb64729371f744aefc90db2348a2668 Mon Sep 17 00:00:00 2001 From: Yanzhen Yu Date: Fri, 5 Oct 2018 22:26:18 +0800 Subject: [PATCH] refactor the test infra: use puppeteer instead of jsdom to get rid of some hack implementations --- index.d.ts | 6 +- package.json | 11 ++- rollup.config.js | 10 +++ test/html/with-script.html | 4 +- test/html/with-style-sheet.html | 16 ++++ test/integration.ts | 147 ++++++++++++++++++-------------- test/js/a.js | 1 + test/server.ts | 0 tsconfig.json | 2 +- 9 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 rollup.config.js create mode 100644 test/html/with-style-sheet.html create mode 100644 test/js/a.js create mode 100644 test/server.ts diff --git a/index.d.ts b/index.d.ts index f7f2dbfa..cbe3deb6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,4 @@ -declare module 'mocha-jsdom' { - function mochaDom(options: any): void; - export = mochaDom; +declare module 'rollup-plugin-typescript' { + function typescript(): any; + export = typescript; } diff --git a/package.json b/package.json index 2c62a4c9..5944a8df 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "main": "index.js", "scripts": { - "test": "TS_NODE_FILES=true mocha -r ts-node/register test/**/*.ts" + "test": "TS_NODE_FILES=true mocha -r ts-node/register test/**/*.ts", + "compile": "rollup --config" }, "repository": { "type": "git", @@ -23,14 +24,16 @@ "homepage": "https://github.com/rrweb-io/rrweb-snapshot#readme", "devDependencies": { "@types/chai": "^4.1.4", - "@types/jsdom": "^11.12.0", "@types/mocha": "^5.2.5", "@types/node": "^10.11.3", + "@types/puppeteer": "^1.8.0", "chai": "^4.1.2", - "jsdom": "^12.1.0", "mocha": "^5.2.0", - "mocha-jsdom": "^2.0.0", + "puppeteer": "^1.9.0", + "rollup": "^0.66.4", + "rollup-plugin-typescript": "^1.0.0", "ts-node": "^7.0.1", + "tslib": "^1.9.3", "tslint": "^4.5.1", "typescript": "^3.0.3" } diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..d5080466 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,10 @@ +import typescript from 'rollup-plugin-typescript'; + +export default { + input: './src/index.ts', + plugins: [typescript()], + output: { + name: 'rrweb', + format: 'iife', + }, +}; diff --git a/test/html/with-script.html b/test/html/with-script.html index 3dd8ca93..5ef140a7 100644 --- a/test/html/with-script.html +++ b/test/html/with-script.html @@ -9,7 +9,7 @@ - + @@ -30,7 +30,7 @@ - + diff --git a/test/html/with-style-sheet.html b/test/html/with-style-sheet.html new file mode 100644 index 00000000..43e0cb01 --- /dev/null +++ b/test/html/with-style-sheet.html @@ -0,0 +1,16 @@ + + + + + + + + with style sheet + + + + + + + + \ No newline at end of file diff --git a/test/integration.ts b/test/integration.ts index 4f9917c8..cdd4139f 100644 --- a/test/integration.ts +++ b/test/integration.ts @@ -1,10 +1,12 @@ -import 'mocha'; -import mochaDom = require('mocha-jsdom'); -import { expect } from 'chai'; import * as fs from 'fs'; import * as path from 'path'; -import { JSDOM } from 'jsdom'; -import { snapshot, rebuild } from '../src'; +import * as http from 'http'; +import * as url from 'url'; +import 'mocha'; +import * as puppeteer from 'puppeteer'; +import * as rollup from 'rollup'; +import typescript = require('rollup-plugin-typescript'); +import { expect } from 'chai'; const htmlFolder = path.join(__dirname, 'html'); const htmls = fs.readdirSync(htmlFolder).map(filePath => { @@ -24,65 +26,86 @@ const htmls = fs.readdirSync(htmlFolder).map(filePath => { }; }); -describe('integration tests', () => { - mochaDom({ url: 'http://localhost' }); +interface IMimeType { + [key: string]: string; +} - for (const html of htmls) { - it('[html file]: ' + html.filePath, done => { - const srcDom = new JSDOM(html.src, { runScripts: 'dangerously' }); - const destDom = new JSDOM(html.dest); - srcDom.window.document.addEventListener('DOMContentLoaded', () => { - const snap = snapshot(srcDom.window.document); - const rebuildDom = rebuild(snap); - const htmlStr = destDom.window.document.documentElement.outerHTML.replace( - /\n\n/g, - '', - ); - const rebuildStr = (rebuildDom as Document).documentElement.outerHTML.replace( - /\n\n/g, - '', - ); - try { - expect(rebuildStr).to.equal(htmlStr); - done(); - } catch (error) { - done(error); - } - }); +const server = () => + new Promise(resolve => { + const mimeType: IMimeType = { + '.html': 'text/html', + '.js': 'text/javascript', + '.css': 'text/css', + }; + const s = http.createServer((req, res) => { + const parsedUrl = url.parse(req.url); + const sanitizePath = path + .normalize(parsedUrl.pathname) + .replace(/^(\.\.[\/\\])+/, ''); + let pathname = path.join(__dirname, sanitizePath); + try { + const data = fs.readFileSync(pathname); + const ext = path.parse(pathname).ext; + res.setHeader('Content-type', mimeType[ext] || 'text/plain'); + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'GET'); + res.setHeader('Access-Control-Allow-Headers', 'Content-type'); + res.end(data); + } catch (error) { + res.end(); + } }); - } - - it('will snapshot document type', () => { - const raw = ''; - const dom = new JSDOM(raw); - const snap = snapshot(dom.window.document); - expect(snap).to.deep.equal({ - type: 0, - childNodes: [ - { - type: 2, - tagName: 'html', - attributes: {}, - childNodes: [ - { - type: 2, - tagName: 'head', - attributes: {}, - childNodes: [], - id: 3, - }, - { - type: 2, - tagName: 'body', - attributes: {}, - childNodes: [], - id: 4, - }, - ], - id: 2, - }, - ], - id: 1, + s.listen(3030).on('listening', () => { + resolve(s); }); }); + +describe('integration tests', () => { + before(async () => { + this.server = await server(); + this.browser = await puppeteer.launch({ + headless: false, + executablePath: '/home/yanzhen/Desktop/chrome-linux/chrome', + }); + + const bundle = await rollup.rollup({ + input: path.resolve(__dirname, '../src/index.ts'), + plugins: [typescript()], + }); + const { code } = await bundle.generate({ + name: 'rrweb', + format: 'iife', + }); + this.code = code; + }); + + after(() => { + this.browser.close(); + this.server.close(); + }); + + for (const html of htmls) { + it('[html file]: ' + html.filePath, async () => { + const page: puppeteer.Page = await this.browser.newPage(); + await page.goto(`http://localhost:3030/html/${html.filePath}`); + await page.setContent(html.src); + page.once('load', async () => { + await page.evaluate(() => { + const x = new XMLSerializer(); + return x.serializeToString(document); + }); + const rebuildHtml = (await page.evaluate(`${this.code} + const x = new XMLSerializer(); + const snap = rrweb.snapshot(document); + x.serializeToString(rrweb.rebuild(snap)); + `)).replace(/\n\n/g, ''); + await page.goto(`data:text/html,${html.dest}`); + const destHtml = (await page.evaluate(() => { + const x = new XMLSerializer(); + return x.serializeToString(document); + })).replace(/\n\n/g, ''); + expect(rebuildHtml).to.equal(destHtml); + }); + }).timeout(5000); + } }); diff --git a/test/js/a.js b/test/js/a.js new file mode 100644 index 00000000..7a776f91 --- /dev/null +++ b/test/js/a.js @@ -0,0 +1 @@ +var a = 1 + 1; diff --git a/test/server.ts b/test/server.ts new file mode 100644 index 00000000..e69de29b diff --git a/tsconfig.json b/tsconfig.json index 06b323aa..6378ca69 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,5 @@ }, "compileOnSave": true, "exclude": ["test"], - "include": ["index.d.ts"] + "include": ["src", "index.d.ts"] }