@open-wc/semantic-dom-diff
Advanced tools
Comparing version 0.9.7 to 0.10.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [0.10.0](https://github.com/open-wc/open-wc/compare/@open-wc/semantic-dom-diff@0.9.7...@open-wc/semantic-dom-diff@0.10.0) (2019-04-08) | ||
### Features | ||
* **semantic-dom-diff:** add support for snapshot testing ([f7a675a](https://github.com/open-wc/open-wc/commit/f7a675a)) | ||
## [0.9.7](https://github.com/open-wc/open-wc/compare/@open-wc/semantic-dom-diff@0.9.6...@open-wc/semantic-dom-diff@0.9.7) (2019-04-06) | ||
@@ -8,0 +19,0 @@ |
@@ -1,2 +0,2 @@ | ||
const DEFAULT_IGNORE_CHILDREN = ['script', 'style', 'svg']; | ||
const DEFAULT_IGNORE_TAGS = ['script', 'style', 'svg']; | ||
const VOID_ELEMENTS = [ | ||
@@ -55,3 +55,3 @@ 'area', | ||
* | ||
* @param {string} html | ||
* @param {Node | string} html | ||
* @param {DiffOptions} [options] | ||
@@ -67,4 +67,4 @@ * @returns {string} html restructured in a diffable format | ||
: []); | ||
const ignoreTags = options.ignoreTags || []; | ||
const ignoreChildren = [...(options.ignoreChildren || []), ...DEFAULT_IGNORE_CHILDREN]; | ||
const ignoreTags = [...(options.ignoreTags || []), ...DEFAULT_IGNORE_TAGS]; | ||
const ignoreChildren = options.ignoreChildren || []; | ||
@@ -204,5 +204,15 @@ let text = ''; | ||
const container = document.createElement('diff-container'); | ||
container.innerHTML = html; | ||
let container; | ||
if (typeof html === 'string') { | ||
container = document.createElement('diff-container'); | ||
container.innerHTML = html; | ||
depth = -1; | ||
} else if (html instanceof Node) { | ||
container = html; | ||
depth = 0; | ||
} else { | ||
throw new Error(`Cannot create diffable HTML from: ${html}`); | ||
} | ||
const walker = document.createTreeWalker( | ||
@@ -209,0 +219,0 @@ container, |
@@ -8,1 +8,3 @@ import { getDiffableHTML } from './get-diffable-html.js'; | ||
}; | ||
export { chaiDomDiff } from './chai-dom-diff'; |
{ | ||
"name": "@open-wc/semantic-dom-diff", | ||
"version": "0.9.7", | ||
"version": "0.10.0", | ||
"description": "To compare dom and shadow dom trees. Part of open-wc recommendations", | ||
@@ -24,2 +24,4 @@ "author": "open-wc", | ||
"test:watch": "karma start --auto-watch=true --single-run=false", | ||
"test:update-snapshots": "karma start --update-snapshots", | ||
"test:prune-snapshots": "karma start --prune-snapshots", | ||
"test:legacy": "karma start --legacy --coverage", | ||
@@ -32,4 +34,5 @@ "test:legacy:watch": "karma start --legacy --auto-watch=true --single-run=false", | ||
"@bundled-es-modules/chai": "^4.2.0", | ||
"@open-wc/testing-karma": "^1.0.2", | ||
"@open-wc/testing-karma-bs": "^1.0.2", | ||
"@open-wc/testing-helpers": "^0.8.6", | ||
"@open-wc/testing-karma": "^1.1.0", | ||
"@open-wc/testing-karma-bs": "^1.0.3", | ||
"@open-wc/testing-wallaby": "^0.1.12", | ||
@@ -39,3 +42,3 @@ "mocha": "^5.0.0", | ||
}, | ||
"gitHead": "5b8ec8d320bb2a171c323702204ce0a47d42fb54" | ||
"gitHead": "87937f313855458c9cb34d72e68bfc4817fd0d93" | ||
} |
290
README.md
@@ -15,3 +15,3 @@ # Semantic Dom Diff | ||
``` | ||
`semantic-dom-diff` exports a function which takes a string of HTML and returns a string of HTML, restructuring it so that it can be easily compared: | ||
`semantic-dom-diff` allows diffing chunks of dom or HTML for semanticaly equality: | ||
- whitespace and newlines are normalized | ||
@@ -21,87 +21,214 @@ - tags and attributes are printed on individual lines | ||
- style, script and svg contents are removed | ||
- tags, attributes or element's light dom can be ignored through configuration | ||
Additional options can be configured. | ||
## Chai plugin | ||
While `semantic-dom-diff` can be used standalone (see below) you will most commonly use this through our chai plugin. | ||
## Basic usage | ||
<details> | ||
<summary>Registering the plugin</summary> | ||
> If you are using `@open-wc/testing` this is already done for you. | ||
```javascript | ||
import { chai } from '@bundled-es-modules/chai'; | ||
import { chaiDomDiff } from '@open-wc/semantic-dom-diff'; | ||
chai.use(chaiDomDiff); | ||
``` | ||
</details> | ||
### Setting up your dom for diffing | ||
You can set up our chai plugin to diff different types of DOM: | ||
```javascript | ||
import { getDiffableHTML } from '@open-wc/semantic-dom-diff'; | ||
class MyElement extends HTMLElement { | ||
constructor() { | ||
super(); | ||
this.attachShadow({ mode: 'open' }); | ||
} | ||
const leftTree = getDiffableHTML(` | ||
<div>foo</div> | ||
`); | ||
const rightTree = getDiffableHTML(` | ||
<div>bar</div> | ||
`); | ||
connectedCallback() { | ||
this.shadowRoot.innerHTML = '<p> shadow content </p>'; | ||
} | ||
} | ||
// use any string comparison tool, for example chai: | ||
expect(leftTree).to.equal(rightTree); | ||
customElements.define('my-element', MyElement); | ||
it('my test', async () => { | ||
const el = await fixture(` | ||
<my-element> | ||
<div> light dom content </div> | ||
</my-element> | ||
`); | ||
expect(el).dom // dom is <my-element><div>light dom content</div></my-element> | ||
expect(el).lightDom // dom is <div>light dom content</div> | ||
expect(el).shadowDom // dom is <p>shadow content</p> | ||
}); | ||
``` | ||
## Ignoring tags and attributes | ||
When working with libraries or custom elements there might be parts of the rendered HTML which is random or otherwise outside of your control. In those cases, you might want to ignore certain attributes or tags entirely. This is possible by passing an options object. | ||
### Manual diffing | ||
You can use the chai plugin to manually diff chunks of dom. The dom is diffed semantically: whitespace, newlines etc. are normalized. | ||
### Ignoring an attribute | ||
```javascript | ||
import { getDiffableHTML } from '@open-wc/semantic-dom-diff'; | ||
class MyElement extends HTMLElement { | ||
constructor() { | ||
super(); | ||
this.attachShadow({ mode: 'open' }); | ||
} | ||
const leftTree = getDiffableHTML(` | ||
<div data-my-attribute="someRandomlyGeneratedDataInAnAttribute"> | ||
foo | ||
</div> | ||
`, { ignoreAttributes: ['data-my-attribute'] }); | ||
connectedCallback() { | ||
this.shadowRoot.innerHTML = '<p> shadow content </p>'; | ||
} | ||
} | ||
const rightTree = getDiffableHTML(` | ||
<div> | ||
foo | ||
</div> | ||
`); | ||
customElements.define('my-element', MyElement); | ||
// this test will pass, the attribute is ignored | ||
expect(leftTree).to.equal(rightTree); | ||
it('my test', async () => { | ||
const el = await fixture(` | ||
<my-element> | ||
<div> light dom content </div> | ||
</my-element> | ||
`); | ||
expect(el).dom.to.equal('<my-element><div>light dom content</div></my-element>'); | ||
expect(el).lightDom.to.equal('<div>light dom content</div>'); | ||
expect(el).shadowDom.to.equal('<p>shadow content</p>'); | ||
}); | ||
``` | ||
### Ignoring an attribute only for certain tags | ||
Randomly generated ids are often used, throwing off your diffs. You can ignore attributes on specific tags: | ||
```javascript | ||
import { getDiffableHTML } from '@open-wc/semantic-dom-diff'; | ||
### Snapshot testing | ||
The most powerful feature of `semantic-dom-diff` is the ability to test and manage snapshots of your web components. | ||
const leftTree = getDiffableHTML(` | ||
<div> | ||
<input id="someRandomlyGeneratedId"> | ||
</div> | ||
`, { ignoreAttributes: [{ tags: ['input'], attributs: ['id'] }] }); | ||
> If you are not using `@open-wc/testing-karma`, you need to manually install [karma-snapshot](https://www.npmjs.com/package/karma-snapshot) and [karma-mocha-snapshot](https://www.npmjs.com/package/karma-mocha-snapshot). | ||
const rightTree = getDiffableHTML(` | ||
<div> | ||
<input> | ||
</div> | ||
`); | ||
#### Setting up a snapshot | ||
// this test will pass, the id attribute is ignored | ||
expect(leftTree).to.equal(rightTree); | ||
Snapshots are created by setting up your component in a specific state, and then calling `.to.equalSnapshot()`. You can use `.dom`, `.lightDom` or `.shadowDom` to set up the dom of your element: | ||
```js | ||
import { fixture } from '@open-wc/testing'; | ||
describe('my-message', () => { | ||
it('renders message foo correctly', () => { | ||
const element = await fixture(` | ||
<my-message message="Foo"></my-element> | ||
`); | ||
expect(element).shadowDom.to.equalSnapshot(); | ||
}); | ||
it('renders message bar correctly', () => { | ||
const element = await fixture(` | ||
<my-message message="Bar"></my-element> | ||
`); | ||
expect(element).shadowDom.to.equalSnapshot(); | ||
}); | ||
it('renders a capitalized message correctly', () => { | ||
const element = await fixture(` | ||
<my-message message="Bar" capitalized></my-element> | ||
`); | ||
expect(element).shadowDom.to.equalSnapshot(); | ||
}); | ||
it('allows rendering a message from a slot', () => { | ||
const element = await fixture(` | ||
<my-message capitalized>Bar</my-element> | ||
`); | ||
expect(element).lightDom.to.equalSnapshot(); | ||
}); | ||
}); | ||
``` | ||
### Ignoring a tag | ||
Similarly you can tell the diff to ignore certain tags entirely: | ||
Snapshots are stored in the `__snapshots__` folder in your project, using the most top level `describe` as the name for your snapshots file. | ||
#### Updating a snapshot | ||
> If you are not using the standard `@open-wc/testing-karma` configuration, see the documentation of `karma-snapshot` how to pass the update/prune flags. | ||
When your tests run for the first time the snapshot files are generated. On subsequent test runs your element is compared with the stored snapshots. If the element and the snapshots differ the test fails. | ||
If the difference was an intended change, you can update the snapshots by passing the `--update-snapshots` flag. | ||
#### Cleaning up unused snapshots | ||
After refactoring there might be leftover snapshot files which are unused. You can run karma with the `--prune-snapshots` flag to clean these up. | ||
**Ignoring tags and attributes** | ||
When working with libraries or custom elements there might be parts of the rendered dom which is random or otherwise outside of your control. In those cases, you might want to ignore certain attributes or tags entirely. This is possible by passing an options object. | ||
```javascript | ||
import { getDiffableHTML } from '@open-wc/semantic-dom-diff'; | ||
it('renders correctly', async () => { | ||
const el = await fixture(` | ||
<div my-random-attribute="${Math.random()}"> | ||
Hey | ||
</div> | ||
`); | ||
expect(el).dom.to.equal('<div>Hey</div>', { | ||
ignoreAttributes: ['my-random-attribute'] | ||
}); | ||
const leftTree = getDiffableHTML(` | ||
<div> | ||
<my-custom-element><my-custom-element> | ||
foo | ||
</div> | ||
`, { ignoreTags: ['my-custom-element'] }); | ||
expect(el).dom.to.equalSnapshot({ | ||
ignoreAttributes: ['my-random-attribute'] | ||
}); | ||
}); | ||
``` | ||
const rightTree = getDiffableHTML(` | ||
<div> | ||
foo | ||
</div> | ||
`); | ||
**Ignoring an attribute only for certain tags** | ||
// this test will pass, the tag is ignored completely | ||
expect(leftTree).to.equal(rightTree); | ||
Randomly generated ids are often used, throwing off your diffs. You can ignore attributes on specific tags: | ||
```javascript | ||
it('renders correctly', async () => { | ||
const el = await fixture(` | ||
<input id="customInput${Math.random()}"> | ||
`); | ||
// ignore id attributes on input elements | ||
expect(el).dom.to.equal('<div>Hey</div>', { | ||
ignoreAttributes: [ | ||
{ tags: ['input'], attributs: ['id'] } | ||
] | ||
}); | ||
expect(el).dom.to.equalSnapshot({ | ||
ignoreAttributes: [ | ||
{ tags: ['input'], attributs: ['id'] } | ||
] | ||
}); | ||
}); | ||
``` | ||
### Ignoring children | ||
**Ignoring tags** | ||
You can tell the diff to ignore certain tags entirely: | ||
```javascript | ||
it('renders correctly', async () => { | ||
const el = await fixture(` | ||
<div> | ||
<my-custom-element></my-custom-element> | ||
foo | ||
</div> | ||
`); | ||
// ignore id attributes on input elements | ||
expect(el).dom.to.equal('<div>Hey</div>', { | ||
ignoreTags: ['my-custom-element'] | ||
}); | ||
expect(el).dom.to.equalSnapshot({ | ||
ignoreTags: ['my-custom-element'] | ||
}); | ||
}); | ||
``` | ||
**Ignoring children** | ||
When working with web components you may find that they sometimes render to their light dom, for example to meet some accessibility requirements. We don't want to ignore the tag completely, as we would then not be able to test if we did render the tag. | ||
@@ -112,24 +239,25 @@ | ||
```javascript | ||
import { getDiffableHTML } from '@open-wc/semantic-dom-diff'; | ||
it('renders correctly', async () => { | ||
const el = await fixture(` | ||
<div> | ||
<my-custom-input id="myInput"> | ||
<input id="inputRenderedInLightDom"> | ||
Some text rendered in the light dom | ||
</my-custom-input> | ||
foo | ||
</div> | ||
`); | ||
const leftTree = getDiffableHTML(` | ||
<div> | ||
<my-custom-input id="myInput"> | ||
<input id="inputRenderedInLightDom"> | ||
Some text rendered in the light dom | ||
</my-custom-input> | ||
foo | ||
</div> | ||
`, { ignoreChildren: ['my-custom-element'] }); | ||
// ignore id attributes on input elements | ||
expect(el).dom.to.equal(` | ||
<div> | ||
<my-custom-input id="myInput"></my-custom-input> | ||
foo | ||
</div> | ||
`, { ignoreChildren: ['my-custom-element'] }); | ||
const rightTree = getDiffableHTML(` | ||
<div> | ||
<my-custom-input id="myInput"></my-custom-input> | ||
foo | ||
</div> | ||
`); | ||
// this test will pass, the light dom of my-custom-input is ignored, but we can still test | ||
// to see if the tag is placed properly | ||
expect(leftTree).to.equal(rightTree); | ||
expect(el).dom.to.equalSnapshot({ | ||
ignoreChildren: ['my-custom-element'] | ||
}); | ||
}); | ||
``` | ||
@@ -136,0 +264,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30518
229
273
7