bem / html-differ

Сompares two HTML
http://bem.info/tools/testing/html-differ/
MIT License
212 stars 45 forks source link

html-differ Build Status Coverage Status Dependency Status devDependency Status

Compares two HTML.

The comparison algorithm

html-differ compares HTML using the following criteria:

<!DOCTYPE HTML PUBLIC "_PUBLIC" "_SYSTEM">
<!doctype html public "_PUBLIC" "_SYSTEM">

For example, the following two code samples will be considered to be equivalent:

<span id="1"></span>
<span id=
    "1"    ></span   >

For example, the following two code samples will be considered to be equivalent:

<span id="blah" class="ololo" tabIndex="1">Text</span>
<span tabIndex="1" id="blah" class="ololo">Text</span>

For example, the following two code samples will be considered to be equivalent:

<span class="ab bc cd">Text</span>
<span class=" cd  ab bc bc">Text</span>

CAUTION!
html-differ does not check the validity of HTML, but compares them using the above shown criteria and specified options (see the list of possible options).

Install

$ npm install html-differ

API

HtmlDiffer

var HtmlDiffer = require('html-differ').HtmlDiffer,
    htmlDiffer = new HtmlDiffer(options);

where options is an object.

Options

ignoreAttributes: [Array]

Sets what kind of respective attributes' content will be ignored during the comparison (default: []).

Example: ['id', 'for']
The following two code samples will be considered to be equivalent:

<label for="random">Text</label>
<input id="random">
<label for="sfsdfksdf">Text</label>
<input id="sfsdfksdf">
compareAttributesAsJSON: [Array]

Sets what kind of respective attributes' content will be compared as JSON objects, but not as strings (default: []).
In cases when the value of the attribute is an invalid JSON or can not be wrapped into a function, it will be compared as undefined.

Example: [{ name: 'data', isFunction: false }, { name: 'onclick', isFunction: true }]
The following two code samples will be considered to be equivalent:

<div data='{"bla":{"first":"ololo","second":"trololo"}}'></div>
<span onclick='return {"aaa":"bbb","bbb":"aaa"}'></span>

<button data='REALLY BAD JSON'></button>
<button onclick='REALLY BAD FUNCTION'></button>
<div data='{"bla":{"second":"trololo","first":"ololo"}}'></div>
<span onclick='return {"bbb":"aaa","aaa":"bbb"}'></span>

<button data='undefined'></button>
<button onclick='undefined'></button>

REMARK!
The first element of the array could be written in a short form as string:
['data', { name: 'onclick', isFunction: true }].

ignoreWhitespaces: Boolean

Makes html-differ ignore whitespaces (spaces, tabs, new lines etc.) during the comparison (default: true).

Example: true
The following two code samples will be considered to be equivalent:

<html>Text Text<head lang="en"><title></title></head><body>Text</body></html>
 <html>
 Text   Text
<head lang="en">
    <title>               </title>

            </head>

<body>
     Text

    </body>

</html>
ignoreComments: Boolean

Makes html-differ ignore HTML comments during the comparison (default: true).

REMARK!
Does not ignore conditional comments.

Example: true
The following two code samples will be considered to be equivalent:

<!DOCTYPE html>
<!-- comments1 -->
<html>
<head lang="en">
    <meta charset="UTF-8">
    <!--[if IE]>
        <link rel="stylesheet" type="text/css" href="https://github.com/bem/html-differ/blob/master/all-ie-only.css" />
    <![endif]-->
    <!--[if !IE]><!-->
        <link href="https://github.com/bem/html-differ/blob/master/non-ie.css" rel="stylesheet">
    <!--<![endif]-->
</head>
<body>
Text<!-- comments2 -->
</body>
</html>
<!DOCTYPE html>

<html>
<head lang="en">
    <meta charset="UTF-8">
    <!--[if IE]>
        <link href="https://github.com/bem/html-differ/blob/master/all-ie-only.css" type="text/css" rel="stylesheet"/>
    <![endif]-->
    <!--[if !IE]><!-->
        <link href="https://github.com/bem/html-differ/blob/master/non-ie.css" rel="stylesheet">
    <!--<![endif]-->
</head>
<body>
Text
</body>
</html>
ignoreEndTags: Boolean

Makes html-differ ignore end tags during the comparison (default: false).

