Skip to content

Commit

Permalink
pretty-format: Support HTMLCollection and NodeList in DOMCollection p…
Browse files Browse the repository at this point in the history
…lugin (#7125)
  • Loading branch information
pedrottimark authored and SimenB committed Oct 11, 2018
1 parent a1b82ca commit 5fcaa24
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 32 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- `[jest-config]` Add `readConfigs` function, previously in `jest-cli` ([#7096](https://github.com/facebook/jest/pull/7096))
- `[jest-snapshot]` Enable configurable snapshot paths ([#6143](https://github.com/facebook/jest/pull/6143))
- `[jest-haste-map]` [**BREAKING**] Remove support for `@providesModule` ([#6104](https://github.com/facebook/jest/pull/6104))
- `[pretty-format]` Support HTMLCollection and NodeList in DOMCollection plugin ([#7125](https://github.com/facebook/jest/pull/7125))

### Fixes

Expand Down
132 changes: 128 additions & 4 deletions packages/pretty-format/src/__tests__/dom_collection.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,150 @@
'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}');
});

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', () => {
const select = document.createElement('select');
select.innerHTML = [
'<option value="1">one</option>',
'<option value="2">two</option>',
'<option value="3">three</option>',
].join('');

const form = document.createElement('form');
form.appendChild(select);

const expectedOption1 = [
' <option',
' value="1"',
' >',
' one',
' </option>,', // comma because item
].join('\n');
const expectedOption2 = [
' <option',
' value="2"',
' >',
' two',
' </option>,', // comma because item
].join('\n');
const expectedOption3 = [
' <option',
' value="3"',
' >',
' three',
' </option>,', // 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);
});

it('supports config.maxDepth option', () => {
expect(select.children).toPrettyPrintTo('[HTMLCollection]', {maxDepth: 0});
});

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 select options', () => {
expect(select.options).toPrettyPrintTo(expectedHTMLOptionsCollection);
});

// When Jest upgrades to a version of jsdom later than 12.2.0,
// the class name might become HTMLFormControlsCollection
const expectedHTMLFormControlsCollection = [
'HTMLCollection [',
' <select>',
' <option',
' value="1"',
' >',
' one',
' </option>', // no comma because element
' <option',
' value="2"',
' >',
' two',
' </option>', // no comma because element
' <option',
' value="3"',
' >',
' three',
' </option>', // no comma because element
' </select>,', // comma because item
']',
].join('\n');

it('supports HTMLCollection for form elements', () => {
expect(form.elements).toPrettyPrintTo(expectedHTMLFormControlsCollection);
});
});
66 changes: 38 additions & 28 deletions packages/pretty-format/src/plugins/dom_collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand All @@ -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.from(collection),
config,
indentation,
depth,
refs,
printer,
) +
']')
);
};

Expand Down

0 comments on commit 5fcaa24

Please sign in to comment.