From cc92f5e00a29548c66ea84819769dc1e7d716cf0 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Fri, 28 Apr 2017 17:51:55 +0200 Subject: [PATCH] Support text and comment nodes in html pretty printing (#3355) * Make sure pretty-format expect util has correct context * Support comment nodes in html pretty printing * Support text nodes in html pretty printing * Add comment key to pretty-format theme * Add type to element in html pretty printer * Remove unused arg from html pretty printer * Cleanup --- .../src/__tests__/HTMLElementPlugin-test.js | 54 +++++++++++++-- .../src/__tests__/expect-util.js | 67 ++++++++++--------- packages/pretty-format/src/index.js | 12 +++- .../pretty-format/src/plugins/HTMLElement.js | 44 ++++++++++-- types/PrettyFormat.js | 9 ++- 5 files changed, 136 insertions(+), 50 deletions(-) diff --git a/packages/pretty-format/src/__tests__/HTMLElementPlugin-test.js b/packages/pretty-format/src/__tests__/HTMLElementPlugin-test.js index 8e99254683b3..ebf3e60636d9 100644 --- a/packages/pretty-format/src/__tests__/HTMLElementPlugin-test.js +++ b/packages/pretty-format/src/__tests__/HTMLElementPlugin-test.js @@ -4,10 +4,9 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. - * + * * @jest-environment jsdom */ -/* eslint-disable max-len */ /* eslint-env browser*/ 'use strict'; @@ -50,10 +49,7 @@ describe('HTMLElement Plugin', () => { parent.setAttribute('id', 123); parent.setAttribute('class', 'classy'); - expect(parent).toPrettyPrintTo( - '', - {}, - ); + expect(parent).toPrettyPrintTo(''); }); it('supports an element with text content', () => { @@ -93,4 +89,50 @@ describe('HTMLElement Plugin', () => { '
\n \n texty texty\n \n
', ); }); + + it('supports siblings', () => { + const parent = document.createElement('div'); + parent.innerHTML = 'some text'; + + expect(parent).toPrettyPrintTo( + [ + '
', + ' ', + ' some ', + ' ', + ' ', + ' text', + ' ', + '
', + ].join('\n'), + ); + }); + + it('supports text node', () => { + const parent = document.createElement('div'); + parent.innerHTML = 'some text'; + + // prettier-ignore + expect(parent).toPrettyPrintTo([ + '
', + ' some ', + ' ', + ' text', + ' ', + '
', + ].join('\n')); + }); + + it('supports comment node', () => { + const parent = document.createElement('div'); + parent.innerHTML = 'some '; + + // prettier-ignore + expect(parent).toPrettyPrintTo([ + '
', + ' some ', + ' ', + '
', + ].join('\n')); + }); }); diff --git a/packages/pretty-format/src/__tests__/expect-util.js b/packages/pretty-format/src/__tests__/expect-util.js index 1586a812aa96..31a474b64348 100644 --- a/packages/pretty-format/src/__tests__/expect-util.js +++ b/packages/pretty-format/src/__tests__/expect-util.js @@ -4,7 +4,7 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. - * + * */ 'use strict'; @@ -13,41 +13,42 @@ const diff = require('jest-diff'); const prettyFormat = require('../'); module.exports = { - getPrettyPrint: plugins => (received, expected, opts) => { - const prettyFormatted = prettyFormat( - received, - Object.assign( - { - plugins, - }, - opts, - ), - ); - const pass = prettyFormatted === expected; + getPrettyPrint: plugins => + function(received, expected, opts) { + const prettyFormatted = prettyFormat( + received, + Object.assign( + { + plugins, + }, + opts, + ), + ); + const pass = prettyFormatted === expected; - const message = pass - ? () => - this.utils.matcherHint('.not.toBe') + - '\n\n' + - `Expected value to not be:\n` + - ` ${this.utils.printExpected(expected)}\n` + - `Received:\n` + - ` ${this.utils.printReceived(prettyFormatted)}` - : () => { - const diffString = diff(expected, prettyFormatted, { - expand: this.expand, - }); - return ( - this.utils.matcherHint('.toBe') + + const message = pass + ? () => + this.utils.matcherHint('.not.toBe') + '\n\n' + - `Expected value to be:\n` + + `Expected value to not be:\n` + ` ${this.utils.printExpected(expected)}\n` + `Received:\n` + - ` ${this.utils.printReceived(prettyFormatted)}` + - (diffString ? `\n\nDifference:\n\n${diffString}` : '') - ); - }; + ` ${this.utils.printReceived(prettyFormatted)}` + : () => { + const diffString = diff(expected, prettyFormatted, { + expand: this.expand, + }); + return ( + this.utils.matcherHint('.toBe') + + '\n\n' + + `Expected value to be:\n` + + ` ${this.utils.printExpected(expected)}\n` + + `Received:\n` + + ` ${this.utils.printReceived(prettyFormatted)}` + + (diffString ? `\n\nDifference:\n\n${diffString}` : '') + ); + }; - return {actual: prettyFormatted, message, pass}; - }, + return {actual: prettyFormatted, message, pass}; + }, }; diff --git a/packages/pretty-format/src/index.js b/packages/pretty-format/src/index.js index d2ad8a6730e8..68de55f1d0ad 100644 --- a/packages/pretty-format/src/index.js +++ b/packages/pretty-format/src/index.js @@ -22,6 +22,7 @@ import type { const style = require('ansi-styles'); type Theme = {| + comment?: string, content?: string, prop?: string, tag?: string, @@ -799,6 +800,7 @@ const DEFAULTS: Options = { printFunctionName: true, spacing: '\n', theme: { + comment: 'gray', content: 'reset', prop: 'yellow', tag: 'cyan', @@ -873,7 +875,13 @@ function prettyFormat(val: any, initialOptions?: InitialOptions): string { opts = normalizeOptions(initialOptions); } - const colors: Colors = {}; + const colors: Colors = { + comment: {close: '', open: ''}, + content: {close: '', open: ''}, + prop: {close: '', open: ''}, + tag: {close: '', open: ''}, + value: {close: '', open: ''}, + }; Object.keys(opts.theme).forEach(key => { if (opts.highlight) { const color = (colors[key] = style[opts.theme[key]]); @@ -886,8 +894,6 @@ function prettyFormat(val: any, initialOptions?: InitialOptions): string { `pretty-format: Option "theme" has a key "${key}" whose value "${opts.theme[key]}" is undefined in ansi-styles.`, ); } - } else { - colors[key] = {close: '', open: ''}; } }); diff --git a/packages/pretty-format/src/plugins/HTMLElement.js b/packages/pretty-format/src/plugins/HTMLElement.js index c956d4aeec31..8e8591248444 100644 --- a/packages/pretty-format/src/plugins/HTMLElement.js +++ b/packages/pretty-format/src/plugins/HTMLElement.js @@ -13,14 +13,36 @@ import type {Colors, Indent, Options, Print, Plugin} from 'types/PrettyFormat'; const escapeHTML = require('./lib/escapeHTML'); -const HTML_ELEMENT_REGEXP = /(HTML\w*?Element)/; + +type Attribute = { + name: string, + value: string, +}; + +type HTMLElement = { + attributes: Array, + childNodes: Array, + nodeType: 1, + tagName: string, +}; +type HTMLText = { + data: string, + nodeType: 3, +}; + +type HTMLComment = { + data: string, + nodeType: 8, +}; + +const HTML_ELEMENT_REGEXP = /(HTML\w*?Element)|Text|Comment/; const test = isHTMLElement; function isHTMLElement(value: any) { return ( value !== undefined && value !== null && - value.nodeType === 1 && + (value.nodeType === 1 || value.nodeType === 3 || value.nodeType === 8) && value.constructor !== undefined && value.constructor.name !== undefined && HTML_ELEMENT_REGEXP.test(value.constructor.name) @@ -41,7 +63,7 @@ function printChildren(flatChildren, print, indent, colors, opts) { .join(opts.edgeSpacing); } -function printAttributes(attributes, print, indent, colors, opts) { +function printAttributes(attributes: Array, indent, colors, opts) { return attributes .sort() .map(attribute => { @@ -57,12 +79,20 @@ function printAttributes(attributes, print, indent, colors, opts) { } const print = ( - element: any, + element: HTMLElement | HTMLText | HTMLComment, print: Print, indent: Indent, opts: Options, colors: Colors, -) => { +): string => { + if (element.nodeType === 3) { + return element.data; + } else if (element.nodeType === 8) { + return ( + colors.comment.open + '' + colors.comment.close + ); + } + let result = colors.tag.open + '<'; const elementName = element.tagName.toLowerCase(); result += elementName + colors.tag.close; @@ -70,10 +100,10 @@ const print = ( const hasAttributes = element.attributes && element.attributes.length; if (hasAttributes) { const attributes = Array.prototype.slice.call(element.attributes); - result += printAttributes(attributes, print, indent, colors, opts); + result += printAttributes(attributes, indent, colors, opts); } - const flatChildren = Array.prototype.slice.call(element.children); + const flatChildren = Array.prototype.slice.call(element.childNodes); if (!flatChildren.length && element.textContent) { flatChildren.push(element.textContent); } diff --git a/types/PrettyFormat.js b/types/PrettyFormat.js index 2f3bd241cd1a..fde835d83f4c 100644 --- a/types/PrettyFormat.js +++ b/types/PrettyFormat.js @@ -9,7 +9,13 @@ */ 'use strict'; -export type Colors = Object; +export type Colors = { + comment: {close: string, open: string}, + content: {close: string, open: string}, + prop: {close: string, open: string}, + tag: {close: string, open: string}, + value: {close: string, open: string}, +}; export type Indent = string => string; export type Refs = Array; export type Print = any => string; @@ -27,6 +33,7 @@ export type Options = {| printFunctionName: boolean, spacing: string, theme: {| + comment: string, content: string, prop: string, tag: string,