Example: true
The following two code samples will be considered to be equivalent:

<span>Text</span>
<span>Text</spane>
ignoreDuplicateAttributes: Boolean

Makes html-differ ignore tags' duplicate attributes during the comparison.
From the list of the same tag's attributes, the attribute which goes the first will be taken for comparison, others will be ignored (default: false).

Example: true
For example, the following two code samples will be considered to be equivalent:

<span id="blah" id="ololo">Text</span>
<span id="blah">Text</span>

Presets

Usage

Passing of a preset via the constructor:

var HtmlDiffer = require('html-differ').HtmlDiffer,
    htmlDiffer = new HtmlDiffer('bem');

Redefinition of a preset via the constructor:

var HtmlDiffer = require('html-differ').HtmlDiffer,
    htmlDiffer = new HtmlDiffer({ preset: 'bem', ignoreAttributes: [] });

Methods

htmlDiffer.diffHtml

@param {String} - the 1-st HTML code
@param {String} - the 2-nd HTML code
@returns {Array of objects} - array with diffs between HTML

htmlDiffer.isEqual

@param {String} - the 1-st HTML code
@param {String} - the 2-nd HTML code
@returns {Boolean}

Logger

var logger = require('html-differ/lib/logger');

Methods

logger.getDiffText

@param {Array of objects} - the result of the work of the method htmlDiffer.diffHtml
@param {Object} - options:

@returns {String}

logger.logDiffText

@param {Array of objects} - the result of the work of the method htmlDiffer.diffHtml
@param {Object} - options:

@returns - pretty logging of diffs:

Example

var fs = require('fs'),
    HtmlDiffer = require('html-differ').HtmlDiffer,
    logger = require('html-differ/lib/logger');

var html1 = fs.readFileSync('1.html', 'utf-8'),
    html2 = fs.readFileSync('2.html', 'utf-8');

var options = {
        ignoreAttributes: [],
        compareAttributesAsJSON: [],
        ignoreWhitespaces: true,
        ignoreComments: true,
        ignoreEndTags: false,
        ignoreDuplicateAttributes: false
    };

var htmlDiffer = new HtmlDiffer(options);

var diff = htmlDiffer.diffHtml(html1, html2),
    isEqual = htmlDiffer.isEqual(html1, html2),
    res = logger.getDiffText(diff, { charsAroundDiff: 40 });

logger.logDiffText(diff, { charsAroundDiff: 40 });

Usage as a program

$ html-differ --help
Compares two HTML

Usage:
  html-differ [OPTIONS] [ARGS]

Options:
  -h, --help : Help
  -v, --version : Shows the version number
  --config=CONFIG : Path to a configuration JSON file
  --bem : Uses predefined options for BEM (deprecated)
  -p PRESET, --preset=PRESET : Name of a preset
  --chars-around-diff=CHARSAROUNDDIFF : The number of characters around the diff (default: 40)

Arguments:
  PATH1 : Path to the 1-st HTML file (required)
  PATH2 : Path to the 2-nd HTML file (required)

Example

$ html-differ path/to/html1 path/to/html2

$ html-differ --config=path/to/config --chars-around-diff=40 path/to/html1 path/to/html2

$ html-differ --preset=bem path/to/html1 path/to/html2

Configuration file

Study the following file config.json:

{
    "ignoreAttributes": [],
    "compareAttributesAsJSON": [],
    "ignoreWhitespaces": true,
    "ignoreComments": true,
    "ignoreEndTags": false,
    "ignoreDuplicateAttributes": false
}

Masks

html-differ supports handling of masks in HTML.

For example, the following two code samples will be considered to be equivalent:

<div id="{{[a-z]*\s\d+}}">
<div id="text 12345">

Syntax

Masks in html-differ have the following syntax:

{{RegExp}}

where:

Screening

The rules of screening of symbols are similar to the rules which are used in regular expressions in JavaScript written in a literal notation.

For example, the following two code samples will be considered to be equivalent:

<div id="{{\d\.\d}}">
<div id="1.1">

If you want to use {{ or }} inside a mask, you should screen both curly braces, i.e. \{\} or \}\}.

For example, the following two code samples will be considered to be equivalent:

<div class="{{a\{\{b\}\}c}}">
<div class="a{{b}}c">