From 25bd2b40870fa559728150b1abf08495324ec69e Mon Sep 17 00:00:00 2001 From: Alex J Burke Date: Sat, 29 Sep 2018 15:37:32 +0200 Subject: [PATCH 1/2] Fix comment nodes being specified as children in a satisfy spec. --- lib/index.js | 14 ++++++++++++- test/index.spec.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 04bf728a..470352e0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -742,6 +742,16 @@ module.exports = { } ); + function convertChildrenToSatisfySpec(children, isHtml) { + return children.map(function(child) { + if (expect.findTypeOf(child).is('DOMNode')) { + return convertDOMNodeToSatisfySpec(child, isHtml); + } else { + return child; + } + }); + } + function convertDOMNodeToSatisfySpec(node, isHtml) { if (node.nodeType === 8 && node.nodeValue.trim() === 'ignore') { // Ignore subtree @@ -991,7 +1001,9 @@ module.exports = { subject.ownerDocument.contentType ), 'to satisfy', - value.children + Array.isArray(value.children) + ? convertChildrenToSatisfySpec(value.children, isHtml) + : value.children ); }); } else if (typeof value.textContent !== 'undefined') { diff --git a/test/index.spec.js b/test/index.spec.js index 6e50d14a..952fb197 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -2032,6 +2032,15 @@ describe('unexpected-dom', function() { expect(body.firstChild, 'to satisfy', { children: ['hey'] }); }); + it('should succeed with a node child', function() { + var node = document.createElement('div'); + node.innerHTML = '
hey
'; + body.innerHTML = '
hey
'; + expect(body.firstChild, 'to satisfy', { + children: [node.firstChild] + }); + }); + it('should fail with a diff', function() { body.innerHTML = '
hey
'; expect( @@ -2049,6 +2058,24 @@ describe('unexpected-dom', function() { '' ); }); + + describe('when using ignore', function() { + it('should succeed', function() { + var node = document.createElement('div'); + node.innerHTML = ''; + var commentNode = node.firstChild; + body.innerHTML = + '
ignoreimportant
'; + expect(body.firstChild, 'to satisfy', { + children: [ + commentNode, + { + children: 'important' + } + ] + }); + }); + }); }); it('should fail with a diff', function() { @@ -2625,6 +2652,31 @@ describe('unexpected-dom', function() { }); }); + describe('to satisfy', function() { + describe('when comparing an array of children', function() { + it('should succeed with a text child', function() { + expect( + [ + '', + '', + ' World', + '' + ].join('\n'), + 'when parsed as XML', + 'queried for first', + 'hello', + 'to satisfy', + { + attributes: { + type: 'greeting' + }, + children: ['World'] + } + ); + }); + }); + }); + describe('when the DOMParser global is available', function() { var originalDOMParser, DOMParserSpy, parseFromStringSpy; From fe9ce653946b2a3a137c7c616bf88c238c9f186c Mon Sep 17 00:00:00 2001 From: Andreas Lind Date: Sun, 30 Sep 2018 22:21:43 +0200 Subject: [PATCH 2/2] Model as its own type and implement the ignoring via an assertion Fixes as the top-level to satisfy RHS. --- lib/index.js | 47 +++++++++++++++++++++++++++++----------------- test/index.spec.js | 42 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/lib/index.js b/lib/index.js index 470352e0..8a01de6a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -308,6 +308,17 @@ module.exports = { } }); + // Recognize as a special subtype of DOMComment so it can be targeted by assertions: + expect.exportType({ + name: 'DOMIgnoreComment', + base: 'DOMComment', + identify: function(obj) { + return ( + this.baseType.identify(obj) && /^\s*ignore\s*$/.test(obj.nodeValue) + ); + } + }); + expect.exportType({ name: 'DOMTextNode', base: 'DOMNode', @@ -719,6 +730,13 @@ module.exports = { } ); + expect.exportAssertion( + ' to [exhaustively] satisfy ', + function(expect, subject, value) { + return expect(subject.nodeValue, 'to equal', value.nodeValue); + } + ); + // Avoid rendering a huge object diff when a text node is matched against a different node type: expect.exportAssertion( ' to [exhaustively] satisfy ', @@ -727,6 +745,13 @@ module.exports = { } ); + // Always passes: + expect.exportAssertion( + // Name each subject type to increase the specificity of the assertion + ' to [exhaustively] satisfy ', + function(expect, subject, value) {} + ); + // Necessary because this case would otherwise be handled by the above catch-all for : expect.exportAssertion( ' to [exhaustively] satisfy ', @@ -742,21 +767,8 @@ module.exports = { } ); - function convertChildrenToSatisfySpec(children, isHtml) { - return children.map(function(child) { - if (expect.findTypeOf(child).is('DOMNode')) { - return convertDOMNodeToSatisfySpec(child, isHtml); - } else { - return child; - } - }); - } - function convertDOMNodeToSatisfySpec(node, isHtml) { - if (node.nodeType === 8 && node.nodeValue.trim() === 'ignore') { - // Ignore subtree - return expect.it('to be an', 'DOMNode'); - } else if (node.nodeType === 10) { + if (node.nodeType === 10) { // HTMLDocType return { name: node.nodeName }; } else if (node.nodeType === 1) { @@ -788,6 +800,9 @@ module.exports = { } else if (node.nodeType === 3) { // DOMTextNode return node.nodeValue; + } else if (node.nodeType === 8) { + // DOMComment + return node; } else { throw new Error( 'to satisfy: Node type ' + @@ -1001,9 +1016,7 @@ module.exports = { subject.ownerDocument.contentType ), 'to satisfy', - Array.isArray(value.children) - ? convertChildrenToSatisfySpec(value.children, isHtml) - : value.children + value.children ); }); } else if (typeof value.textContent !== 'undefined') { diff --git a/test/index.spec.js b/test/index.spec.js index 952fb197..d5384956 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -63,6 +63,10 @@ function parseHtml(str) { .window.document.body.firstChild; } +function parseHtmlDocument(str) { + return new jsdom.JSDOM(str).window.document; +} + function parseHtmlFragment(str) { str = '' + str + ''; var htmlDocument = new jsdom.JSDOM(str).window.document; @@ -76,6 +80,10 @@ function parseHtmlFragment(str) { return documentFragment; } +function parseHtmlNode(str) { + return parseHtmlFragment(str).childNodes[0]; +} + function parseXml(str) { if (typeof DOMParser !== 'undefined') { // eslint-disable-next-line no-undef @@ -1468,7 +1476,7 @@ describe('unexpected-dom', function() { ); }); - describe('and it contain an ignore comment', function() { + describe('and it contains an ignore comment', function() { it('ignores the corresponding subtree', () => { expect( [ @@ -2078,6 +2086,38 @@ describe('unexpected-dom', function() { }); }); + describe('when matching against ', function() { + var ignoreComment = parseHtmlNode(''); + + it('should match a text node', function() { + expect(parseHtmlNode('foo'), 'to satisfy', ignoreComment); + }); + + it('should match an element', function() { + expect(parseHtmlNode('
foo
'), 'to satisfy', ignoreComment); + }); + + it('should match a comment', function() { + expect(parseHtmlNode(''), 'to satisfy', ignoreComment); + }); + + it('should match a doctype', function() { + expect( + parseHtmlDocument('').firstChild, + 'to satisfy', + ignoreComment + ); + }); + + it('should match a document', function() { + expect( + 'abc', + 'when parsed as xml to satisfy', + ignoreComment + ); + }); + }); + it('should fail with a diff', function() { body.innerHTML = '
foobar
hey
';