diff --git a/.prettierrc b/.prettierrc index 1502887d..a20502b7 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,4 @@ { "singleQuote": true, - "trailingComma": "es5" -} \ No newline at end of file + "trailingComma": "all" +} diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 00000000..f7f2dbfa --- /dev/null +++ b/index.d.ts @@ -0,0 +1,4 @@ +declare module 'mocha-jsdom' { + function mochaDom(options: any): void; + export = mochaDom; +} diff --git a/package.json b/package.json index c8c0d7d1..2c62a4c9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "main": "index.js", "scripts": { - "test": "mocha -r ts-node/register src/**/*.test.ts" + "test": "TS_NODE_FILES=true mocha -r ts-node/register test/**/*.ts" }, "repository": { "type": "git", @@ -23,9 +23,13 @@ "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", "chai": "^4.1.2", + "jsdom": "^12.1.0", "mocha": "^5.2.0", + "mocha-jsdom": "^2.0.0", "ts-node": "^7.0.1", "tslint": "^4.5.1", "typescript": "^3.0.3" diff --git a/src/rebuild.ts b/src/rebuild.ts index 1d581e45..3dee6026 100644 --- a/src/rebuild.ts +++ b/src/rebuild.ts @@ -14,7 +14,11 @@ function buildNode(n: serializedNodeWithId): Node | null { const node = document.createElement(n.tagName); for (const name in n.attributes) { if (n.attributes.hasOwnProperty(name)) { - node.setAttribute(name, n.attributes[name]); + try { + node.setAttribute(name, n.attributes[name]); + } catch (error) { + // skip invalid attribute + } } } return node; diff --git a/test/html/about-mozilla.html b/test/html/about-mozilla.html new file mode 100644 index 00000000..f353c482 --- /dev/null +++ b/test/html/about-mozilla.html @@ -0,0 +1,57 @@ + + + + + The Book of Mozilla, 11:9 + + + + + +

+ Mammon slept. And the beast reborn spread over the earth and its numbers + grew legion. And they proclaimed the times and sacrificed crops unto the + fire, with the cunning of foxes. And they built a new world in their own + image as promised by the + sacred words, and spoke + of the beast with their children. Mammon awoke, and lo! it was + naught but a follower. +

+ +

+ from The Book of Mozilla, 11:9
(10th Edition) +

+ + + + \ No newline at end of file diff --git a/test/html/basic.html b/test/html/basic.html new file mode 100644 index 00000000..95fac2be --- /dev/null +++ b/test/html/basic.html @@ -0,0 +1,15 @@ + + + + + + + + Document + + + + + + + \ No newline at end of file diff --git a/test/index.ts b/test/index.ts new file mode 100644 index 00000000..a9fba369 --- /dev/null +++ b/test/index.ts @@ -0,0 +1,70 @@ +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'; + +const htmlFolder = path.join(__dirname, 'html'); +const htmls = fs.readdirSync(htmlFolder).map(filePath => { + return { + filePath, + content: fs.readFileSync(path.resolve(htmlFolder, filePath), 'utf-8'), + }; +}); + +describe('integration tests', () => { + mochaDom({ url: 'http://localhost' }); + + 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, + }); + }); + + it('will not throw error with invalid attribute', () => { + const raw = ``; + const dom = new JSDOM(raw); + expect(() => rebuild(snapshot(dom.window.document))).not.to.throw(); + }); + + for (const html of htmls) { + it('[html file]:' + html.filePath, () => { + const dom = new JSDOM(html.content); + const snap = snapshot(dom.window.document); + const rebuildDom = rebuild(snap); + expect((rebuildDom as Document).documentElement.outerHTML).to.equal( + dom.window.document.documentElement.outerHTML, + ); + }); + } +}); diff --git a/tsconfig.json b/tsconfig.json index ce1b7e3c..06b323aa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,5 +9,7 @@ "outDir": "build", "lib": ["es6", "dom"] }, - "compileOnSave": true + "compileOnSave": true, + "exclude": ["test"], + "include": ["index.d.ts"] } diff --git a/tslint.json b/tslint.json index 3a0c0801..a153081c 100644 --- a/tslint.json +++ b/tslint.json @@ -9,7 +9,13 @@ "object-literal-sort-keys": false, "no-unused-variable": true, "object-literal-key-quotes": false, - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"] + "variable-name": [ + true, + "ban-keywords", + "check-format", + "allow-leading-underscore" + ], + "arrow-parens": false }, "rulesDirectory": [] -} \ No newline at end of file +}