Skip to content

Instantly share code, notes, and snippets.

@nweldev
Created August 7, 2019 10:26
Show Gist options
  • Save nweldev/56113345cb4fd5d45f636ac6c7c3637b to your computer and use it in GitHub Desktop.
Save nweldev/56113345cb4fd5d45f636ac6c7c3637b to your computer and use it in GitHub Desktop.
chai-dom as an ES Module
/********
Convert chai-dom 1.8.1 to es module, without any other modification.
From https://github.com/nathanboktae/chai-dom/blob/86c3423/chai-dom.js
See https://github.com/nathanboktae/chai-dom/issues/38
Usage:
import { chaiDom } from '<path-to>/chai-dom';
chai.use(chaiDom);
Copyright (c) 2015 Nathan Black and other contributors
This work is licensed under the terms of the MIT license. For a copy, see <https://opensource.org/licenses/MIT>.
**********/
export function chaiDom(chai, utils) {
var flag = utils.flag,
elToString = function(el) {
var desc
if (isNodeList(el)) {
if (el.length === 0) return 'empty NodeList'
desc = Array.prototype.slice.call(el, 0, 5).map(elToString).join(', ')
return el.length > 5 ? desc + '... (+' + (el.length - 5) + ' more)' : desc
}
if (!isHTMLElement(el)) {
return String(el)
}
desc = el.tagName.toLowerCase()
if (el.id) {
desc += '#' + el.id
}
if (el.className) {
desc += '.' + String(el.className).replace(/\s+/g, '.')
}
Array.prototype.forEach.call(el.attributes, function(attr) {
if (attr.name !== 'class' && attr.name !== 'id') {
desc += '[' + attr.name + (attr.value ? '="' + attr.value + '"]' : ']')
}
})
return desc
},
attrAssert = function(name, val) {
var el = flag(this, 'object'), actual = el.getAttribute(name)
if (!flag(this, 'negate') || undefined === val) {
this.assert(
!!el.attributes[name]
, 'expected ' + elToString(el) + ' to have an attribute #{exp}'
, 'expected ' + elToString(el) + ' not to have an attribute #{exp}'
, name
)
}
if (undefined !== val) {
this.assert(
val === actual
, 'expected ' + elToString(el) + ' to have an attribute ' + utils.inspect(name) + ' with the value #{exp}, but the value was #{act}'
, 'expected ' + elToString(el) + ' not to have an attribute ' + utils.inspect(name) + ' with the value #{act}'
, val
, actual
)
}
flag(this, 'object', actual)
},
isHTMLElement = function(el) {
return el.nodeType === 1 // window.Node.ELEMENT_NODE
},
isNodeList = function(obj) {
return Object.prototype.toString.call(obj) === '[object NodeList]'
}
utils.elToString = elToString
chai.Assertion.addMethod('attr', attrAssert)
chai.Assertion.addMethod('attribute', attrAssert)
chai.Assertion.addMethod('class', function(className) {
var el = flag(this, 'object')
this.assert(
el.classList.contains(className)
, 'expected ' + elToString(el) + ' to have class #{exp}'
, 'expected ' + elToString(el) + ' not to have class #{exp}'
, className
)
})
chai.Assertion.addMethod('id', function(id) {
var el = flag(this, 'object')
this.assert(
el.id == id
, 'expected ' + elToString(el) + ' to have id #{exp}'
, 'expected ' + elToString(el) + ' not to have id #{exp}'
, id
)
})
chai.Assertion.addMethod('html', function(html) {
var el = flag(this, 'object'), actual = flag(this, 'object').innerHTML
if (flag(this, 'contains')) {
this.assert(
actual.indexOf(html) >= 0
, 'expected #{act} to contain HTML #{exp}'
, 'expected #{act} not to contain HTML #{exp}'
, html
, actual
)
} else {
this.assert(
actual === html
, 'expected ' + elToString(el) + ' to have HTML #{exp}, but the HTML was #{act}'
, 'expected ' + elToString(el) + ' not to have HTML #{exp}'
, html
, actual
)
}
})
chai.Assertion.addChainableMethod('trimmed', null, function() {
flag(this, 'trim-text', true)
})
chai.Assertion.addMethod('text', function(text) {
var obj = flag(this, 'object'), contains = flag(this, 'contains'),
trim = flag(this, 'trim-text'), actual, result
if (isNodeList(obj)) {
actual = Array.prototype.map.call(obj, function(el) { return trim ? el.textContent.trim() : el.textContent })
if (Array.isArray(text)) {
result = contains ?
text[flag(this, 'negate') ? 'some' : 'every'](function(t) {
return Array.prototype.some.call(obj, function(el) {
return (trim ? el.textContent.trim() : el.textContent) === t
})
})
:
utils.eql(actual, text)
actual = actual.join()
text = text.join()
} else {
actual = actual.join('')
result = contains ? actual.indexOf(text) >= 0 : actual === text
}
} else {
actual = trim ? obj.textContent.trim() : obj.textContent
result = contains ? actual.indexOf(text) >= 0 : actual === text
}
var objDesc = elToString(obj), textMsg = trim ? 'trimmed text' : 'text'
if (contains) {
this.assert(
result
, 'expected ' + objDesc + ' to contain #{exp}, but the ' + textMsg + ' was #{act}'
, 'expected ' + objDesc + ' not to contain #{exp}, but the ' + textMsg + ' was #{act}'
, text
, actual
)
} else {
this.assert(
result
, 'expected ' + objDesc + ' to have ' + textMsg + ' #{exp}, but the ' + textMsg + ' was #{act}'
, 'expected ' + objDesc + ' not to have ' + textMsg + ' #{exp}'
, text
, actual
)
}
})
chai.Assertion.addMethod('value', function(value) {
var el = flag(this, 'object'), actual = flag(this, 'object').value
this.assert(
flag(this, 'object').value === value
, 'expected ' + elToString(el) + ' to have value #{exp}, but the value was #{act}'
, 'expected ' + elToString(el) + ' not to have value #{exp}'
, value
, actual
)
})
chai.Assertion.overwriteProperty('exist', function(_super) {
return function() {
var obj = flag(this, 'object')
if (isNodeList(obj)) {
this.assert(
obj.length > 0
, 'expected an empty NodeList to have nodes'
, 'expected ' + elToString(obj) + ' to not exist')
} else {
_super.apply(this, arguments)
}
}
})
chai.Assertion.overwriteProperty('empty', function(_super) {
return function() {
var obj = flag(this, 'object')
if (isHTMLElement(obj)) {
this.assert(
obj.children.length === 0
, 'expected ' + elToString(obj) + ' to be empty'
, 'expected ' + elToString(obj) + ' to not be empty')
} else if (isNodeList(obj)) {
this.assert(
obj.length === 0
, 'expected ' + elToString(obj) + ' to be empty'
, 'expected ' + elToString(obj) + ' to not be empty')
} else {
_super.apply(this, arguments)
}
}
})
chai.Assertion.overwriteChainableMethod('length',
function(_super) {
return function(length) {
var obj = flag(this, 'object')
if (isNodeList(obj) || isHTMLElement(obj)) {
var actualLength = obj.children ? obj.children.length : obj.length
this.assert(
actualLength === length
, 'expected ' + elToString(obj) + ' to have #{exp} children but it had #{act} children'
, 'expected ' + elToString(obj) + ' to not have #{exp} children'
, length
, actualLength
)
} else {
_super.apply(this, arguments)
}
}
},
function(_super) {
return function() {
_super.call(this)
}
}
)
chai.Assertion.overwriteMethod('match', function(_super) {
return function(selector) {
var obj = flag(this, 'object')
if (isHTMLElement(obj)) {
this.assert(
obj.matches(selector)
, 'expected ' + elToString(obj) + ' to match #{exp}'
, 'expected ' + elToString(obj) + ' to not match #{exp}'
, selector
)
} else if (isNodeList(obj)) {
this.assert(
(!!obj.length && Array.prototype.every.call(obj, function(el) { return el.matches(selector) }))
, 'expected ' + elToString(obj) + ' to match #{exp}'
, 'expected ' + elToString(obj) + ' to not match #{exp}'
, selector
)
} else {
_super.apply(this, arguments)
}
}
})
chai.Assertion.overwriteChainableMethod('contain',
function(_super) {
return function(subitem) {
var obj = flag(this, 'object')
if (isHTMLElement(obj)) {
if (typeof subitem === 'string') {
this.assert(
!!obj.querySelector(subitem)
, 'expected ' + elToString(obj) + ' to contain #{exp}'
, 'expected ' + elToString(obj) + ' to not contain #{exp}'
, subitem)
} else {
this.assert(
obj.contains(subitem)
, 'expected ' + elToString(obj) + ' to contain ' + elToString(subitem)
, 'expected ' + elToString(obj) + ' to not contain ' + elToString(subitem))
}
} else {
_super.apply(this, arguments)
}
}
},
function(_super) {
return function() {
_super.call(this)
}
}
)
chai.Assertion.addMethod('descendant', function(subitem) {
var obj = flag(this, 'object'), actual = subitem
if (typeof subitem === 'string') {
actual = obj.querySelector(subitem)
this.assert(
!!actual
, 'expected ' + elToString(obj) + ' to have descendant #{exp}'
, 'expected ' + elToString(obj) + ' to not have descendant #{exp}'
, subitem)
} else {
this.assert(
obj.contains(subitem)
, 'expected ' + elToString(obj) + ' to contain ' + elToString(subitem)
, 'expected ' + elToString(obj) + ' to not contain ' + elToString(subitem))
}
flag(this, 'object', actual)
})
chai.Assertion.addMethod('descendants', function(selector) {
var obj = flag(this, 'object'),
actual = obj.querySelectorAll(selector)
this.assert(
!!actual.length
, 'expected ' + elToString(obj) + ' to have descendants #{exp}'
, 'expected ' + elToString(obj) + ' to not have descendants #{exp}'
, selector)
flag(this, 'object', actual)
})
chai.Assertion.addProperty('displayed', function() {
var el = flag(this, 'object'),
actual = document.body.contains(el) ? window.getComputedStyle(el).display : el.style.display
this.assert(
actual !== 'none'
, 'expected ' + elToString(el) + ' to be displayed, but it was not'
, 'expected ' + elToString(el) + ' to not be displayed, but it was as ' + actual
, actual
)
})
chai.Assertion.addProperty('visible', function() {
var el = flag(this, 'object'),
actual = document.body.contains(el) ? window.getComputedStyle(el).visibility : el.style.visibility
this.assert(
actual !== 'hidden' && actual !== 'collapse'
, 'expected ' + elToString(el) + ' to be visible, but it was ' + (actual === 'hidden' ? 'hidden' : 'collapsed')
, 'expected ' + elToString(el) + ' to not be visible, but it was'
, actual
)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment