diff --git a/package.json b/package.json index 28c15d9ba023..c52ff646e01b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "flow-bin": "^0.39.0", "glob": "^7.1.1", "graceful-fs": "^4.1.11", + "immutable": "^3.8.1", "istanbul-api": "^1.1.0", "istanbul-lib-coverage": "^1.0.0", "jasmine-reporters": "^2.2.0", diff --git a/packages/jest-diff/src/index.js b/packages/jest-diff/src/index.js index 8beb375bcc94..80385a664305 100644 --- a/packages/jest-diff/src/index.js +++ b/packages/jest-diff/src/index.js @@ -15,6 +15,7 @@ import type {DiffOptions} from './diffStrings'; const ReactElementPlugin = require('pretty-format/build/plugins/ReactElement'); const ReactTestComponentPlugin = require('pretty-format/build/plugins/ReactTestComponent'); const AsymmetricMatcherPlugin = require('pretty-format/build/plugins/AsymmetricMatcher'); +const ImmutablePlugins = require('pretty-format/build/plugins/ImmutablePlugins'); const chalk = require('chalk'); const diffStrings = require('./diffStrings'); @@ -30,7 +31,7 @@ const PLUGINS = [ ReactTestComponentPlugin, ReactElementPlugin, AsymmetricMatcherPlugin, -]; +].concat(ImmutablePlugins); const FORMAT_OPTIONS = { plugins: PLUGINS, }; diff --git a/packages/jest-matcher-utils/src/index.js b/packages/jest-matcher-utils/src/index.js index 7c9ee30cf2b7..2845993d5bd5 100644 --- a/packages/jest-matcher-utils/src/index.js +++ b/packages/jest-matcher-utils/src/index.js @@ -13,8 +13,13 @@ const chalk = require('chalk'); const prettyFormat = require('pretty-format'); const AsymmetricMatcherPlugin = require('pretty-format/build/plugins/AsymmetricMatcher'); +const ReactElementPlugin = require('pretty-format/build/plugins/ReactElement'); +const ImmutablePlugins = require('pretty-format/build/plugins/ImmutablePlugins'); -const PLUGINS = [AsymmetricMatcherPlugin]; +const PLUGINS = [ + AsymmetricMatcherPlugin, + ReactElementPlugin, +].concat(ImmutablePlugins); export type ValueType = | 'array' diff --git a/packages/jest-snapshot/src/__tests__/plugins-test.js b/packages/jest-snapshot/src/__tests__/plugins-test.js index 26bd654c6665..e887b602f329 100644 --- a/packages/jest-snapshot/src/__tests__/plugins-test.js +++ b/packages/jest-snapshot/src/__tests__/plugins-test.js @@ -31,7 +31,7 @@ const testPath = names => { it('gets plugins', () => { const {getSerializers} = require('../plugins'); const plugins = getSerializers(); - expect(plugins.length).toBe(2); + expect(plugins.length).toBe(8); }); it('adds plugins from an empty array', () => testPath([])); diff --git a/packages/jest-snapshot/src/plugins.js b/packages/jest-snapshot/src/plugins.js index 481155b9cd93..e6f30bfaad70 100644 --- a/packages/jest-snapshot/src/plugins.js +++ b/packages/jest-snapshot/src/plugins.js @@ -11,8 +11,12 @@ const ReactElementPlugin = require('pretty-format/build/plugins/ReactElement'); const ReactTestComponentPlugin = require('pretty-format/build/plugins/ReactTestComponent'); +const ImmutablePlugins = require('pretty-format/build/plugins/ImmutablePlugins'); -let PLUGINS = [ReactElementPlugin, ReactTestComponentPlugin]; +let PLUGINS = [ + ReactElementPlugin, + ReactTestComponentPlugin, +].concat(ImmutablePlugins); // Prepend to list so the last added is the first tested. exports.addSerializer = (plugin: any) => { diff --git a/packages/pretty-format/src/__tests__/ImmutablePlugins-test.js b/packages/pretty-format/src/__tests__/ImmutablePlugins-test.js new file mode 100644 index 000000000000..84a933b9a63d --- /dev/null +++ b/packages/pretty-format/src/__tests__/ImmutablePlugins-test.js @@ -0,0 +1,376 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + */ + /* eslint-disable max-len */ + +'use strict'; + +const React = require('react'); +const diff = require('jest-diff'); +const prettyFormat = require('../'); +const Immutable = require('immutable'); +const ReactElementPlugin = require('../plugins/ReactElement'); +const ReactTestComponentPlugin = require('../plugins/ReactTestComponent'); +const ImmutablePlugins = require('../plugins/ImmutablePlugins'); + +expect.extend({ + toPrettyPrintTo(received, expected, opts) { + const prettyPrintImmutable = prettyFormat(received, + Object.assign({ + plugins: [ + ReactElementPlugin, + ReactTestComponentPlugin, + ].concat(ImmutablePlugins), + }, opts) + ); + const pass = prettyPrintImmutable === 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(prettyPrintImmutable)}` + : () => { + const diffString = diff(expected, prettyPrintImmutable, { + 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(prettyPrintImmutable)}` + + (diffString ? `\n\nDifference:\n\n${diffString}` : ''); + }; + + return {actual: prettyPrintImmutable, message, pass}; + }, +}); + +describe('Immutable.OrderedSet plugin', () => { + it('supports an empty set', () => { + expect(Immutable.OrderedSet([])) + .toPrettyPrintTo('Immutable.OrderedSet []', {min: true}); + }); + + it('supports a single string element', () => { + expect(Immutable.OrderedSet(['foo'])) + .toPrettyPrintTo('Immutable.OrderedSet ["foo"]', {min: true}); + }); + + it('supports a single integer element', () => { + expect(Immutable.OrderedSet([1])) + .toPrettyPrintTo('Immutable.OrderedSet [1]', {min: true}); + }); + + it('supports multiple string elements {min: true}', () => { + expect(Immutable.OrderedSet(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.OrderedSet ["jhon", "mike", "cristian"]', {min: true}); + }); + + it('supports multiple string elements {min: false}', () => { + expect(Immutable.OrderedSet(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.OrderedSet [\n "jhon",\n "mike",\n "cristian",\n]', {min: false}); + }); + + it('supports multiple integer elements {min: true}', () => { + expect(Immutable.OrderedSet([1, 2, 3])) + .toPrettyPrintTo('Immutable.OrderedSet [1, 2, 3]', {min: true}); + }); + + it('supports multiple integer elements {min: false}', () => { + expect(Immutable.OrderedSet([1, 2, 3])) + .toPrettyPrintTo('Immutable.OrderedSet [\n 1,\n 2,\n 3,\n]', {min: false}); + }); + + it('supports object elements {min: true}', () => { + expect(Immutable.OrderedSet([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.OrderedSet [{\"a\": 1, \"b\": 2, \"c\": 3}]', {min: true}); + }); + + it('supports object elements {min: false}', () => { + expect(Immutable.OrderedSet([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.OrderedSet [\n Object {\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n },\n]', {min: false}); + }); + + it('supports React components {min: true}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.OrderedSet([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.OrderedSet [Hello World]', {min: true}); + }); + + it('supports React components {min: false}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.OrderedSet([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.OrderedSet [\n \n Hello World\n ,\n]', {min: false}); + }); +}); + +describe('Immutable.List plugin', () => { + it('supports an empty set', () => { + expect(Immutable.List([])) + .toPrettyPrintTo('Immutable.List []', {min: true}); + }); + + it('supports a single string element', () => { + expect(Immutable.List(['foo'])) + .toPrettyPrintTo('Immutable.List ["foo"]', {min: true}); + }); + + it('supports a single integer element', () => { + expect(Immutable.List([1])) + .toPrettyPrintTo('Immutable.List [1]', {min: true}); + }); + + it('supports multiple string elements {min: true}', () => { + expect(Immutable.List(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.List ["jhon", "mike", "cristian"]', {min: true}); + }); + + it('supports multiple string elements {min: false}', () => { + expect(Immutable.List(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.List [\n "jhon",\n "mike",\n "cristian",\n]'); + }); + + it('supports multiple integer elements {min: true}', () => { + expect(Immutable.List([1, 2, 3])) + .toPrettyPrintTo('Immutable.List [1, 2, 3]', {min: true}); + }); + + it('supports multiple integer elements {min: false}', () => { + expect(Immutable.List([1, 2, 3])) + .toPrettyPrintTo('Immutable.List [\n 1,\n 2,\n 3,\n]'); + }); + + it('supports object elements {min: true}', () => { + expect(Immutable.List([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.List [{\"a\": 1, \"b\": 2, \"c\": 3}]', {min: true}); + }); + + it('supports object elements {min: false}', () => { + expect(Immutable.List([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.List [\n Object {\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n },\n]'); + }); + + it('supports React components {min: true}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.List([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.List [Hello World, Hello World]', {min: true}); + }); + + it('supports React components {min: false}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.List([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.List [\n \n Hello World\n ,\n \n Hello World\n ,\n]'); + }); +}); + +describe('Immutable.Stack plugin', () => { + it('supports an empty set', () => { + expect(Immutable.Stack([])) + .toPrettyPrintTo('Immutable.Stack []', {min: true}); + }); + + it('supports a single string element', () => { + expect(Immutable.Stack(['foo'])) + .toPrettyPrintTo('Immutable.Stack ["foo"]', {min: true}); + }); + + it('supports a single integer element', () => { + expect(Immutable.Stack([1])) + .toPrettyPrintTo('Immutable.Stack [1]', {min: true}); + }); + + it('supports multiple string elements {min: true}', () => { + expect(Immutable.Stack(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.Stack ["jhon", "mike", "cristian"]', {min: true}); + }); + + it('supports multiple string elements {min: false}', () => { + expect(Immutable.Stack(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.Stack [\n "jhon",\n "mike",\n "cristian",\n]'); + }); + + it('supports multiple integer elements {min: true}', () => { + expect(Immutable.Stack([1, 2, 3])) + .toPrettyPrintTo('Immutable.Stack [1, 2, 3]', {min: true}); + }); + + it('supports multiple integer elements {min: false}', () => { + expect(Immutable.Stack([1, 2, 3])) + .toPrettyPrintTo('Immutable.Stack [\n 1,\n 2,\n 3,\n]'); + }); + + it('supports object elements {min: true}', () => { + expect(Immutable.Stack([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.Stack [{\"a\": 1, \"b\": 2, \"c\": 3}]', {min: true}); + }); + + it('supports object elements {min: false}', () => { + expect(Immutable.Stack([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.Stack [\n Object {\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n },\n]'); + }); + + it('supports React components {min: true}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.Stack([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.Stack [Hello World, Hello World]', {min: true}); + }); + + it('supports React components {min: false}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.Stack([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.Stack [\n \n Hello World\n ,\n \n Hello World\n ,\n]'); + }); +}); + +describe('Immutable.Set plugin', () => { + it('supports an empty set', () => { + expect(Immutable.Set([])) + .toPrettyPrintTo('Immutable.Set []', {min: true}); + }); + + it('supports a single string element', () => { + expect(Immutable.Set(['foo'])) + .toPrettyPrintTo('Immutable.Set ["foo"]', {min: true}); + }); + + it('supports a single integer element', () => { + expect(Immutable.Set([1])) + .toPrettyPrintTo('Immutable.Set [1]', {min: true}); + }); + + it('supports multiple string elements {min: true}', () => { + expect(Immutable.Set(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.Set ["jhon", "mike", "cristian"]', {min: true}); + }); + + it('supports multiple string elements {min: false}', () => { + expect(Immutable.Set(['jhon', 'mike', 'cristian'])) + .toPrettyPrintTo('Immutable.Set [\n "jhon",\n "mike",\n "cristian",\n]'); + }); + + it('supports multiple integer elements {min: true}', () => { + expect(Immutable.Set([1, 2, 3])) + .toPrettyPrintTo('Immutable.Set [1, 2, 3]', {min: true}); + }); + + it('supports multiple integer elements {min: false}', () => { + expect(Immutable.Set([1, 2, 3])) + .toPrettyPrintTo('Immutable.Set [\n 1,\n 2,\n 3,\n]'); + }); + + it('supports object elements {min: true}', () => { + expect(Immutable.Set([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.Set [{\"a\": 1, \"b\": 2, \"c\": 3}]', {min: true}); + }); + + it('supports object elements {min: false}', () => { + expect(Immutable.Set([{a: 1, b: 2, c: 3}])) + .toPrettyPrintTo('Immutable.Set [\n Object {\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n },\n]'); + }); + + it('supports React components {min: true}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.Set([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.Set [Hello World]', {min: true}); + }); + + it('supports React components {min: false}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.Set([reactComponent, reactComponent])) + .toPrettyPrintTo('Immutable.Set [\n \n Hello World\n ,\n]'); + }); +}); + +describe('Immutable.Map plugin', () => { + it('supports an empty set', () => { + expect(Immutable.Map({})) + .toPrettyPrintTo('Immutable.Map {}', {min: true}); + }); + + it('supports an object with single key', () => { + expect(Immutable.Map({a: 1})) + .toPrettyPrintTo('Immutable.Map {a: 1}', {min: true}); + }); + + it('supports an object with multiple keys {min: true}', () => { + expect(Immutable.Map({a: 1, b: 2, c: 3})) + .toPrettyPrintTo('Immutable.Map {a: 1, b: 2, c: 3}', {min: true}); + }); + + it('supports an object with multiple keys {min: false}', () => { + expect(Immutable.Map({a: 1, b: 2, c: 3})) + .toPrettyPrintTo('Immutable.Map {\n a: 1,\n b: 2,\n c: 3,\n}'); + }); + + it('supports object elements {min: true}', () => { + expect(Immutable.Map({key: {a: 1, b: 2, c: 3}})) + .toPrettyPrintTo('Immutable.Map {key: {\"a\": 1, \"b\": 2, \"c\": 3}}', {min: true}); + }); + + it('supports object elements {min: false}', () => { + expect(Immutable.Map({key: {a: 1, b: 2, c: 3}})) + .toPrettyPrintTo('Immutable.Map {\n key: Object {\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n },\n}'); + }); + + it('supports React components {min: true}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.Map({a: reactComponent, b: reactComponent})) + .toPrettyPrintTo('Immutable.Map {a: Hello World, b: Hello World}', {min: true}); + }); + + it('supports React components {min: false}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.Map({a: reactComponent, b: reactComponent})) + .toPrettyPrintTo('Immutable.Map {\n a: \n Hello World\n ,\n b: \n Hello World\n ,\n}'); + }); +}); + +describe('Immutable.OrderedMap plugin', () => { + it('supports an empty set', () => { + expect(Immutable.OrderedMap({})) + .toPrettyPrintTo('Immutable.OrderedMap {}', {min: true}); + }); + + it('supports an object with single key', () => { + expect(Immutable.OrderedMap({a: 1})) + .toPrettyPrintTo('Immutable.OrderedMap {a: 1}', {min: true}); + }); + + it('supports an object with multiple keys {min: true}', () => { + expect(Immutable.OrderedMap({a: 1, b: 2, c: 3})) + .toPrettyPrintTo('Immutable.OrderedMap {a: 1, b: 2, c: 3}', {min: true}); + }); + + it('supports an object with multiple keys {min: false}', () => { + expect(Immutable.OrderedMap({a: 1, b: 2, c: 3})) + .toPrettyPrintTo('Immutable.OrderedMap {\n a: 1,\n b: 2,\n c: 3,\n}'); + }); + + it('supports object elements {min: true}', () => { + expect(Immutable.OrderedMap({key: {a: 1, b: 2, c: 3}})) + .toPrettyPrintTo('Immutable.OrderedMap {key: {\"a\": 1, \"b\": 2, \"c\": 3}}', {min: true}); + }); + + it('supports object elements {min: false}', () => { + expect(Immutable.OrderedMap({key: {a: 1, b: 2, c: 3}})) + .toPrettyPrintTo('Immutable.OrderedMap {\n key: Object {\n \"a\": 1,\n \"b\": 2,\n \"c\": 3,\n },\n}'); + }); + + it('supports React components {min: true}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.OrderedMap({a: reactComponent, b: reactComponent})) + .toPrettyPrintTo('Immutable.OrderedMap {a: Hello World, b: Hello World}', {min: true}); + }); + + it('supports React components {min: false}', () => { + const reactComponent = React.createElement('Mouse', null, 'Hello World'); + expect(Immutable.OrderedMap({a: reactComponent, b: reactComponent})) + .toPrettyPrintTo('Immutable.OrderedMap {\n a: \n Hello World\n ,\n b: \n Hello World\n ,\n}'); + }); +}); diff --git a/packages/pretty-format/src/plugins/ImmutableList.js b/packages/pretty-format/src/plugins/ImmutableList.js new file mode 100644 index 000000000000..69854ceb4a6a --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutableList.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const printImmutable = require('./printImmutable'); +const IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@'; + +const isList = (maybeList: Object) => { + return !!(maybeList && maybeList[IS_LIST_SENTINEL]); +}; + +const test = (object: Object) => object && isList(object); + +const print = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object +) => { + return printImmutable(val, print, indent, opts, colors, 'List', false); +}; + +module.exports = {print, test}; diff --git a/packages/pretty-format/src/plugins/ImmutableMap.js b/packages/pretty-format/src/plugins/ImmutableMap.js new file mode 100644 index 000000000000..092b0b630b75 --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutableMap.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const printImmutable = require('./printImmutable'); +const IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@'; + +const isMap = (maybeMap: Object) => { + return !!(maybeMap && maybeMap[IS_MAP_SENTINEL]); +}; + +const test = (object: Object) => object && isMap(object); + +const print = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object +) => { + return printImmutable(val, print, indent, opts, colors, 'Map', true); +}; + +module.exports = {print, test}; diff --git a/packages/pretty-format/src/plugins/ImmutableOrderedMap.js b/packages/pretty-format/src/plugins/ImmutableOrderedMap.js new file mode 100644 index 000000000000..6f01ee9cc23f --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutableOrderedMap.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const printImmutable = require('./printImmutable'); +const IS_MAP_SENTINEL = '@@__IMMUTABLE_MAP__@@'; +const IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@'; + +const isMap = (maybeMap: Object) => { + return !!(maybeMap && maybeMap[IS_MAP_SENTINEL]); +}; + +const isOrdered = (maybeOrdered: Object) => { + return !!(maybeOrdered && maybeOrdered[IS_ORDERED_SENTINEL]); +}; + +const isOrderedMap = (maybeOrderedMap: Object) => { + return isMap(maybeOrderedMap) && isOrdered(maybeOrderedMap); +}; + +const test = (object: Object) => object && isOrderedMap(object); + +const print = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object +) => { + return printImmutable(val, print, indent, opts, colors, 'OrderedMap', true); +}; + +module.exports = {print, test}; diff --git a/packages/pretty-format/src/plugins/ImmutableOrderedSet.js b/packages/pretty-format/src/plugins/ImmutableOrderedSet.js new file mode 100644 index 000000000000..3b158bc85ef7 --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutableOrderedSet.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const printImmutable = require('./printImmutable'); +const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@'; +const IS_ORDERED_SENTINEL = '@@__IMMUTABLE_ORDERED__@@'; + +const isSet = (maybeSet: Object) => { + return !!(maybeSet && maybeSet[IS_SET_SENTINEL]); +}; + +const isOrdered = (maybeOrdered: Object) => { + return !!(maybeOrdered && maybeOrdered[IS_ORDERED_SENTINEL]); +}; + +const isOrderedSet = (maybeOrderedSet: Object) => { + return isSet(maybeOrderedSet) && isOrdered(maybeOrderedSet); +}; + +const test = (object: Object) => object && isOrderedSet(object); + +const print = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object +) => { + return printImmutable(val, print, indent, opts, colors, 'OrderedSet', false); +}; + +module.exports = {print, test}; diff --git a/packages/pretty-format/src/plugins/ImmutablePlugins.js b/packages/pretty-format/src/plugins/ImmutablePlugins.js new file mode 100644 index 000000000000..4d6d73bcc28d --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutablePlugins.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const ImmutableOrderedSetPlugin = require('./ImmutableOrderedSet'); +const ImmutableListPlugin = require('./ImmutableList'); +const ImmutableMapPlugin = require('./ImmutableMap'); +const ImmutableOrderedMapPlugin = require('./ImmutableOrderedMap'); +const ImmutableSetPlugin = require('./ImmutableSet'); +const ImmutableStackPlugin = require('./ImmutableStack'); + +module.exports = [ + ImmutableOrderedSetPlugin, + ImmutableListPlugin, + ImmutableOrderedMapPlugin, + ImmutableMapPlugin, + ImmutableSetPlugin, + ImmutableStackPlugin, +]; diff --git a/packages/pretty-format/src/plugins/ImmutableSet.js b/packages/pretty-format/src/plugins/ImmutableSet.js new file mode 100644 index 000000000000..f9222c83ae63 --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutableSet.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const printImmutable = require('./printImmutable'); +const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@'; + +const isSet = (maybeSet: Object) => { + return !!(maybeSet && maybeSet[IS_SET_SENTINEL]); +}; + +const test = (object: Object) => object && isSet(object); + +const print = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object +) => { + return printImmutable(val, print, indent, opts, colors, 'Set', false); +}; + +module.exports = {print, test}; diff --git a/packages/pretty-format/src/plugins/ImmutableStack.js b/packages/pretty-format/src/plugins/ImmutableStack.js new file mode 100644 index 000000000000..be13c944fc2e --- /dev/null +++ b/packages/pretty-format/src/plugins/ImmutableStack.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const printImmutable = require('./printImmutable'); +const IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@'; + +const isStack = (maybeStack: Object) => { + return !!(maybeStack && maybeStack[IS_STACK_SENTINEL]); +}; + +const test = (object: Object) => object && isStack(object); + +const print = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object +) => { + return printImmutable(val, print, indent, opts, colors, 'Stack', false); +}; + +module.exports = {print, test}; diff --git a/packages/pretty-format/src/plugins/printImmutable.js b/packages/pretty-format/src/plugins/printImmutable.js new file mode 100644 index 000000000000..e34725ecfff9 --- /dev/null +++ b/packages/pretty-format/src/plugins/printImmutable.js @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * 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. + * @flow + */ + +'use strict'; + +const IMMUTABLE_NAMESPACE = 'Immutable.'; +const SPACE = ' '; + +const addKey = (isMap: boolean, key: any) => { + return isMap ? (key + ': ') : ''; +}; + +const addFinalEdgeSpacing = (length: number, edgeSpacing: string) => { + return length > 0 ? edgeSpacing : ''; +}; + +const printImmutable = ( + val: Object, + print: Function, + indent: Function, + opts: Object, + colors: Object, + immutableDataStructureName: string, + isMap: boolean, +) : string => { + const openTag = isMap ? '{' : '['; + const closeTag = isMap ? '}' : ']'; + let result = IMMUTABLE_NAMESPACE + immutableDataStructureName + + SPACE + openTag + opts.edgeSpacing; + + const immutableArray = []; + val.forEach((item: any, key: any) => { + immutableArray.push( + indent(addKey(isMap, key) + print(item, print, indent, opts, colors)) + ); + }); + + if (!opts.min && immutableArray.length > 0) { + result += immutableArray.join(',' + opts.spacing) + ','; + } else { + result += immutableArray.join(',' + opts.spacing); + } + + return result + + addFinalEdgeSpacing(immutableArray.length, opts.edgeSpacing) + + closeTag; +}; + +module.exports = printImmutable; diff --git a/yarn.lock b/yarn.lock index 303583c3a628..b68ea71f82cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1171,6 +1171,10 @@ ignore@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.2.tgz#1c51e1ef53bab6ddc15db4d9ac4ec139eceb3410" +immutable@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"