From 441f90db38e1b0c324e8d83072820359f413406c Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 24 Dec 2018 00:13:06 +0100 Subject: [PATCH 1/5] convert pretty-format to typescript --- jest.config.js | 2 +- .../jest-circus/src/formatNodeAssertErrors.js | 1 + packages/jest-circus/src/utils.js | 1 + packages/pretty-format/package.json | 5 + ...cher.test.js => AsymmetricMatcher.test.ts} | 9 +- ...onvertAnsi.test.js => ConvertAnsi.test.ts} | 8 +- ...llection.test.js => DOMCollection.test.ts} | 12 +- ...{DOMElement.test.js => DOMElement.test.ts} | 9 +- .../{Immutable.test.js => Immutable.test.ts} | 25 ++-- ...react.test.js.snap => react.test.tsx.snap} | 0 .../src/__tests__/getPrettyPrint.js | 48 ------- ...ttyFormat.test.js => prettyFormat.test.ts} | 41 +++--- .../{react.test.js => react.test.tsx} | 31 +++-- .../src/__tests__/setPrettyPrint.ts | 56 +++++++++ .../src/{collections.js => collections.ts} | 15 ++- .../pretty-format/src/{index.js => index.ts} | 37 +++--- ...mmetricMatcher.js => AsymmetricMatcher.ts} | 8 +- .../{ConvertAnsi.js => ConvertAnsi.ts} | 17 ++- .../{DOMCollection.js => DOMCollection.ts} | 10 +- .../plugins/{DOMElement.js => DOMElement.ts} | 80 ++++++------ .../plugins/{Immutable.js => Immutable.ts} | 14 +-- .../{ReactElement.js => ReactElement.ts} | 16 +-- ...TestComponent.js => ReactTestComponent.ts} | 28 +++-- .../lib/{escapeHTML.js => escapeHTML.ts} | 2 - .../src/plugins/lib/{markup.js => markup.ts} | 6 +- packages/pretty-format/src/types.ts | 117 ++++++++++++++++++ packages/pretty-format/tsconfig.json | 7 ++ yarn.lock | 30 +++++ 28 files changed, 392 insertions(+), 243 deletions(-) rename packages/pretty-format/src/__tests__/{AsymmetricMatcher.test.js => AsymmetricMatcher.test.ts} (98%) rename packages/pretty-format/src/__tests__/{ConvertAnsi.test.js => ConvertAnsi.test.ts} (94%) rename packages/pretty-format/src/__tests__/{DOMCollection.test.js => DOMCollection.test.ts} (94%) rename packages/pretty-format/src/__tests__/{DOMElement.test.js => DOMElement.test.ts} (98%) rename packages/pretty-format/src/__tests__/{Immutable.test.js => Immutable.test.ts} (98%) rename packages/pretty-format/src/__tests__/__snapshots__/{react.test.js.snap => react.test.tsx.snap} (100%) delete mode 100644 packages/pretty-format/src/__tests__/getPrettyPrint.js rename packages/pretty-format/src/__tests__/{prettyFormat.test.js => prettyFormat.test.ts} (97%) rename packages/pretty-format/src/__tests__/{react.test.js => react.test.tsx} (97%) create mode 100644 packages/pretty-format/src/__tests__/setPrettyPrint.ts rename packages/pretty-format/src/{collections.js => collections.ts} (93%) rename packages/pretty-format/src/{index.js => index.ts} (95%) rename packages/pretty-format/src/plugins/{AsymmetricMatcher.js => AsymmetricMatcher.ts} (93%) rename packages/pretty-format/src/plugins/{ConvertAnsi.js => ConvertAnsi.ts} (84%) rename packages/pretty-format/src/plugins/{DOMCollection.js => DOMCollection.ts} (89%) rename packages/pretty-format/src/plugins/{DOMElement.js => DOMElement.ts} (58%) rename packages/pretty-format/src/plugins/{Immutable.js => Immutable.ts} (94%) rename packages/pretty-format/src/plugins/{ReactElement.js => ReactElement.ts} (90%) rename packages/pretty-format/src/plugins/{ReactTestComponent.js => ReactTestComponent.ts} (73%) rename packages/pretty-format/src/plugins/lib/{escapeHTML.js => escapeHTML.ts} (96%) rename packages/pretty-format/src/plugins/lib/{markup.js => markup.ts} (97%) create mode 100644 packages/pretty-format/src/types.ts create mode 100644 packages/pretty-format/tsconfig.json diff --git a/jest.config.js b/jest.config.js index 999b16dd01ca..db041ad091ae 100644 --- a/jest.config.js +++ b/jest.config.js @@ -38,7 +38,7 @@ module.exports = { '\\.snap$', '/packages/.*/build', '/packages/.*/build-es5', - '/packages/.*/src/__tests__/getPrettyPrint.js', + '/packages/.*/src/__tests__/setPrettyPrint.ts', '/packages/jest-cli/src/__tests__/test_root', '/packages/jest-cli/src/__tests__/__fixtures__/', '/packages/jest-cli/src/lib/__tests__/fixtures/', diff --git a/packages/jest-circus/src/formatNodeAssertErrors.js b/packages/jest-circus/src/formatNodeAssertErrors.js index a13caf678687..6434eee318a5 100644 --- a/packages/jest-circus/src/formatNodeAssertErrors.js +++ b/packages/jest-circus/src/formatNodeAssertErrors.js @@ -12,6 +12,7 @@ import type {Event, State} from 'types/Circus'; import {diff, printExpected, printReceived} from 'jest-matcher-utils'; import chalk from 'chalk'; +// $FlowFixMe: Converted to TS import prettyFormat from 'pretty-format'; type AssertionError = {| diff --git a/packages/jest-circus/src/utils.js b/packages/jest-circus/src/utils.js index e8c515478694..4f079ece8c6e 100644 --- a/packages/jest-circus/src/utils.js +++ b/packages/jest-circus/src/utils.js @@ -28,6 +28,7 @@ import co from 'co'; import StackUtils from 'stack-utils'; +// $FlowFixMe: Converted to TS import prettyFormat from 'pretty-format'; import {getState} from './state'; diff --git a/packages/pretty-format/package.json b/packages/pretty-format/package.json index c9d7fedc45b7..c90ad0715fcd 100644 --- a/packages/pretty-format/package.json +++ b/packages/pretty-format/package.json @@ -9,6 +9,7 @@ "license": "MIT", "description": "Stringify any JavaScript value.", "main": "build/index.js", + "types": "build/index.d.ts", "browser": "build-es5/index.js", "author": "James Kyle ", "dependencies": { @@ -18,7 +19,11 @@ "devDependencies": { "@types/ansi-regex": "^4.0.0", "@types/ansi-styles": "^3.2.1", + "@types/jest": "^24.0.0", + "@types/react": "*", + "@types/react-test-renderer": "*", "immutable": "4.0.0-rc.9", + "jest-diff": "^24.0.0", "react": "*", "react-dom": "*", "react-test-renderer": "*" diff --git a/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.js b/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts similarity index 98% rename from packages/pretty-format/src/__tests__/AsymmetricMatcher.test.js rename to packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts index 7e670e57e9d2..1a25400ca982 100644 --- a/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.js +++ b/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts @@ -3,17 +3,16 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {OptionsReceived} from 'types/PrettyFormat'; +import {OptionsReceived} from '../types'; + +import prettyFormat from '../'; -const prettyFormat = require('../'); const {AsymmetricMatcher} = prettyFormat.plugins; let options: OptionsReceived; -function fnNameFor(func) { +function fnNameFor(func: Function) { if (func.name) { return func.name; } diff --git a/packages/pretty-format/src/__tests__/ConvertAnsi.test.js b/packages/pretty-format/src/__tests__/ConvertAnsi.test.ts similarity index 94% rename from packages/pretty-format/src/__tests__/ConvertAnsi.test.js rename to packages/pretty-format/src/__tests__/ConvertAnsi.test.ts index f17208681dc1..c562f67a8123 100644 --- a/packages/pretty-format/src/__tests__/ConvertAnsi.test.js +++ b/packages/pretty-format/src/__tests__/ConvertAnsi.test.ts @@ -3,12 +3,12 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -const ansiStyle = require('ansi-styles'); -const prettyFormat = require('../'); +import ansiStyle from 'ansi-styles'; + +import prettyFormat from '../'; + const {ConvertAnsi} = prettyFormat.plugins; const prettyFormatResult = (val: string) => diff --git a/packages/pretty-format/src/__tests__/DOMCollection.test.js b/packages/pretty-format/src/__tests__/DOMCollection.test.ts similarity index 94% rename from packages/pretty-format/src/__tests__/DOMCollection.test.js rename to packages/pretty-format/src/__tests__/DOMCollection.test.ts index 6c08ba00308a..8cba5748f95b 100644 --- a/packages/pretty-format/src/__tests__/DOMCollection.test.js +++ b/packages/pretty-format/src/__tests__/DOMCollection.test.ts @@ -5,21 +5,15 @@ * LICENSE file in the root directory of this source tree. * * @jest-environment jsdom - * @flow */ /* eslint-env browser*/ -'use strict'; +import prettyFormat from '../'; +import setPrettyPrint from './setPrettyPrint'; -const prettyFormat = require('../'); const {DOMCollection, DOMElement} = prettyFormat.plugins; -const toPrettyPrintTo = require('./getPrettyPrint').default([ - DOMCollection, - DOMElement, -]); -const expect: any = global.expect; -expect.extend({toPrettyPrintTo}); +setPrettyPrint([DOMCollection, DOMElement]); describe('DOMCollection plugin for object properties', () => { it('supports DOMStringMap', () => { diff --git a/packages/pretty-format/src/__tests__/DOMElement.test.js b/packages/pretty-format/src/__tests__/DOMElement.test.ts similarity index 98% rename from packages/pretty-format/src/__tests__/DOMElement.test.js rename to packages/pretty-format/src/__tests__/DOMElement.test.ts index 074252ea0f77..b5e22f549c40 100644 --- a/packages/pretty-format/src/__tests__/DOMElement.test.js +++ b/packages/pretty-format/src/__tests__/DOMElement.test.ts @@ -5,18 +5,15 @@ * LICENSE file in the root directory of this source tree. * * @jest-environment jsdom - * @flow */ /* eslint-env browser*/ -'use strict'; +import prettyFormat from '../'; +import setPrettyPrint from './setPrettyPrint'; -const prettyFormat = require('../'); const {DOMElement} = prettyFormat.plugins; -const toPrettyPrintTo = require('./getPrettyPrint').default([DOMElement]); -const expect: any = global.expect; -expect.extend({toPrettyPrintTo}); +setPrettyPrint([DOMElement]); describe('pretty-format', () => { // Test is not related to plugin but is related to jsdom testing environment. diff --git a/packages/pretty-format/src/__tests__/Immutable.test.js b/packages/pretty-format/src/__tests__/Immutable.test.ts similarity index 98% rename from packages/pretty-format/src/__tests__/Immutable.test.js rename to packages/pretty-format/src/__tests__/Immutable.test.ts index e03b69dcc860..05c51241f804 100644 --- a/packages/pretty-format/src/__tests__/Immutable.test.js +++ b/packages/pretty-format/src/__tests__/Immutable.test.ts @@ -3,27 +3,22 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - import React from 'react'; import Immutable from 'immutable'; -import getPrettyPrint from './getPrettyPrint'; -const {Immutable: ImmutablePlugin, ReactElement} = require('..').plugins; +import setPrettyPrint from './setPrettyPrint'; +import prettyFormat from '..'; -const toPrettyPrintTo = getPrettyPrint([ReactElement, ImmutablePlugin]); +const {Immutable: ImmutablePlugin, ReactElement} = prettyFormat.plugins; -const expect = global.expect; -expect.extend({toPrettyPrintTo}); +setPrettyPrint([ReactElement, ImmutablePlugin]); it('does not incorrectly match identity-obj-proxy as Immutable object', () => { // SENTINEL constant is from https://github.com/facebook/immutable-js const IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@'; - const val = {}; + const val: any = {}; val[IS_ITERABLE_SENTINEL] = IS_ITERABLE_SENTINEL; // mock the mock object :) const expected = `{"${IS_ITERABLE_SENTINEL}": "${IS_ITERABLE_SENTINEL}"}`; expect(val).toPrettyPrintTo(expected, {min: true}); @@ -507,7 +502,7 @@ describe('Immutable.OrderedMap', () => { }); it('supports non-string keys', () => { - const val = Immutable.OrderedMap([ + const val = Immutable.OrderedMap([ [false, 'boolean'], ['false', 'string'], [0, 'number'], @@ -871,7 +866,7 @@ describe('Immutable.Seq', () => { }); it('supports a non-empty sequence from arguments', () => { - function returnArguments(...args) { + function returnArguments(..._args: Array) { return arguments; } expect(Immutable.Seq(returnArguments(0, 1, 2))).toPrettyPrintTo( @@ -933,7 +928,7 @@ describe('Immutable.Seq', () => { describe('Immutable.Seq lazy entries', () => { const expected = 'Immutable.Seq {…}'; const object = {key0: '', key1: '1'}; - const filterer = value => value.length !== 0; + const filterer = (value: string) => value.length !== 0; // undefined size confirms correct criteria for lazy Seq test('from object properties', () => { @@ -951,7 +946,7 @@ describe('Immutable.Seq lazy entries', () => { describe('Immutable.Seq lazy values', () => { const expected = 'Immutable.Seq […]'; const array = ['', '1', '22']; - const filterer = item => item.length !== 0; + const filterer = (item: string) => item.length !== 0; test('from Immutable.Range', () => { const val = Immutable.Range(1, Infinity); @@ -961,7 +956,7 @@ describe('Immutable.Seq lazy values', () => { // undefined size confirms correct criteria for lazy Seq test('from iterator', () => { - function returnIterator(values) { + function returnIterator(values: Array) { let i = 0; return { next() { diff --git a/packages/pretty-format/src/__tests__/__snapshots__/react.test.js.snap b/packages/pretty-format/src/__tests__/__snapshots__/react.test.tsx.snap similarity index 100% rename from packages/pretty-format/src/__tests__/__snapshots__/react.test.js.snap rename to packages/pretty-format/src/__tests__/__snapshots__/react.test.tsx.snap diff --git a/packages/pretty-format/src/__tests__/getPrettyPrint.js b/packages/pretty-format/src/__tests__/getPrettyPrint.js deleted file mode 100644 index 3eae13b07dbc..000000000000 --- a/packages/pretty-format/src/__tests__/getPrettyPrint.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -'use strict'; - -import type {OptionsReceived, Plugins} from 'types/PrettyFormat'; - -const diff = require('jest-diff'); -const prettyFormat = require('../'); - -const getPrettyPrint = (plugins: Plugins) => - function(received: any, expected: any, options?: OptionsReceived) { - const prettyFormatted = prettyFormat(received, {plugins, ...options}); - 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') + - '\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}; - }; - -export default getPrettyPrint; diff --git a/packages/pretty-format/src/__tests__/prettyFormat.test.js b/packages/pretty-format/src/__tests__/prettyFormat.test.ts similarity index 97% rename from packages/pretty-format/src/__tests__/prettyFormat.test.js rename to packages/pretty-format/src/__tests__/prettyFormat.test.ts index 339252ee9be2..779d3c45a754 100644 --- a/packages/pretty-format/src/__tests__/prettyFormat.test.js +++ b/packages/pretty-format/src/__tests__/prettyFormat.test.ts @@ -3,21 +3,18 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - -const prettyFormat = require('../'); +import prettyFormat from '../'; -function returnArguments(...args) { +function returnArguments(..._args: Array) { return arguments; } class MyArray extends Array {} -function MyObject(value) { +function MyObject(value: unknown) { + // @ts-ignore this.name = value; } @@ -33,7 +30,7 @@ describe('prettyFormat()', () => { }); it('prints an empty array', () => { - const val = []; + const val: never[] = []; expect(prettyFormat(val)).toEqual('Array []'); }); @@ -94,7 +91,7 @@ describe('prettyFormat()', () => { it('prints an anonymous callback function', () => { let val; - function f(cb) { + function f(cb: () => void) { val = cb; } f(() => {}); @@ -159,7 +156,7 @@ describe('prettyFormat()', () => { }); it('prints a map with non-string keys', () => { - const val = new Map([ + const val = new Map([ [false, 'boolean'], ['false', 'string'], [0, 'number'], @@ -416,7 +413,7 @@ describe('prettyFormat()', () => { }); it('prints circular references', () => { - const val = {}; + const val: any = {}; val.prop = val; expect(prettyFormat(val)).toEqual('Object {\n "prop": [Circular],\n}'); }); @@ -488,6 +485,7 @@ describe('prettyFormat()', () => { 'map non-empty': new Map([['name', 'value']]), 'object literal empty': {}, 'object literal non-empty': {name: 'value'}, + // @ts-ignore 'object with constructor': new MyObject('value'), 'object without constructor': Object.create(null), 'set empty': new Set(), @@ -519,13 +517,13 @@ describe('prettyFormat()', () => { it('throws on invalid options', () => { expect(() => { - // $FlowFixMe + // @ts-ignore prettyFormat({}, {invalidOption: true}); }).toThrow(); }); it('supports plugins', () => { - function Foo() {} + class Foo {} expect( prettyFormat(new Foo(), { @@ -548,10 +546,10 @@ describe('prettyFormat()', () => { const options = { plugins: [ { - print(val) { + print(val: any) { return val.payload; }, - test(val) { + test(val: any) { return val && typeof val.payload === 'string'; }, }, @@ -565,7 +563,7 @@ describe('prettyFormat()', () => { const options = { plugins: [ { - print(val) { + print(val: any) { return val; }, test() { @@ -646,7 +644,7 @@ describe('prettyFormat()', () => { plugins: [ { print(val, print) { - return val.map(item => print(item)).join(' - '); + return val.map((item: any) => print(item)).join(' - '); }, test(val) { return Array.isArray(val); @@ -663,7 +661,7 @@ describe('prettyFormat()', () => { prettyFormat(val, { plugins: [ { - print(val, print) { + print(_val, _print) { return '[called]'; }, test(val) { @@ -728,7 +726,7 @@ describe('prettyFormat()', () => { it('calls toJSON on Sets', () => { const set = new Set([1]); - (set: Object).toJSON = () => 'map'; + (set as any).toJSON = () => 'map'; expect(prettyFormat(set)).toEqual('"map"'); }); @@ -736,7 +734,7 @@ describe('prettyFormat()', () => { const value = {apple: 'banana', toJSON: jest.fn(() => '1')}; const name = value.toJSON.name || 'anonymous'; const set = new Set([value]); - (set: Object).toJSON = jest.fn(() => 'map'); + (set as any).toJSON = jest.fn(() => 'map'); expect( prettyFormat(set, { callToJSON: false, @@ -746,7 +744,7 @@ describe('prettyFormat()', () => { name + '],\n },\n}', ); - expect((set: Object).toJSON).not.toBeCalled(); + expect((set as any).toJSON).not.toBeCalled(); expect(value.toJSON).not.toBeCalled(); }); @@ -787,6 +785,7 @@ describe('prettyFormat()', () => { 'map non-empty': new Map([['name', 'value']]), 'object literal empty': {}, 'object literal non-empty': {name: 'value'}, + // @ts-ignore 'object with constructor': new MyObject('value'), 'object without constructor': Object.create(null), 'set empty': new Set(), diff --git a/packages/pretty-format/src/__tests__/react.test.js b/packages/pretty-format/src/__tests__/react.test.tsx similarity index 97% rename from packages/pretty-format/src/__tests__/react.test.js rename to packages/pretty-format/src/__tests__/react.test.tsx index 6a268319cf99..44d33d4b083e 100644 --- a/packages/pretty-format/src/__tests__/react.test.js +++ b/packages/pretty-format/src/__tests__/react.test.tsx @@ -3,20 +3,17 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {OptionsReceived} from 'types/PrettyFormat'; +import React from 'react'; +import renderer from 'react-test-renderer'; -const React = require('react'); -const renderer = require('react-test-renderer'); +import prettyFormat from '..'; +import {OptionsReceived} from '../types'; const elementSymbol = Symbol.for('react.element'); const fragmentSymbol = Symbol.for('react.fragment'); const testSymbol = Symbol.for('react.test.json'); - -const prettyFormat = require('..'); const {ReactElement, ReactTestComponent} = prettyFormat.plugins; const formatElement = (element: any, options?: OptionsReceived) => @@ -116,7 +113,9 @@ test('supports props with numbers', () => { test('supports a single element with a function prop', () => { assertPrintedJSX( - React.createElement('Mouse', {onclick: function onclick() {}}), + React.createElement<{onclick: any}>('Mouse', { + onclick: function onclick() {}, + }), '', ); }); @@ -141,7 +140,7 @@ test('supports an element with and object prop and children', () => { test('supports an element with complex props and mixed children', () => { assertPrintedJSX( - React.createElement( + React.createElement<{customProp: any; onclick: any}>( 'Mouse', {customProp: {one: '1', two: 2}, onclick: function onclick() {}}, 'HELLO', @@ -167,11 +166,11 @@ test('escapes children properly', () => { test('supports everything all together', () => { assertPrintedJSX( - React.createElement( + React.createElement<{customProp: any; onclick: any}>( 'Mouse', {customProp: {one: '1', two: 2}, onclick: function onclick() {}}, 'HELLO', - React.createElement( + React.createElement<{customProp: any; onclick: any}>( 'Mouse', {customProp: {one: '1', two: 2}, onclick: function onclick() {}}, 'HELLO', @@ -266,7 +265,7 @@ test('supports a single element with custom React elements with props (using ano }); test('supports a single element with custom React elements with a child', () => { - function Cat(props) { + function Cat(props: any) { return React.createElement('div', props); } assertPrintedJSX( @@ -565,7 +564,7 @@ describe('maxDepth option', () => { test('min option', () => { assertPrintedJSX( - React.createElement( + React.createElement<{customProp: any; onclick: any}>( 'Mouse', {customProp: {one: '1', two: 2}, onclick: function onclick() {}}, 'HELLO', @@ -622,9 +621,9 @@ test('throws if theme option is null', () => { 'Hello, Mouse!', ); expect(() => { + // @ts-ignore formatElement(jsx, { highlight: true, - // $FlowFixMe theme: null, }); }).toThrow('pretty-format: Option "theme" must not be null.'); @@ -637,9 +636,9 @@ test('throws if theme option is not of type "object"', () => { {style: 'color:red'}, 'Hello, Mouse!', ); + // @ts-ignore formatElement(jsx, { highlight: true, - // $FlowFixMe theme: 'beautiful', }); }).toThrow( @@ -701,7 +700,7 @@ test('ReactTestComponent plugin highlights syntax with color from theme option', }); test('supports forwardRef with a child', () => { - function Cat(props) { + function Cat(props: any) { return React.createElement('div', props, props.children); } diff --git a/packages/pretty-format/src/__tests__/setPrettyPrint.ts b/packages/pretty-format/src/__tests__/setPrettyPrint.ts new file mode 100644 index 000000000000..4a8a562bf52b --- /dev/null +++ b/packages/pretty-format/src/__tests__/setPrettyPrint.ts @@ -0,0 +1,56 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// @ts-ignore +import diff from 'jest-diff'; + +import prettyFormat from '../'; +import {OptionsReceived, Plugins} from '../types'; + +declare global { + namespace jest { + interface Matchers { + toPrettyPrintTo(expected: any, options?: OptionsReceived): R; + } + } +} + +const setPrettyPrint = (plugins: Plugins) => { + expect.extend({ + toPrettyPrintTo(received: any, expected: any, options?: OptionsReceived) { + const prettyFormatted = prettyFormat(received, {plugins, ...options}); + 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') + + '\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}; + }, + }); +}; + +export default setPrettyPrint; diff --git a/packages/pretty-format/src/collections.js b/packages/pretty-format/src/collections.ts similarity index 93% rename from packages/pretty-format/src/collections.js rename to packages/pretty-format/src/collections.ts index ec0478b488f3..28112d1117b5 100644 --- a/packages/pretty-format/src/collections.js +++ b/packages/pretty-format/src/collections.ts @@ -4,17 +4,16 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow */ -import type {Config, Printer, Refs} from 'types/PrettyFormat'; +import {Config, Printer, Refs} from './types'; const getKeysOfEnumerableProperties = (object: Object) => { - const keys = Object.keys(object).sort(); + const keys: Array = Object.keys(object).sort(); if (Object.getOwnPropertySymbols) { Object.getOwnPropertySymbols(object).forEach(symbol => { - //$FlowFixMe because property enumerable is missing in undefined + // @ts-ignore: because property enumerable is missing in undefined if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) { keys.push(symbol); } @@ -180,7 +179,13 @@ export function printObjectProperties( for (let i = 0; i < keys.length; i++) { const key = keys[i]; const name = printer(key, config, indentationNext, depth, refs); - const value = printer(val[key], config, indentationNext, depth, refs); + const value = printer( + (val as any)[key], + config, + indentationNext, + depth, + refs, + ); result += indentationNext + name + ': ' + value; diff --git a/packages/pretty-format/src/index.js b/packages/pretty-format/src/index.ts similarity index 95% rename from packages/pretty-format/src/index.js rename to packages/pretty-format/src/index.ts index bea132820a4e..6b9858e3dae6 100644 --- a/packages/pretty-format/src/index.js +++ b/packages/pretty-format/src/index.ts @@ -3,23 +3,20 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type { +import style from 'ansi-styles'; +import { Colors, Config, Options, OptionsReceived, + NewPlugin, Plugin, Plugins, Refs, - StringOrNull, Theme, -} from 'types/PrettyFormat'; - -import style from 'ansi-styles'; +} from './types'; import { printIteratorEntries, @@ -44,18 +41,18 @@ const symbolToString = Symbol.prototype.toString; // Explicitly comparing typeof constructor to function avoids undefined as name // when mock identity-obj-proxy returns the key as the value for any key. -const getConstructorName = val => +const getConstructorName = (val: any) => (typeof val.constructor === 'function' && val.constructor.name) || 'Object'; // Is val is equal to global window object? Works even if it does not exist :) /* global window */ -const isWindow = val => typeof window !== 'undefined' && val === window; +const isWindow = (val: any) => typeof window !== 'undefined' && val === window; const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/; const NEWLINE_REGEXP = /\n/gi; class PrettyFormatPluginError extends Error { - constructor(message, stack) { + constructor(message: string, stack: string) { super(message); this.stack = stack; this.name = this.constructor.name; @@ -103,7 +100,7 @@ function printBasicValue( printFunctionName: boolean, escapeRegex: boolean, escapeString: boolean, -): StringOrNull { +): string | null { if (val === true || val === false) { return '' + val; } @@ -254,6 +251,10 @@ function printComplexValue( '}'; } +function isNewPlugin(plugin: Plugin): plugin is NewPlugin { + return (plugin as NewPlugin).serialize != null; +} + function printPlugin( plugin: Plugin, val: any, @@ -265,7 +266,7 @@ function printPlugin( let printed; try { - printed = plugin.serialize + printed = isNewPlugin(plugin) ? plugin.serialize(val, config, indentation, depth, refs, printer) : plugin.print( val, @@ -392,13 +393,12 @@ function validateOptions(options: OptionsReceived) { } const getColorsHighlight = (options: OptionsReceived): Colors => - // $FlowFixMe: Flow thinks keys from `Colors` are missing from `DEFAULT_THEME_KEYS` DEFAULT_THEME_KEYS.reduce((colors, key) => { const value = - options.theme && options.theme[key] !== undefined - ? options.theme[key] - : DEFAULT_THEME[key]; - const color = style[value]; + options.theme && (options.theme as any)[key] !== undefined + ? (options.theme as any)[key] + : (DEFAULT_THEME as any)[key]; + const color = (style as any)[value]; if ( color && typeof color.close === 'string' && @@ -414,7 +414,6 @@ const getColorsHighlight = (options: OptionsReceived): Colors => }, Object.create(null)); const getColorsEmpty = (): Colors => - // $FlowFixMe: Flow thinks keys from `Colors` are missing from `DEFAULT_THEME_KEYS` DEFAULT_THEME_KEYS.reduce((colors, key) => { colors[key] = {close: '', open: ''}; return colors; @@ -506,4 +505,4 @@ prettyFormat.plugins = { ReactTestComponent, }; -module.exports = prettyFormat; +export = prettyFormat; diff --git a/packages/pretty-format/src/plugins/AsymmetricMatcher.js b/packages/pretty-format/src/plugins/AsymmetricMatcher.ts similarity index 93% rename from packages/pretty-format/src/plugins/AsymmetricMatcher.js rename to packages/pretty-format/src/plugins/AsymmetricMatcher.ts index 3d6376c732fe..83fe8a7cf4d6 100644 --- a/packages/pretty-format/src/plugins/AsymmetricMatcher.js +++ b/packages/pretty-format/src/plugins/AsymmetricMatcher.ts @@ -3,11 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; +import {Config, NewPlugin, Printer, Refs} from '../types'; import {printListItems, printObjectProperties} from '../collections'; @@ -90,4 +88,6 @@ export const serialize = ( export const test = (val: any) => val && val.$$typeof === asymmetricMatcher; -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/ConvertAnsi.js b/packages/pretty-format/src/plugins/ConvertAnsi.ts similarity index 84% rename from packages/pretty-format/src/plugins/ConvertAnsi.js rename to packages/pretty-format/src/plugins/ConvertAnsi.ts index b974b47aef88..5a673342ce0d 100644 --- a/packages/pretty-format/src/plugins/ConvertAnsi.js +++ b/packages/pretty-format/src/plugins/ConvertAnsi.ts @@ -3,17 +3,14 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, Printer, NewPlugin, Refs} from 'types/PrettyFormat'; - import ansiRegex from 'ansi-regex'; import style from 'ansi-styles'; +import {Config, Printer, NewPlugin, Refs} from '../types'; -const toHumanReadableAnsi = text => - text.replace(ansiRegex(), (match, offset, string) => { +const toHumanReadableAnsi = (text: string) => + text.replace(ansiRegex(), match => { switch (match) { case style.red.close: case style.green.close: @@ -59,8 +56,8 @@ const toHumanReadableAnsi = text => } }); -export const test = (val: any) => - typeof val === 'string' && val.match(ansiRegex()); +export const test = (val: any): boolean => + typeof val === 'string' && !!val.match(ansiRegex()); export const serialize = ( val: string, @@ -71,4 +68,6 @@ export const serialize = ( printer: Printer, ) => printer(toHumanReadableAnsi(val), config, indentation, depth, refs); -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/DOMCollection.js b/packages/pretty-format/src/plugins/DOMCollection.ts similarity index 89% rename from packages/pretty-format/src/plugins/DOMCollection.js rename to packages/pretty-format/src/plugins/DOMCollection.ts index b45975022286..e922cc1bd9f9 100644 --- a/packages/pretty-format/src/plugins/DOMCollection.js +++ b/packages/pretty-format/src/plugins/DOMCollection.ts @@ -3,11 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; +import {Config, NewPlugin, Printer, Refs} from '../types'; import {printListItems, printObjectProperties} from '../collections'; @@ -26,7 +24,7 @@ export const test = (val: any) => testName(val.constructor.name); // Convert array of attribute objects to props object. -const propsReducer = (props, attribute) => { +const propsReducer = (props: any, attribute: any) => { props[attribute.name] = attribute.value; return props; }; @@ -72,4 +70,6 @@ export const serialize = ( ); }; -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/DOMElement.js b/packages/pretty-format/src/plugins/DOMElement.ts similarity index 58% rename from packages/pretty-format/src/plugins/DOMElement.js rename to packages/pretty-format/src/plugins/DOMElement.ts index f9e86164ad15..03546fb210fb 100644 --- a/packages/pretty-format/src/plugins/DOMElement.js +++ b/packages/pretty-format/src/plugins/DOMElement.ts @@ -3,11 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; +import {Config, NewPlugin, Printer, Refs} from '../types'; import { printChildren, @@ -18,30 +16,6 @@ import { printText, } from './lib/markup'; -type Attribute = { - name: string, - value: string, -}; - -type Element = { - attributes: Array, - childNodes: Array, - nodeType: 1, - tagName: string, -}; -type Text = { - data: string, - nodeType: 3, -}; -type Comment = { - data: string, - nodeType: 8, -}; -type DocumentFragment = { - children: Array, - nodeType: 11, -}; - const ELEMENT_NODE = 1; const TEXT_NODE = 3; const COMMENT_NODE = 8; @@ -61,33 +35,39 @@ export const test = (val: any) => val.constructor.name && testNode(val.nodeType, val.constructor.name); -// Convert array of attribute objects to keys array and props object. -const keysMapper = attribute => attribute.name; -const propsReducer = (props, attribute) => { - props[attribute.name] = attribute.value; - return props; -}; +type HandledType = Element | Text | Comment | DocumentFragment; + +function nodeIsText(node: HandledType): node is Text { + return node.nodeType === TEXT_NODE; +} + +function nodeIsComment(node: HandledType): node is Comment { + return node.nodeType === COMMENT_NODE; +} + +function nodeIsFragment(node: HandledType): node is DocumentFragment { + return node.nodeType === FRAGMENT_NODE; +} export const serialize = ( - node: Element | Text | Comment | DocumentFragment, + node: HandledType, config: Config, indentation: string, depth: number, refs: Refs, printer: Printer, ): string => { - if (node.nodeType === TEXT_NODE) { + if (nodeIsText(node)) { return printText(node.data, config); } - if (node.nodeType === COMMENT_NODE) { + if (nodeIsComment(node)) { return printComment(node.data, config); } - const type = - node.nodeType === FRAGMENT_NODE - ? `DocumentFragment` - : node.tagName.toLowerCase(); + const type = nodeIsFragment(node) + ? `DocumentFragment` + : node.tagName.toLowerCase(); if (++depth > config.maxDepth) { return printElementAsLeaf(type, config); @@ -96,8 +76,20 @@ export const serialize = ( return printElement( type, printProps( - Array.prototype.map.call(node.attributes || [], keysMapper).sort(), - Array.prototype.reduce.call(node.attributes || [], propsReducer, {}), + nodeIsFragment(node) + ? [] + : Array.from(node.attributes) + .map(attr => attr.name) + .sort(), + nodeIsFragment(node) + ? [] + : Array.from(node.attributes).reduce( + (props, attribute) => { + props[attribute.name] = attribute.value; + return props; + }, + {} as any, + ), config, indentation + config.indent, depth, @@ -117,4 +109,6 @@ export const serialize = ( ); }; -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/Immutable.js b/packages/pretty-format/src/plugins/Immutable.ts similarity index 94% rename from packages/pretty-format/src/plugins/Immutable.js rename to packages/pretty-format/src/plugins/Immutable.ts index 3814b7d832a0..85a415731a49 100644 --- a/packages/pretty-format/src/plugins/Immutable.js +++ b/packages/pretty-format/src/plugins/Immutable.ts @@ -3,11 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, Printer, NewPlugin, Refs} from 'types/PrettyFormat'; +import {Config, Printer, NewPlugin, Refs} from '../types'; import {printIteratorEntries, printIteratorValues} from '../collections'; // SENTINEL constants are from https://github.com/facebook/immutable-js @@ -21,8 +19,8 @@ const IS_SEQ_SENTINEL = '@@__IMMUTABLE_SEQ__@@'; const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@'; const IS_STACK_SENTINEL = '@@__IMMUTABLE_STACK__@@'; -const getImmutableName = name => 'Immutable.' + name; -const printAsLeaf = name => '[' + name + ']'; +const getImmutableName = (name: string) => 'Immutable.' + name; +const printAsLeaf = (name: string) => '[' + name + ']'; const SPACE = ' '; const LAZY = '…'; // Seq is lazy if it calls a method like filter @@ -52,7 +50,7 @@ const printImmutableEntries = ( // Record has an entries method because it is a collection in immutable v3. // Return an iterator for Immutable Record from version v3 or v4. -const getRecordEntries = val => { +const getRecordEntries = (val: any) => { let i = 0; return { next() { @@ -239,4 +237,6 @@ export const test = (val: any) => val && (val[IS_ITERABLE_SENTINEL] === true || val[IS_RECORD_SENTINEL] === true); -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/ReactElement.js b/packages/pretty-format/src/plugins/ReactElement.ts similarity index 90% rename from packages/pretty-format/src/plugins/ReactElement.js rename to packages/pretty-format/src/plugins/ReactElement.ts index eef452ce9525..aa05d4ebf72e 100644 --- a/packages/pretty-format/src/plugins/ReactElement.js +++ b/packages/pretty-format/src/plugins/ReactElement.ts @@ -3,11 +3,9 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; +import {Config, NewPlugin, Printer, Refs} from '../types'; import { printChildren, @@ -24,7 +22,7 @@ const contextSymbol = Symbol.for('react.context'); // Given element.props.children, or subtree during recursive traversal, // return flattened array of children. -const getChildren = (arg, children = []) => { +const getChildren = (arg: any[], children = []) => { if (Array.isArray(arg)) { arg.forEach(item => { getChildren(item, children); @@ -35,7 +33,7 @@ const getChildren = (arg, children = []) => { return children; }; -const getType = element => { +const getType = (element: any) => { const type = element.type; if (typeof type === 'string') { return type; @@ -66,7 +64,7 @@ const getType = element => { return 'UNDEFINED'; }; -const getPropKeys = element => { +const getPropKeys = (element: any) => { const {props} = element; return Object.keys(props) @@ -75,7 +73,7 @@ const getPropKeys = element => { }; export const serialize = ( - element: React$Element, + element: any, config: Config, indentation: string, depth: number, @@ -109,4 +107,6 @@ export const serialize = ( export const test = (val: any) => val && val.$$typeof === elementSymbol; -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/ReactTestComponent.js b/packages/pretty-format/src/plugins/ReactTestComponent.ts similarity index 73% rename from packages/pretty-format/src/plugins/ReactTestComponent.js rename to packages/pretty-format/src/plugins/ReactTestComponent.ts index 159602bd79b8..c380fbfc3e81 100644 --- a/packages/pretty-format/src/plugins/ReactTestComponent.js +++ b/packages/pretty-format/src/plugins/ReactTestComponent.ts @@ -3,17 +3,19 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type { - Config, - Printer, - NewPlugin, - ReactTestObject, - Refs, -} from 'types/PrettyFormat'; +import {Config, Printer, NewPlugin, Refs} from '../types'; + +export type ReactTestObject = { + $$typeof: Symbol; + type: string; + props?: Object; + children?: null | Array; +}; + +// Child can be `number` in Stack renderer but not in Fiber renderer. +type ReactTestChild = ReactTestObject | string | number; import { printChildren, @@ -24,12 +26,12 @@ import { const testSymbol = Symbol.for('react.test.json'); -const getPropKeys = object => { +const getPropKeys = (object: ReactTestObject) => { const {props} = object; return props ? Object.keys(props) - .filter(key => props[key] !== undefined) + .filter(key => (props as any)[key] !== undefined) .sort() : []; }; @@ -73,4 +75,6 @@ export const serialize = ( export const test = (val: any) => val && val.$$typeof === testSymbol; -export default ({serialize, test}: NewPlugin); +const plugin: NewPlugin = {serialize, test}; + +export default plugin; diff --git a/packages/pretty-format/src/plugins/lib/escapeHTML.js b/packages/pretty-format/src/plugins/lib/escapeHTML.ts similarity index 96% rename from packages/pretty-format/src/plugins/lib/escapeHTML.js rename to packages/pretty-format/src/plugins/lib/escapeHTML.ts index 2fd80a074e32..e4c17104269e 100644 --- a/packages/pretty-format/src/plugins/lib/escapeHTML.js +++ b/packages/pretty-format/src/plugins/lib/escapeHTML.ts @@ -3,8 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ export default function escapeHTML(str: string): string { diff --git a/packages/pretty-format/src/plugins/lib/markup.js b/packages/pretty-format/src/plugins/lib/markup.ts similarity index 97% rename from packages/pretty-format/src/plugins/lib/markup.js rename to packages/pretty-format/src/plugins/lib/markup.ts index ee346d73c6ef..c5ab6a786091 100644 --- a/packages/pretty-format/src/plugins/lib/markup.js +++ b/packages/pretty-format/src/plugins/lib/markup.ts @@ -3,18 +3,16 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -import type {Config, Printer, Refs} from 'types/PrettyFormat'; +import {Config, Printer, Refs} from '../../types'; import escapeHTML from './escapeHTML'; // Return empty string if keys is empty. export const printProps = ( keys: Array, - props: Object, + props: any, config: Config, indentation: string, depth: number, diff --git a/packages/pretty-format/src/types.ts b/packages/pretty-format/src/types.ts new file mode 100644 index 000000000000..89d06d5bd418 --- /dev/null +++ b/packages/pretty-format/src/types.ts @@ -0,0 +1,117 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +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}; +}; +type Indent = (arg0: string) => string; +export type Refs = Array; +type Print = (arg0: any) => string; + +export type Theme = { + comment: string; + content: string; + prop: string; + tag: string; + value: string; +}; + +type ThemeReceived = { + comment?: string; + content?: string; + prop?: string; + tag?: string; + value?: string; +}; + +export type Options = { + callToJSON: boolean; + escapeRegex: boolean; + escapeString: boolean; + highlight: boolean; + indent: number; + maxDepth: number; + min: boolean; + plugins: Plugins; + printFunctionName: boolean; + theme: Theme; +}; + +export type OptionsReceived = { + callToJSON?: boolean; + escapeRegex?: boolean; + escapeString?: boolean; + highlight?: boolean; + indent?: number; + maxDepth?: number; + min?: boolean; + plugins?: Plugins; + printFunctionName?: boolean; + theme?: ThemeReceived; +}; + +export type Config = { + callToJSON: boolean; + colors: Colors; + escapeRegex: boolean; + escapeString: boolean; + indent: string; + maxDepth: number; + min: boolean; + plugins: Plugins; + printFunctionName: boolean; + spacingInner: string; + spacingOuter: string; +}; + +export type Printer = ( + val: any, + config: Config, + indentation: string, + depth: number, + refs: Refs, + hasCalledToJSON?: boolean, +) => string; + +type Test = (arg0: any) => boolean; + +export type NewPlugin = { + serialize: ( + val: any, + config: Config, + indentation: string, + depth: number, + refs: Refs, + printer: Printer, + ) => string; + test: Test; +}; + +type PluginOptions = { + edgeSpacing: string; + min: boolean; + spacing: string; +}; + +type OldPlugin = { + print: ( + val: any, + print: Print, + indent: Indent, + options: PluginOptions, + colors: Colors, + ) => string; + test: Test; +}; + +export type Plugin = NewPlugin | OldPlugin; + +export type Plugins = Array; diff --git a/packages/pretty-format/tsconfig.json b/packages/pretty-format/tsconfig.json new file mode 100644 index 000000000000..7bb06bce6d20 --- /dev/null +++ b/packages/pretty-format/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + } +} diff --git a/yarn.lock b/yarn.lock index ffc57a710145..6b1c4ffc6978 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1640,6 +1640,11 @@ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.12.tgz#7e0ced251fa94c3bc2d1023d4b84b2992fa06376" integrity sha512-/kQvbVzdEpOq4tEWT79yAHSM4nH4xMlhJv2GrLVQt4Qmo8yYsPdioBM1QpN/2GX1wkfMnyXvdoftvLUr0LBj7Q== +"@types/jest@^24.0.0": + version "24.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.0.tgz#848492026c327b3548d92be0352a545c36a21e8a" + integrity sha512-kOafJnUTnMd7/OfEO/x3I47EHswNjn+dbz9qk3mtonr1RvKT+1FGVxnxAx08I9K8Tl7j9hpoJRE7OCf+t10fng== + "@types/jsdom@^11.12.0": version "11.12.0" resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-11.12.0.tgz#00ddc6f0a1b04c2f5ff6fb23eb59360ca65f12ae" @@ -1703,11 +1708,31 @@ resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-1.2.0.tgz#891e73f735ad5e82e8adae3a99424128e105fb62" integrity sha512-7JXpT2rSd4hqd2oBWU1wfEW6x6gX+qPH+gLzGEx+My3wcb67K9Rc02xNQRVn67phusmXm5Yqn4oTP2OW1G5zdQ== +"@types/prop-types@*": + version "15.5.8" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce" + integrity sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw== + "@types/q@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18" integrity sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA== +"@types/react-test-renderer@*": + version "16.0.3" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.0.3.tgz#cce5c983d66cc5c3582e7c2f44b274ab635a8acc" + integrity sha512-NWOAxVQeJxpXuNKgw83Hah0nquiw1nUexM9qY/Hk3a+XhZwgMtaa6GLA9E1TKMT75Odb3/KE/jiBO4enTuEJjQ== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "16.8.1" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.1.tgz#b431b104ecc6febda170b718caa9f50be66a6750" + integrity sha512-tD1ETKJcuhANOejRc/p7OgQ16DKnbGi0M3LccelKlPnUCDp2a5koVxZFoRN9HN+A+m84HB5VGN7I+r3nNhS3PA== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/resolve@*": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -4115,6 +4140,11 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" +csstype@^2.2.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.2.tgz#3043d5e065454579afc7478a18de41909c8a2f01" + integrity sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" From c0331c1814e6f5996f546296ba5c4ffb53c584bb Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 6 Feb 2019 10:20:36 +0100 Subject: [PATCH 2/5] changelog --- CHANGELOG.md | 1 + scripts/build.js | 4 +--- scripts/watch.js | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d039d87a4441..fa44400ddb21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Chore & Maintenance - `[*]`: Setup building, linting and testing of TypeScript ([#7808](https://github.com/facebook/jest/pull/7808)) +- `[pretty-format]`: Migrate to TypeScript ([#7809](https://github.com/facebook/jest/pull/7809)) ### Performance diff --git a/scripts/build.js b/scripts/build.js index 78d67bdbec5f..9afc50653ad6 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -196,9 +196,7 @@ function compileTypes(packages) { fs.existsSync(path.resolve(p, 'tsconfig.json')) ); - if (packageWithTs.length > 0) { - execa.sync('tsc', ['-b', ...packageWithTs]); - } + execa.sync('tsc', ['-b', ...packageWithTs]); } if (files.length) { diff --git a/scripts/watch.js b/scripts/watch.js index b40d670643b5..d2ab88c9791a 100644 --- a/scripts/watch.js +++ b/scripts/watch.js @@ -61,9 +61,7 @@ const packageWithTs = packages.filter(p => fs.existsSync(path.resolve(p, 'tsconfig.json')) ); -if (packageWithTs.length > 0) { - execa('tsc', ['-b', ...packageWithTs, '--watch']); -} +execa('tsc', ['-b', ...packageWithTs, '--watch']); setInterval(() => { const files = Array.from(filesToBuild.keys()); From 67e2488b18cc874d2f5d028747bee854680a5b3f Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Wed, 6 Feb 2019 11:24:21 -0500 Subject: [PATCH 3/5] Adds some inline docs to the exported methods --- packages/pretty-format/src/collections.ts | 32 ++++++++++++++--------- packages/pretty-format/src/index.ts | 21 ++++++++++++--- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/packages/pretty-format/src/collections.ts b/packages/pretty-format/src/collections.ts index 28112d1117b5..87afa9fe74fb 100644 --- a/packages/pretty-format/src/collections.ts +++ b/packages/pretty-format/src/collections.ts @@ -23,9 +23,11 @@ const getKeysOfEnumerableProperties = (object: Object) => { return keys; }; -// Return entries (for example, of a map) -// with spacing, indentation, and comma -// without surrounding punctuation (for example, braces) +/** + * Return entries (for example, of a map) + * with spacing, indentation, and comma + * without surrounding punctuation (for example, braces) + */ export function printIteratorEntries( // Flow 0.51.0: property `@@iterator` of $Iterator not found in Object // To allow simplistic getRecordIterator in immutable.js @@ -82,9 +84,11 @@ export function printIteratorEntries( return result; } -// Return values (for example, of a set) -// with spacing, indentation, and comma -// without surrounding punctuation (braces or brackets) +/** + * Return values (for example, of a set) + * with spacing, indentation, and comma + * without surrounding punctuation (braces or brackets) + */ export function printIteratorValues( iterator: Iterator, config: Config, @@ -121,9 +125,11 @@ export function printIteratorValues( return result; } -// Return items (for example, of an array) -// with spacing, indentation, and comma -// without surrounding punctuation (for example, brackets) +/** + * Return items (for example, of an array) + * with spacing, indentation, and comma + * without surrounding punctuation (for example, brackets) + **/ export function printListItems( list: any, config: Config, @@ -157,9 +163,11 @@ export function printListItems( return result; } -// Return properties of an object -// with spacing, indentation, and comma -// without surrounding punctuation (for example, braces) +/** + * Return properties of an object + * with spacing, indentation, and comma + * without surrounding punctuation (for example, braces) + */ export function printObjectProperties( val: Object, config: Config, diff --git a/packages/pretty-format/src/index.ts b/packages/pretty-format/src/index.ts index 6b9858e3dae6..856504521ac1 100644 --- a/packages/pretty-format/src/index.ts +++ b/packages/pretty-format/src/index.ts @@ -39,13 +39,15 @@ const errorToString = Error.prototype.toString; const regExpToString = RegExp.prototype.toString; const symbolToString = Symbol.prototype.toString; -// Explicitly comparing typeof constructor to function avoids undefined as name -// when mock identity-obj-proxy returns the key as the value for any key. +/** + * Explicitly comparing typeof constructor to function avoids undefined as name + * when mock identity-obj-proxy returns the key as the value for any key. + */ const getConstructorName = (val: any) => (typeof val.constructor === 'function' && val.constructor.name) || 'Object'; -// Is val is equal to global window object? Works even if it does not exist :) /* global window */ +/** Is val is equal to global window object? Works even if it does not exist :) */ const isWindow = (val: any) => typeof window !== 'undefined' && val === window; const SYMBOL_REGEXP = /^Symbol\((.*)\)(.*)$/; @@ -95,6 +97,10 @@ function printError(val: Error): string { return '[' + errorToString.call(val) + ']'; } +/** + * The first port of call for printing an object, handles most of the + * data-types in JS. + */ function printBasicValue( val: any, printFunctionName: boolean, @@ -167,6 +173,10 @@ function printBasicValue( return null; } +/** + * Handles more complex objects ( such as objects with circular references. + * maps and sets etc ) + */ function printComplexValue( val: any, config: Config, @@ -471,6 +481,11 @@ function createIndent(indent: number): string { return new Array(indent + 1).join(' '); } +/** + * Returns a presentation string of your `val` object + * @param val any potential JavaScript object + * @param options Custom settings + */ function prettyFormat(val: any, options?: OptionsReceived): string { if (options) { validateOptions(options); From a37f6b11ca139618ef8d36473f607ab7bb4e9225 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 6 Feb 2019 20:20:53 +0100 Subject: [PATCH 4/5] Update collections.ts --- packages/pretty-format/src/collections.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pretty-format/src/collections.ts b/packages/pretty-format/src/collections.ts index 87afa9fe74fb..7a95502fbd9c 100644 --- a/packages/pretty-format/src/collections.ts +++ b/packages/pretty-format/src/collections.ts @@ -126,7 +126,7 @@ export function printIteratorValues( } /** - * Return items (for example, of an array) + * Return items (for example, of an array) * with spacing, indentation, and comma * without surrounding punctuation (for example, brackets) **/ From 5cfdf4c8dcc59fc059b2e03c4901b5d7adc1eec7 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 6 Feb 2019 21:33:44 +0100 Subject: [PATCH 5/5] tweak types --- packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts | 2 +- packages/pretty-format/src/collections.ts | 3 +-- packages/pretty-format/src/index.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts b/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts index 1a25400ca982..b46d96ba5565 100644 --- a/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts +++ b/packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts @@ -12,7 +12,7 @@ import prettyFormat from '../'; const {AsymmetricMatcher} = prettyFormat.plugins; let options: OptionsReceived; -function fnNameFor(func: Function) { +function fnNameFor(func: (...any: any[]) => any) { if (func.name) { return func.name; } diff --git a/packages/pretty-format/src/collections.ts b/packages/pretty-format/src/collections.ts index 7a95502fbd9c..305e5c0da3d6 100644 --- a/packages/pretty-format/src/collections.ts +++ b/packages/pretty-format/src/collections.ts @@ -13,8 +13,7 @@ const getKeysOfEnumerableProperties = (object: Object) => { if (Object.getOwnPropertySymbols) { Object.getOwnPropertySymbols(object).forEach(symbol => { - // @ts-ignore: because property enumerable is missing in undefined - if (Object.getOwnPropertyDescriptor(object, symbol).enumerable) { + if (Object.getOwnPropertyDescriptor(object, symbol)!.enumerable) { keys.push(symbol); } }); diff --git a/packages/pretty-format/src/index.ts b/packages/pretty-format/src/index.ts index 856504521ac1..9ed723356e42 100644 --- a/packages/pretty-format/src/index.ts +++ b/packages/pretty-format/src/index.ts @@ -43,7 +43,7 @@ const symbolToString = Symbol.prototype.toString; * Explicitly comparing typeof constructor to function avoids undefined as name * when mock identity-obj-proxy returns the key as the value for any key. */ -const getConstructorName = (val: any) => +const getConstructorName = (val: new (...args: any[]) => any) => (typeof val.constructor === 'function' && val.constructor.name) || 'Object'; /* global window */