From deded51f82f6e528eb044cb260346d902916106d Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Mon, 8 Oct 2018 18:18:34 -0400 Subject: [PATCH 1/3] pretty-format: Support HTMLCollection and NodeList in DOMCollection plugin --- .../src/__tests__/dom_collection.test.js | 93 ++++++++++++++++++- .../src/plugins/dom_collection.js | 66 +++++++------ 2 files changed, 127 insertions(+), 32 deletions(-) diff --git a/packages/pretty-format/src/__tests__/dom_collection.test.js b/packages/pretty-format/src/__tests__/dom_collection.test.js index 38128a3ff8c6..2e4e0e3af1f4 100644 --- a/packages/pretty-format/src/__tests__/dom_collection.test.js +++ b/packages/pretty-format/src/__tests__/dom_collection.test.js @@ -12,26 +12,111 @@ 'use strict'; const prettyFormat = require('../'); -const {DOMCollection} = prettyFormat.plugins; +const {DOMCollection, DOMElement} = prettyFormat.plugins; const toPrettyPrintTo = require('./expect_util').getPrettyPrint([ DOMCollection, + DOMElement, ]); const expect: any = global.expect; expect.extend({toPrettyPrintTo}); -describe('DOMCollection Plugin', () => { - it('supports a DOMStringMap', () => { +describe('DOMCollection plugin for object properties', () => { + it('supports DOMStringMap', () => { const el = document.createElement('div'); el.dataset.foo = 'bar'; expect(el.dataset).toPrettyPrintTo('DOMStringMap {\n "foo": "bar",\n}'); }); - it('supports a NamedNodeMap', () => { + it('supports NamedNodeMap', () => { const el = document.createElement('div'); el.setAttribute('foo', 'bar'); expect(el.attributes).toPrettyPrintTo('NamedNodeMap {\n "foo": "bar",\n}'); }); }); + +describe('DOMCollection plugin for list items', () => { + const select = document.createElement('select'); + select.innerHTML = [ + '', + '', + '', + ].join(''); + + const form = document.createElement('form'); + form.appendChild(select); + + const expectedOption1 = [ + ' ', + ' one', + ' ,', // comma because item + ].join('\n'); + const expectedOption2 = [ + ' ', + ' two', + ' ,', // comma because item + ].join('\n'); + const expectedOption3 = [ + ' ', + ' three', + ' ,', // comma because item + ].join('\n'); + + const expectedHTMLCollection = [ + 'HTMLCollection [', + expectedOption1, + expectedOption2, + expectedOption3, + ']', + ].join('\n'); + + it('supports HTMLCollection for getElementsByTagName', () => { + const options = form.getElementsByTagName('option'); + expect(options).toPrettyPrintTo(expectedHTMLCollection); + }); + + it('supports HTMLCollection for children', () => { + expect(select.children).toPrettyPrintTo(expectedHTMLCollection); + }); + + const expectedNodeList = [ + 'NodeList [', + expectedOption1, + expectedOption2, + expectedOption3, + ']', + ].join('\n'); + + it('supports NodeList for querySelectorAll', () => { + const options = form.querySelectorAll('option'); + expect(options).toPrettyPrintTo(expectedNodeList); + }); + + it('supports NodeList for childNodes', () => { + expect(select.childNodes).toPrettyPrintTo(expectedNodeList); + }); + + const expectedHTMLOptionsCollection = [ + 'HTMLOptionsCollection [', + expectedOption1, + expectedOption2, + expectedOption3, + ']', + ].join('\n'); + + it('supports HTMLOptionsCollection for options', () => { + expect(select.options).toPrettyPrintTo(expectedHTMLOptionsCollection); + }); + + // Omitted a test for form.elements because constructor.name + // is HTMLCollection in jsdom version 11 + // might become HTMLFormControlsCollectio in jsdom 12 +}); diff --git a/packages/pretty-format/src/plugins/dom_collection.js b/packages/pretty-format/src/plugins/dom_collection.js index 5af357b05af5..302813a1a73f 100644 --- a/packages/pretty-format/src/plugins/dom_collection.js +++ b/packages/pretty-format/src/plugins/dom_collection.js @@ -9,29 +9,26 @@ import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; -import {printObjectProperties} from '../collections'; +import {printListItems, printObjectProperties} from '../collections'; const SPACE = ' '; -const COLLECTION_NAMES = ['DOMStringMap', 'NamedNodeMap']; +const OBJECT_NAMES = ['DOMStringMap', 'NamedNodeMap']; +const ARRAY_REGEXP = /^(HTML\w*Collection|NodeList)$/; + +const testName = (name: any) => + OBJECT_NAMES.indexOf(name) !== -1 || ARRAY_REGEXP.test(name); export const test = (val: any) => val && val.constructor && - COLLECTION_NAMES.indexOf(val.constructor.name) !== -1; - -const convertCollectionToObject = (collection: any) => { - let result = {}; - - if (collection.constructor.name === 'NamedNodeMap') { - for (let i = 0; i < collection.length; i++) { - result[collection[i].name] = collection[i].value; - } - } else { - result = Object.assign({}, collection); - } + val.constructor.name && + testName(val.constructor.name); - return result; +// Convert array of attribute objects to props object. +const propsReducer = (props, attribute) => { + props[attribute.name] = attribute.value; + return props; }; export const serialize = ( @@ -42,23 +39,36 @@ export const serialize = ( refs: Refs, printer: Printer, ): string => { + const name = collection.constructor.name; if (++depth > config.maxDepth) { - return '[' + collection.constructor.name + ']'; + return '[' + name + ']'; } return ( - collection.constructor.name + - SPACE + - '{' + - printObjectProperties( - convertCollectionToObject(collection), - config, - indentation, - depth, - refs, - printer, - ) + - '}' + (config.min ? '' : name + SPACE) + + (OBJECT_NAMES.indexOf(name) !== -1 + ? '{' + + printObjectProperties( + name === 'NamedNodeMap' + ? Array.prototype.reduce.call(collection, propsReducer, {}) + : Object.assign({}, collection), + config, + indentation, + depth, + refs, + printer, + ) + + '}' + : '[' + + printListItems( + Array.prototype.slice.call(collection), + config, + indentation, + depth, + refs, + printer, + ) + + ']') ); }; From 69dc91f982fa091232c734f99f1b7274dfbf66af Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Mon, 8 Oct 2018 18:30:02 -0400 Subject: [PATCH 2/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cac33660b742..95a3d7a66205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `[jest-worker]` [**BREAKING**] Add functionality to call a `setup` method in the worker before the first call and a `teardown` method when ending the farm ([#7014](https://github.com/facebook/jest/pull/7014)). - `[jest-config]` [**BREAKING**] Set default `notifyMode` to `failure-change` ([#7024](https://github.com/facebook/jest/pull/7024)) - `[jest-snapshot]` Enable configurable snapshot paths ([#6143](https://github.com/facebook/jest/pull/6143)) +- `[pretty-format]` Support HTMLCollection and NodeList in DOMCollection plugin ([#7125](https://github.com/facebook/jest/pull/7125)) ### Fixes From 7f65212022397d095afd741957ba665cfaea8db8 Mon Sep 17 00:00:00 2001 From: Mark Pedrotti Date: Tue, 9 Oct 2018 11:23:41 -0400 Subject: [PATCH 3/3] Make recommended changes and add tests for options --- .../src/__tests__/dom_collection.test.js | 47 +++++++++++++++++-- .../src/plugins/dom_collection.js | 2 +- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/pretty-format/src/__tests__/dom_collection.test.js b/packages/pretty-format/src/__tests__/dom_collection.test.js index 2e4e0e3af1f4..cf0d498f8b18 100644 --- a/packages/pretty-format/src/__tests__/dom_collection.test.js +++ b/packages/pretty-format/src/__tests__/dom_collection.test.js @@ -35,6 +35,17 @@ describe('DOMCollection plugin for object properties', () => { expect(el.attributes).toPrettyPrintTo('NamedNodeMap {\n "foo": "bar",\n}'); }); + + it('supports config.min option', () => { + const el = document.createElement('div'); + el.setAttribute('name1', 'value1'); + el.setAttribute('name2', 'value2'); + + expect(el.attributes).toPrettyPrintTo( + '{"name1": "value1", "name2": "value2"}', + {min: true}, + ); + }); }); describe('DOMCollection plugin for list items', () => { @@ -87,6 +98,10 @@ describe('DOMCollection plugin for list items', () => { expect(select.children).toPrettyPrintTo(expectedHTMLCollection); }); + it('supports config.maxDepth option', () => { + expect(select.children).toPrettyPrintTo('[HTMLCollection]', {maxDepth: 0}); + }); + const expectedNodeList = [ 'NodeList [', expectedOption1, @@ -112,11 +127,35 @@ describe('DOMCollection plugin for list items', () => { ']', ].join('\n'); - it('supports HTMLOptionsCollection for options', () => { + it('supports HTMLOptionsCollection for select options', () => { expect(select.options).toPrettyPrintTo(expectedHTMLOptionsCollection); }); - // Omitted a test for form.elements because constructor.name - // is HTMLCollection in jsdom version 11 - // might become HTMLFormControlsCollectio in jsdom 12 + // When Jest upgrades to a version of jsdom later than 12.2.0, + // the class name might become HTMLFormControlsCollection + const expectedHTMLFormControlsCollection = [ + 'HTMLCollection [', + ' ,', // comma because item + ']', + ].join('\n'); + + it('supports HTMLCollection for form elements', () => { + expect(form.elements).toPrettyPrintTo(expectedHTMLFormControlsCollection); + }); }); diff --git a/packages/pretty-format/src/plugins/dom_collection.js b/packages/pretty-format/src/plugins/dom_collection.js index 302813a1a73f..716e83829617 100644 --- a/packages/pretty-format/src/plugins/dom_collection.js +++ b/packages/pretty-format/src/plugins/dom_collection.js @@ -61,7 +61,7 @@ export const serialize = ( '}' : '[' + printListItems( - Array.prototype.slice.call(collection), + Array.from(collection), config, indentation, depth,