From e760ec40f04042d46c58bf7fd2c8049cbad8abb0 Mon Sep 17 00:00:00 2001 From: doniyor2109 Date: Sat, 16 Feb 2019 16:59:52 +0500 Subject: [PATCH] jest snapshot - TS migration (#7899) --- CHANGELOG.md | 1 + packages/jest-message-util/src/index.ts | 7 +- packages/jest-message-util/src/types.ts | 12 ++ packages/jest-snapshot/package.json | 8 ++ .../jest-snapshot/src/{State.js => State.ts} | 67 +++++----- ...t.js.snap => mock_serializer.test.ts.snap} | 0 ...js.snap => snapshot_resolver.test.ts.snap} | 0 ...shots.test.js => inline_snapshots.test.ts} | 84 +++++------- .../{matcher.test.js => matcher.test.ts} | 10 +- ...alizer.test.js => mock_serializer.test.ts} | 2 - .../{plugins.test.js => plugins.test.ts} | 4 +- ...lver.test.js => snapshot_resolver.test.ts} | 16 ++- ..._matcher.test.js => throw_matcher.test.ts} | 20 +-- .../{utils.test.js => utils.test.ts} | 36 +++--- .../jest-snapshot/src/{index.js => index.ts} | 51 ++++---- ...nline_snapshots.js => inline_snapshots.ts} | 57 ++++---- ...{mock_serializer.js => mock_serializer.ts} | 25 ++-- .../src/{plugins.js => plugins.ts} | 10 +- ...pshot_resolver.js => snapshot_resolver.ts} | 47 ++++--- packages/jest-snapshot/src/types.ts | 8 ++ .../jest-snapshot/src/{utils.js => utils.ts} | 46 +++---- packages/jest-snapshot/tsconfig.json | 16 +++ packages/jest-types/src/Matchers.ts | 40 ++++++ packages/jest-types/src/PrettyFormat.ts | 117 +++++++++++++++++ packages/jest-types/src/index.ts | 13 +- packages/pretty-format/package.json | 1 + packages/pretty-format/src/types.ts | 122 ++---------------- packages/pretty-format/tsconfig.json | 3 +- yarn.lock | 10 ++ 29 files changed, 492 insertions(+), 341 deletions(-) create mode 100644 packages/jest-message-util/src/types.ts rename packages/jest-snapshot/src/{State.js => State.ts} (85%) rename packages/jest-snapshot/src/__tests__/__snapshots__/{mock_serializer.test.js.snap => mock_serializer.test.ts.snap} (100%) rename packages/jest-snapshot/src/__tests__/__snapshots__/{snapshot_resolver.test.js.snap => snapshot_resolver.test.ts.snap} (100%) rename packages/jest-snapshot/src/__tests__/{inline_snapshots.test.js => inline_snapshots.test.ts} (73%) rename packages/jest-snapshot/src/__tests__/{matcher.test.js => matcher.test.ts} (76%) rename packages/jest-snapshot/src/__tests__/{mock_serializer.test.js => mock_serializer.test.ts} (99%) rename packages/jest-snapshot/src/__tests__/{plugins.test.js => plugins.test.ts} (96%) rename packages/jest-snapshot/src/__tests__/{snapshot_resolver.test.js => snapshot_resolver.test.ts} (91%) rename packages/jest-snapshot/src/__tests__/{throw_matcher.test.js => throw_matcher.test.ts} (82%) rename packages/jest-snapshot/src/__tests__/{utils.test.js => utils.test.ts} (89%) rename packages/jest-snapshot/src/{index.js => index.ts} (91%) rename packages/jest-snapshot/src/{inline_snapshots.js => inline_snapshots.ts} (80%) rename packages/jest-snapshot/src/{mock_serializer.js => mock_serializer.ts} (75%) rename packages/jest-snapshot/src/{plugins.js => plugins.ts} (83%) rename packages/jest-snapshot/src/{snapshot_resolver.js => snapshot_resolver.ts} (68%) create mode 100644 packages/jest-snapshot/src/types.ts rename packages/jest-snapshot/src/{utils.js => utils.ts} (85%) create mode 100644 packages/jest-snapshot/tsconfig.json create mode 100644 packages/jest-types/src/Matchers.ts create mode 100644 packages/jest-types/src/PrettyFormat.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfdfa66e605..88cc0354d2c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - `[babel-jest]`: Migrate to TypeScript ([#7862](https://github.com/facebook/jest/pull/7862)) - `[jest-resolve]`: Migrate to TypeScript ([#7871](https://github.com/facebook/jest/pull/7871)) - `[@jest/reporter]`: New package extracted from `jest-cli` ([#7902](https://github.com/facebook/jest/pull/7902)) +- `[jest-snapshot]`: Migrate to TypeScript ([#7899](https://github.com/facebook/jest/pull/7899)) ### Performance diff --git a/packages/jest-message-util/src/index.ts b/packages/jest-message-util/src/index.ts index 4e1b969f5d23..f1c6ad699215 100644 --- a/packages/jest-message-util/src/index.ts +++ b/packages/jest-message-util/src/index.ts @@ -13,6 +13,9 @@ import micromatch from 'micromatch'; import slash from 'slash'; import {codeFrameColumns} from '@babel/code-frame'; import StackUtils from 'stack-utils'; +import {Frame} from './types'; + +export {Frame} from './types'; type Path = Config.Path; type AssertionResult = TestResult.AssertionResult; @@ -227,7 +230,7 @@ export const getStackTraceLines = ( options: StackTraceOptions = {noStackTrace: false}, ) => removeInternalStackEntries(stack.split(/\n/), options); -export const getTopFrame = (lines: string[]) => { +export const getTopFrame = (lines: string[]): Frame | null => { for (const line of lines) { if (line.includes(PATH_NODE_MODULES) || line.includes(PATH_JEST_PACKAGES)) { continue; @@ -236,7 +239,7 @@ export const getTopFrame = (lines: string[]) => { const parsedFrame = stackUtils.parseLine(line.trim()); if (parsedFrame && parsedFrame.file) { - return parsedFrame; + return parsedFrame as Frame; } } diff --git a/packages/jest-message-util/src/types.ts b/packages/jest-message-util/src/types.ts new file mode 100644 index 000000000000..d8c9530b9b35 --- /dev/null +++ b/packages/jest-message-util/src/types.ts @@ -0,0 +1,12 @@ +/** + * 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. + */ + +import {StackData} from 'stack-utils'; + +export interface Frame extends StackData { + file: string; +} diff --git a/packages/jest-snapshot/package.json b/packages/jest-snapshot/package.json index 43c27d8bbab0..2f42a9bbc86b 100644 --- a/packages/jest-snapshot/package.json +++ b/packages/jest-snapshot/package.json @@ -8,8 +8,10 @@ }, "license": "MIT", "main": "build/index.js", + "types": "build/index.d.ts", "dependencies": { "@babel/types": "^7.0.0", + "@jest/types": "^24.1.0", "chalk": "^2.0.1", "jest-diff": "^24.0.0", "jest-matcher-utils": "^24.0.0", @@ -20,9 +22,15 @@ "pretty-format": "^24.0.0", "semver": "^5.5.0" }, + "peerDependencies": { + "jest-haste-map": "^24.0.0" + }, "devDependencies": { "@types/mkdirp": "^0.5.2", + "@types/natural-compare": "^1.4.0", + "@types/prettier": "^1.16.1", "@types/semver": "^5.5.0", + "jest-haste-map": "^24.0.0", "prettier": "^1.13.4" }, "engines": { diff --git a/packages/jest-snapshot/src/State.js b/packages/jest-snapshot/src/State.ts similarity index 85% rename from packages/jest-snapshot/src/State.js rename to packages/jest-snapshot/src/State.ts index ed380afbc1fb..c6fd06953b73 100644 --- a/packages/jest-snapshot/src/State.js +++ b/packages/jest-snapshot/src/State.ts @@ -3,13 +3,11 @@ * * 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 {Path, SnapshotUpdateState} from 'types/Config'; - import fs from 'fs'; +import {Config} from '@jest/types'; + import {getTopFrame, getStackTraceLines} from 'jest-message-util'; import { saveSnapshotFile, @@ -19,41 +17,44 @@ import { testNameToKey, unescape, } from './utils'; -import {saveInlineSnapshots, type InlineSnapshot} from './inline_snapshots'; +import {saveInlineSnapshots, InlineSnapshot} from './inline_snapshots'; +import {SnapshotData} from './types'; -export type SnapshotStateOptions = {| - updateSnapshot: SnapshotUpdateState, - getPrettier: () => null | any, - getBabelTraverse: () => Function, - expand?: boolean, -|}; +export type SnapshotStateOptions = { + updateSnapshot: Config.SnapshotUpdateState; + getPrettier: () => null | any; + getBabelTraverse: () => Function; + expand?: boolean; +}; -export type SnapshotMatchOptions = {| - testName: string, - received: any, - key?: string, - inlineSnapshot?: string, - error?: Error, -|}; +export type SnapshotMatchOptions = { + testName: string; + received: any; + key?: string; + inlineSnapshot?: string; + error?: Error; +}; export default class SnapshotState { - _counters: Map; - _dirty: boolean; - _index: number; - _updateSnapshot: SnapshotUpdateState; - _snapshotData: {[key: string]: string}; - _snapshotPath: Path; - _inlineSnapshots: Array; - _uncheckedKeys: Set; - _getBabelTraverse: () => Function; - _getPrettier: () => null | any; + private _counters: Map; + private _dirty: boolean; + // @ts-ignore + private _index: number; + private _updateSnapshot: Config.SnapshotUpdateState; + private _snapshotData: SnapshotData; + private _snapshotPath: Config.Path; + private _inlineSnapshots: Array; + private _uncheckedKeys: Set; + private _getBabelTraverse: () => Function; + private _getPrettier: () => null | any; + added: number; expand: boolean; matched: number; unmatched: number; updated: number; - constructor(snapshotPath: Path, options: SnapshotStateOptions) { + constructor(snapshotPath: Config.Path, options: SnapshotStateOptions) { this._snapshotPath = snapshotPath; const {data, dirty} = getSnapshotData( this._snapshotPath, @@ -83,15 +84,15 @@ export default class SnapshotState { }); } - _addSnapshot( + private _addSnapshot( key: string, receivedSerialized: string, - options: {isInline: boolean, error?: Error}, + options: {isInline: boolean; error?: Error}, ) { this._dirty = true; if (options.isInline) { const error = options.error || new Error(); - const lines = getStackTraceLines(error.stack); + const lines = getStackTraceLines(error.stack || ''); const frame = getTopFrame(lines); if (!frame) { throw new Error( @@ -251,7 +252,7 @@ export default class SnapshotState { } } - fail(testName: string, received: any, key?: string) { + fail(testName: string, _received: any, key?: string) { this._counters.set(testName, (this._counters.get(testName) || 0) + 1); const count = Number(this._counters.get(testName)); diff --git a/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap b/packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.ts.snap similarity index 100% rename from packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.js.snap rename to packages/jest-snapshot/src/__tests__/__snapshots__/mock_serializer.test.ts.snap diff --git a/packages/jest-snapshot/src/__tests__/__snapshots__/snapshot_resolver.test.js.snap b/packages/jest-snapshot/src/__tests__/__snapshots__/snapshot_resolver.test.ts.snap similarity index 100% rename from packages/jest-snapshot/src/__tests__/__snapshots__/snapshot_resolver.test.js.snap rename to packages/jest-snapshot/src/__tests__/__snapshots__/snapshot_resolver.test.ts.snap diff --git a/packages/jest-snapshot/src/__tests__/inline_snapshots.test.js b/packages/jest-snapshot/src/__tests__/inline_snapshots.test.ts similarity index 73% rename from packages/jest-snapshot/src/__tests__/inline_snapshots.test.js rename to packages/jest-snapshot/src/__tests__/inline_snapshots.test.ts index 63c744e73d0c..a7b7ad418eeb 100644 --- a/packages/jest-snapshot/src/__tests__/inline_snapshots.test.js +++ b/packages/jest-snapshot/src/__tests__/inline_snapshots.test.ts @@ -3,19 +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 */ jest.mock('fs'); jest.mock('prettier'); -const fs = require('fs'); -const path = require('path'); -const prettier = require('prettier'); -const babelTraverse = require('@babel/traverse').default; +import fs from 'fs'; +import path from 'path'; +import prettier from 'prettier'; +import babelTraverse from '@babel/traverse'; +import {Frame} from 'jest-message-util'; -const {saveInlineSnapshots} = require('../inline_snapshots'); +import {saveInlineSnapshots} from '../inline_snapshots'; const writeFileSync = fs.writeFileSync; const readFileSync = fs.readFileSync; @@ -23,45 +22,34 @@ const existsSync = fs.existsSync; const statSync = fs.statSync; const readdirSync = fs.readdirSync; beforeEach(() => { - // $FlowFixMe mock fs.writeFileSync = jest.fn(); - // $FlowFixMe mock fs.readFileSync = jest.fn(); - // $FlowFixMe mock fs.existsSync = jest.fn(() => true); - // $FlowFixMe mock - fs.statSync = jest.fn(filePath => ({ + (fs.statSync as jest.Mock).mockImplementation(filePath => ({ isDirectory: () => !filePath.endsWith('.js'), })); - // $FlowFixMe mock fs.readdirSync = jest.fn(() => []); - prettier.resolveConfig.sync.mockReset(); + (prettier.resolveConfig.sync as jest.Mock).mockReset(); }); afterEach(() => { - // $FlowFixMe mock fs.writeFileSync = writeFileSync; - // $FlowFixMe mock fs.readFileSync = readFileSync; - // $FlowFixMe mock fs.existsSync = existsSync; - // $FlowFixMe mock fs.statSync = statSync; - // $FlowFixMe mock fs.readdirSync = readdirSync; }); test('saveInlineSnapshots() replaces empty function call with a template literal', () => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => `expect(1).toMatchInlineSnapshot();\n`, - ): any); + ); saveInlineSnapshots( [ { - frame: {column: 11, file: filename, line: 1}, + frame: {column: 11, file: filename, line: 1} as Frame, snapshot: `1`, }, ], @@ -79,17 +67,16 @@ test.each([['babylon'], ['flow'], ['typescript']])( 'saveInlineSnapshots() replaces existing template literal - %s parser', parser => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => 'expect(1).toMatchInlineSnapshot(`2`);\n', - ): any); + ); - prettier.resolveConfig.sync.mockReturnValue({parser}); + (prettier.resolveConfig.sync as jest.Mock).mockReturnValue({parser}); saveInlineSnapshots( [ { - frame: {column: 11, file: filename, line: 1}, + frame: {column: 11, file: filename, line: 1} as Frame, snapshot: `1`, }, ], @@ -97,7 +84,9 @@ test.each([['babylon'], ['flow'], ['typescript']])( babelTraverse, ); - expect(prettier.resolveConfig.sync.mock.results[0].value).toEqual({parser}); + expect( + (prettier.resolveConfig.sync as jest.Mock).mock.results[0].value, + ).toEqual({parser}); expect(fs.writeFileSync).toHaveBeenCalledWith( filename, @@ -108,15 +97,14 @@ test.each([['babylon'], ['flow'], ['typescript']])( test('saveInlineSnapshots() replaces existing template literal with property matchers', () => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => 'expect(1).toMatchInlineSnapshot({}, `2`);\n', - ): any); + ); saveInlineSnapshots( [ { - frame: {column: 11, file: filename, line: 1}, + frame: {column: 11, file: filename, line: 1} as Frame, snapshot: `1`, }, ], @@ -132,16 +120,15 @@ test('saveInlineSnapshots() replaces existing template literal with property mat test('saveInlineSnapshots() throws if frame does not match', () => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => 'expect(1).toMatchInlineSnapshot();\n', - ): any); + ); const save = () => saveInlineSnapshots( [ { - frame: {column: 2 /* incorrect */, file: filename, line: 1}, + frame: {column: 2 /* incorrect */, file: filename, line: 1} as Frame, snapshot: `1`, }, ], @@ -154,12 +141,11 @@ test('saveInlineSnapshots() throws if frame does not match', () => { test('saveInlineSnapshots() throws if multiple calls to to the same location', () => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => 'expect(1).toMatchInlineSnapshot();\n', - ): any); + ); - const frame = {column: 11, file: filename, line: 1}; + const frame = {column: 11, file: filename, line: 1} as Frame; const save = () => saveInlineSnapshots( [{frame, snapshot: `1`}, {frame, snapshot: `2`}], @@ -174,12 +160,11 @@ test('saveInlineSnapshots() throws if multiple calls to to the same location', ( test('saveInlineSnapshots() uses escaped backticks', () => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => 'expect("`").toMatchInlineSnapshot();\n', - ): any); + ); - const frame = {column: 13, file: filename, line: 1}; + const frame = {column: 13, file: filename, line: 1} as Frame; saveInlineSnapshots([{frame, snapshot: '`'}], prettier, babelTraverse); expect(fs.writeFileSync).toHaveBeenCalledWith( @@ -190,11 +175,10 @@ test('saveInlineSnapshots() uses escaped backticks', () => { test('saveInlineSnapshots() works with non-literals in expect call', () => { const filename = path.join(__dirname, 'my.test.js'); - // $FlowFixMe mock - fs.readFileSync = (jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => `expect({a: 'a'}).toMatchInlineSnapshot();\n`, - ): any); - prettier.resolveConfig.sync.mockReturnValue({ + ); + (prettier.resolveConfig.sync as jest.Mock).mockReturnValue({ bracketSpacing: false, singleQuote: true, }); @@ -202,7 +186,7 @@ test('saveInlineSnapshots() works with non-literals in expect call', () => { saveInlineSnapshots( [ { - frame: {column: 18, file: filename, line: 1}, + frame: {column: 18, file: filename, line: 1} as Frame, snapshot: `{a: 'a'}`, }, ], diff --git a/packages/jest-snapshot/src/__tests__/matcher.test.js b/packages/jest-snapshot/src/__tests__/matcher.test.ts similarity index 76% rename from packages/jest-snapshot/src/__tests__/matcher.test.js rename to packages/jest-snapshot/src/__tests__/matcher.test.ts index e487a545dade..5bbfe1226577 100644 --- a/packages/jest-snapshot/src/__tests__/matcher.test.js +++ b/packages/jest-snapshot/src/__tests__/matcher.test.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. - * */ -'use strict'; -const {toMatchSnapshot} = require('../'); +import jestSnapshot from '../'; + +const {toMatchSnapshot} = jestSnapshot; it(`matcher returns matcher name, expected and actual values`, () => { const actual = 'a'; const expected = 'b'; const matcher = toMatchSnapshot.bind({ - snapshotState: {match: (testName, received) => ({actual, expected})}, + snapshotState: { + match: (_testName: string, _received: any) => ({actual, expected}), + }, }); const matcherResult = matcher({a: 1}); diff --git a/packages/jest-snapshot/src/__tests__/mock_serializer.test.js b/packages/jest-snapshot/src/__tests__/mock_serializer.test.ts similarity index 99% rename from packages/jest-snapshot/src/__tests__/mock_serializer.test.js rename to packages/jest-snapshot/src/__tests__/mock_serializer.test.ts index 702898f65a50..b859a9671a30 100644 --- a/packages/jest-snapshot/src/__tests__/mock_serializer.test.js +++ b/packages/jest-snapshot/src/__tests__/mock_serializer.test.ts @@ -3,9 +3,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * */ -'use strict'; import prettyFormat from 'pretty-format'; diff --git a/packages/jest-snapshot/src/__tests__/plugins.test.js b/packages/jest-snapshot/src/__tests__/plugins.test.ts similarity index 96% rename from packages/jest-snapshot/src/__tests__/plugins.test.js rename to packages/jest-snapshot/src/__tests__/plugins.test.ts index 8f0a9629dc99..feb47a2ea591 100644 --- a/packages/jest-snapshot/src/__tests__/plugins.test.js +++ b/packages/jest-snapshot/src/__tests__/plugins.test.ts @@ -3,13 +3,11 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * */ -'use strict'; beforeEach(() => jest.resetModules()); -const testPath = names => { +const testPath = (names: string[]) => { const {addSerializer, getSerializers} = require('../plugins'); const prev = getSerializers(); const added = names.map(name => diff --git a/packages/jest-snapshot/src/__tests__/snapshot_resolver.test.js b/packages/jest-snapshot/src/__tests__/snapshot_resolver.test.ts similarity index 91% rename from packages/jest-snapshot/src/__tests__/snapshot_resolver.test.js rename to packages/jest-snapshot/src/__tests__/snapshot_resolver.test.ts index fd53291ef0ca..5afee9699182 100644 --- a/packages/jest-snapshot/src/__tests__/snapshot_resolver.test.js +++ b/packages/jest-snapshot/src/__tests__/snapshot_resolver.test.ts @@ -1,14 +1,16 @@ // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. -const path = require('path'); -const {buildSnapshotResolver} = require('../snapshot_resolver'); +import path from 'path'; +import {Config} from '@jest/types'; + +import {buildSnapshotResolver, SnapshotResolver} from '../snapshot_resolver'; describe('defaults', () => { - let snapshotResolver; + let snapshotResolver: SnapshotResolver; const projectConfig = { rootDir: 'default', // snapshotResolver: null, - }; + } as Config.ProjectConfig; beforeEach(() => { snapshotResolver = buildSnapshotResolver(projectConfig); @@ -32,7 +34,7 @@ describe('defaults', () => { }); describe('custom resolver in project config', () => { - let snapshotResolver; + let snapshotResolver: SnapshotResolver; const customSnapshotResolverFile = path.join( __dirname, 'fixtures', @@ -41,7 +43,7 @@ describe('custom resolver in project config', () => { const projectConfig = { rootDir: 'custom1', snapshotResolver: customSnapshotResolverFile, - }; + } as Config.ProjectConfig; beforeEach(() => { snapshotResolver = buildSnapshotResolver(projectConfig); @@ -78,7 +80,7 @@ describe('malformed custom resolver in project config', () => { return { rootDir: 'missing-resolveSnapshotPath', snapshotResolver: customSnapshotResolverFile, - }; + } as Config.ProjectConfig; }; it('missing resolveSnapshotPath throws ', () => { diff --git a/packages/jest-snapshot/src/__tests__/throw_matcher.test.js b/packages/jest-snapshot/src/__tests__/throw_matcher.test.ts similarity index 82% rename from packages/jest-snapshot/src/__tests__/throw_matcher.test.js rename to packages/jest-snapshot/src/__tests__/throw_matcher.test.ts index d08d4e9877f9..bbe8b9d477db 100644 --- a/packages/jest-snapshot/src/__tests__/throw_matcher.test.js +++ b/packages/jest-snapshot/src/__tests__/throw_matcher.test.ts @@ -3,13 +3,13 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * */ -'use strict'; -const {toThrowErrorMatchingSnapshot} = require('../'); +import jestSnapshot from '../'; + +const {toThrowErrorMatchingSnapshot} = jestSnapshot; -let matchFn; +let matchFn: jest.Mock; beforeEach(() => { matchFn = jest.fn(() => ({ @@ -23,9 +23,13 @@ it('throw matcher can take func', () => { snapshotState: {match: matchFn}, }); - throwMatcher(() => { - throw new Error('coconut'); - }); + throwMatcher( + () => { + throw new Error('coconut'); + }, + undefined, + false, + ); expect(matchFn).toHaveBeenCalledWith( expect.objectContaining({received: 'coconut', testName: ''}), @@ -33,7 +37,7 @@ it('throw matcher can take func', () => { }); describe('throw matcher from promise', () => { - let throwMatcher; + let throwMatcher: typeof toThrowErrorMatchingSnapshot; beforeEach(() => { throwMatcher = toThrowErrorMatchingSnapshot.bind({ diff --git a/packages/jest-snapshot/src/__tests__/utils.test.js b/packages/jest-snapshot/src/__tests__/utils.test.ts similarity index 89% rename from packages/jest-snapshot/src/__tests__/utils.test.js rename to packages/jest-snapshot/src/__tests__/utils.test.ts index d4d34a2d2131..981070691777 100644 --- a/packages/jest-snapshot/src/__tests__/utils.test.js +++ b/packages/jest-snapshot/src/__tests__/utils.test.ts @@ -7,21 +7,21 @@ jest.mock('fs'); -const fs = require('fs'); -const path = require('path'); -const chalk = require('chalk'); +import fs from 'fs'; +import path from 'path'; +import chalk from 'chalk'; -const { +import { + deepMerge, getSnapshotData, keyToTestName, saveSnapshotFile, serialize, testNameToKey, - deepMerge, SNAPSHOT_GUIDE_LINK, SNAPSHOT_VERSION, SNAPSHOT_VERSION_WARNING, -} = require('../utils'); +} from '../utils'; const writeFileSync = fs.writeFileSync; const readFileSync = fs.readFileSync; @@ -80,7 +80,9 @@ test('saveSnapshotFile() works with \r', () => { test('getSnapshotData() throws when no snapshot version', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); - fs.readFileSync = jest.fn(() => 'exports[`myKey`] = `
\n
`;\n'); + (fs.readFileSync as jest.Mock).mockImplementation( + () => 'exports[`myKey`] = `
\n
`;\n', + ); const update = 'none'; expect(() => getSnapshotData(filename, update)).toThrowError( @@ -95,7 +97,7 @@ test('getSnapshotData() throws when no snapshot version', () => { test('getSnapshotData() throws for older snapshot version', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); - fs.readFileSync = jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => `// Jest Snapshot v0.99, ${SNAPSHOT_GUIDE_LINK}\n\n` + 'exports[`myKey`] = `
\n
`;\n', @@ -118,7 +120,7 @@ test('getSnapshotData() throws for older snapshot version', () => { test('getSnapshotData() throws for newer snapshot version', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); - fs.readFileSync = jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => `// Jest Snapshot v2, ${SNAPSHOT_GUIDE_LINK}\n\n` + 'exports[`myKey`] = `
\n
`;\n', @@ -141,7 +143,9 @@ test('getSnapshotData() throws for newer snapshot version', () => { test('getSnapshotData() does not throw for when updating', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); - fs.readFileSync = jest.fn(() => 'exports[`myKey`] = `
\n
`;\n'); + (fs.readFileSync as jest.Mock).mockImplementation( + () => 'exports[`myKey`] = `
\n
`;\n', + ); const update = 'all'; expect(() => getSnapshotData(filename, update)).not.toThrow(); @@ -149,7 +153,9 @@ test('getSnapshotData() does not throw for when updating', () => { test('getSnapshotData() marks invalid snapshot dirty when updating', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); - fs.readFileSync = jest.fn(() => 'exports[`myKey`] = `
\n
`;\n'); + (fs.readFileSync as jest.Mock).mockImplementation( + () => 'exports[`myKey`] = `
\n
`;\n', + ); const update = 'all'; expect(getSnapshotData(filename, update)).toMatchObject({dirty: true}); @@ -157,7 +163,7 @@ test('getSnapshotData() marks invalid snapshot dirty when updating', () => { test('getSnapshotData() marks valid snapshot not dirty when updating', () => { const filename = path.join(__dirname, 'old-snapshot.snap'); - fs.readFileSync = jest.fn( + (fs.readFileSync as jest.Mock).mockImplementation( () => `// Jest Snapshot v${SNAPSHOT_VERSION}, ${SNAPSHOT_GUIDE_LINK}\n\n` + 'exports[`myKey`] = `
\n
`;\n', @@ -171,14 +177,14 @@ test('escaping', () => { const filename = path.join(__dirname, 'escaping.snap'); const data = '"\'\\'; saveSnapshotFile({key: data}, filename); - const writtenData = fs.writeFileSync.mock.calls[0][1]; + const writtenData = (fs.writeFileSync as jest.Mock).mock.calls[0][1]; expect(writtenData).toBe( `// Jest Snapshot v1, ${SNAPSHOT_GUIDE_LINK}\n\n` + 'exports[`key`] = `"\'\\\\`;\n', ); - // eslint-disable-next-line no-unused-vars - const exports = {}; + // @ts-ignore + const exports = {}; // eslint-disable-line // eslint-disable-next-line no-eval const readData = eval('var exports = {}; ' + writtenData + ' exports'); expect(readData).toEqual({key: data}); diff --git a/packages/jest-snapshot/src/index.js b/packages/jest-snapshot/src/index.ts similarity index 91% rename from packages/jest-snapshot/src/index.js rename to packages/jest-snapshot/src/index.ts index 7c0cb0687303..bc22a7e4b9d9 100644 --- a/packages/jest-snapshot/src/index.js +++ b/packages/jest-snapshot/src/index.ts @@ -3,33 +3,34 @@ * * 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 {HasteFS} from 'types/HasteMap'; -import type {MatcherState} from 'types/Matchers'; -import type {Path, SnapshotUpdateState} from 'types/Config'; -import type {SnapshotResolver} from 'types/SnapshotResolver'; - import fs from 'fs'; +import {Config, Matchers} from '@jest/types'; +import {FS as HasteFS} from 'jest-haste-map'; + import diff from 'jest-diff'; import {EXPECTED_COLOR, matcherHint, RECEIVED_COLOR} from 'jest-matcher-utils'; import { buildSnapshotResolver, isSnapshotPath, + SnapshotResolver, EXTENSION, } from './snapshot_resolver'; import SnapshotState from './State'; import {addSerializer, getSerializers} from './plugins'; import * as utils from './utils'; -const fileExists = (filePath: Path, hasteFS: HasteFS): boolean => +type Context = Matchers.MatcherState & { + snapshotState: SnapshotState; +}; + +const fileExists = (filePath: Config.Path, hasteFS: HasteFS): boolean => hasteFS.exists(filePath) || fs.existsSync(filePath); const cleanup = ( hasteFS: HasteFS, - update: SnapshotUpdateState, + update: Config.SnapshotUpdateState, snapshotResolver: SnapshotResolver, ) => { const pattern = '\\.' + EXTENSION + '$'; @@ -51,9 +52,10 @@ const cleanup = ( }; const toMatchSnapshot = function( + this: Context, received: any, propertyMatchers?: any, - testName?: string, + testName?: Config.Path, ) { if (arguments.length === 3 && !propertyMatchers) { throw new Error( @@ -70,6 +72,7 @@ const toMatchSnapshot = function( }; const toMatchInlineSnapshot = function( + this: Context, received: any, propertyMatchersOrInlineSnapshot?: any, inlineSnapshot?: string, @@ -95,11 +98,11 @@ const _toMatchSnapshot = ({ testName, inlineSnapshot, }: { - context: MatcherState & {dontThrow?: () => any}, - received: any, - propertyMatchers?: any, - testName?: string, - inlineSnapshot?: string, + context: Context; + received: any; + propertyMatchers?: any; + testName?: string; + inlineSnapshot?: string; }) => { context.dontThrow && context.dontThrow(); testName = typeof propertyMatchers === 'string' ? propertyMatchers : testName; @@ -168,7 +171,7 @@ const _toMatchSnapshot = ({ const {pass} = result; let {actual, expected} = result; - let report; + let report: () => string; if (pass) { return {message: () => '', pass: true}; } else if (!expected) { @@ -211,8 +214,9 @@ const _toMatchSnapshot = ({ }; const toThrowErrorMatchingSnapshot = function( + this: Context, received: any, - testName?: string, + testName: string | undefined, fromPromise: boolean, ) { return _toThrowErrorMatchingSnapshot({ @@ -224,6 +228,7 @@ const toThrowErrorMatchingSnapshot = function( }; const toThrowErrorMatchingInlineSnapshot = function( + this: Context, received: any, inlineSnapshot?: string, fromPromise?: boolean, @@ -243,11 +248,11 @@ const _toThrowErrorMatchingSnapshot = ({ fromPromise, inlineSnapshot, }: { - context: MatcherState & {dontThrow?: () => any}, - received: any, - testName?: string, - fromPromise?: boolean, - inlineSnapshot?: string, + context: Context; + received: any; + testName?: string; + fromPromise?: boolean; + inlineSnapshot?: string; }) => { context.dontThrow && context.dontThrow(); const {isNot} = context; @@ -291,7 +296,7 @@ const _toThrowErrorMatchingSnapshot = ({ }); }; -module.exports = { +export = { EXTENSION, SnapshotState, addSerializer, diff --git a/packages/jest-snapshot/src/inline_snapshots.js b/packages/jest-snapshot/src/inline_snapshots.ts similarity index 80% rename from packages/jest-snapshot/src/inline_snapshots.js rename to packages/jest-snapshot/src/inline_snapshots.ts index cd171877a4a7..9468c1c4ec43 100644 --- a/packages/jest-snapshot/src/inline_snapshots.js +++ b/packages/jest-snapshot/src/inline_snapshots.ts @@ -3,22 +3,26 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ import fs from 'fs'; -import semver from 'semver'; import path from 'path'; -import {templateElement, templateLiteral, file} from '@babel/types'; - -import type {Path} from 'types/Config'; +import semver from 'semver'; +import { + templateElement, + templateLiteral, + file, + CallExpression, +} from '@babel/types'; +import {Frame} from 'jest-message-util'; + +import {Config} from '@jest/types'; import {escapeBacktickString} from './utils'; -export type InlineSnapshot = {| - snapshot: string, - frame: {line: number, column: number, file: string}, -|}; +export type InlineSnapshot = { + snapshot: string; + frame: Frame; +}; export const saveInlineSnapshots = ( snapshots: InlineSnapshot[], @@ -54,7 +58,7 @@ export const saveInlineSnapshots = ( const saveSnapshotsForFile = ( snapshots: Array, - sourceFilePath: Path, + sourceFilePath: Config.Path, prettier: any, babelTraverse: Function, ) => { @@ -86,16 +90,21 @@ const saveSnapshotsForFile = ( } }; -const groupSnapshotsBy = (createKey: InlineSnapshot => string) => ( - snapshots: Array, -) => - snapshots.reduce((object, inlineSnapshot) => { - const key = createKey(inlineSnapshot); - return {...object, [key]: (object[key] || []).concat(inlineSnapshot)}; - }, {}); - -const groupSnapshotsByFrame = groupSnapshotsBy( - ({frame: {line, column}}) => `${line}:${column - 1}`, +const groupSnapshotsBy = ( + createKey: (inlineSnapshot: InlineSnapshot) => string, +) => (snapshots: Array) => + snapshots.reduce<{[key: string]: InlineSnapshot[]}>( + (object, inlineSnapshot) => { + const key = createKey(inlineSnapshot); + return {...object, [key]: (object[key] || []).concat(inlineSnapshot)}; + }, + {}, + ); + +const groupSnapshotsByFrame = groupSnapshotsBy(({frame: {line, column}}) => + typeof line === 'number' && typeof column === 'number' + ? `${line}:${column - 1}` + : '', ); const groupSnapshotsByFile = groupSnapshotsBy(({frame: {file}}) => file); @@ -105,7 +114,7 @@ const createParser = ( babelTraverse: Function, ) => ( text: string, - parsers: {[key: string]: (string) => any}, + parsers: {[key: string]: (text: string) => any}, options: any, ) => { // Workaround for https://github.com/prettier/prettier/issues/3150 @@ -122,7 +131,7 @@ const createParser = ( } babelTraverse(ast, { - CallExpression({node: {arguments: args, callee}}) { + CallExpression({node: {arguments: args, callee}}: {node: CallExpression}) { if ( callee.type !== 'MemberExpression' || callee.property.type !== 'Identifier' @@ -167,7 +176,7 @@ const createParser = ( return ast; }; -const simpleDetectParser = (filePath: Path) => { +const simpleDetectParser = (filePath: Config.Path) => { const extname = path.extname(filePath); if (/tsx?$/.test(extname)) { return 'typescript'; diff --git a/packages/jest-snapshot/src/mock_serializer.js b/packages/jest-snapshot/src/mock_serializer.ts similarity index 75% rename from packages/jest-snapshot/src/mock_serializer.js rename to packages/jest-snapshot/src/mock_serializer.ts index 410c6d9f2a9b..fbfaf7a1448c 100644 --- a/packages/jest-snapshot/src/mock_serializer.js +++ b/packages/jest-snapshot/src/mock_serializer.ts @@ -3,19 +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 {Config, NewPlugin, Printer, Refs} from 'types/PrettyFormat'; +import {PrettyFormat} from '@jest/types'; -export const serialize = ( - val: any, - config: Config, - indentation: string, - depth: number, - refs: Refs, - printer: Printer, +export const serialize: PrettyFormat.NewPlugin['serialize'] = ( + val, + config, + indentation, + depth, + refs, + printer, ): string => { // Serialize a non-default name, even if config.printFunctionName is false. const name = val.getMockName(); @@ -44,6 +42,9 @@ export const serialize = ( return '[MockFunction' + nameString + ']' + callsString; }; -export const test = (val: any) => val && !!val._isMockFunction; +export const test: PrettyFormat.NewPlugin['test'] = val => + val && !!val._isMockFunction; + +const plugin: PrettyFormat.NewPlugin = {serialize, test}; -export default ({serialize, test}: NewPlugin); +export default plugin; diff --git a/packages/jest-snapshot/src/plugins.js b/packages/jest-snapshot/src/plugins.ts similarity index 83% rename from packages/jest-snapshot/src/plugins.js rename to packages/jest-snapshot/src/plugins.ts index e445ce59c2f0..ebf50c0eb651 100644 --- a/packages/jest-snapshot/src/plugins.js +++ b/packages/jest-snapshot/src/plugins.ts @@ -3,13 +3,11 @@ * * 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 {Plugin} from 'types/PrettyFormat'; - import prettyFormat from 'pretty-format'; +import {PrettyFormat} from '@jest/types'; + import jestMockSerializer from './mock_serializer'; const { @@ -21,7 +19,7 @@ const { AsymmetricMatcher, } = prettyFormat.plugins; -let PLUGINS: Array = [ +let PLUGINS: PrettyFormat.Plugins = [ ReactTestComponent, ReactElement, DOMElement, @@ -32,7 +30,7 @@ let PLUGINS: Array = [ ]; // Prepend to list so the last added is the first tested. -export const addSerializer = (plugin: Plugin) => { +export const addSerializer = (plugin: PrettyFormat.Plugin) => { PLUGINS = [plugin].concat(PLUGINS); }; diff --git a/packages/jest-snapshot/src/snapshot_resolver.js b/packages/jest-snapshot/src/snapshot_resolver.ts similarity index 68% rename from packages/jest-snapshot/src/snapshot_resolver.js rename to packages/jest-snapshot/src/snapshot_resolver.ts index c8c8829aa19f..824fb5307dfa 100644 --- a/packages/jest-snapshot/src/snapshot_resolver.js +++ b/packages/jest-snapshot/src/snapshot_resolver.ts @@ -1,9 +1,19 @@ -// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +/** + * 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. + */ -import type {ProjectConfig, Path} from 'types/Config'; -import type {SnapshotResolver} from 'types/SnapshotResolver'; -import chalk from 'chalk'; import path from 'path'; +import {Config} from '@jest/types'; +import chalk from 'chalk'; + +export type SnapshotResolver = { + testPathForConsistencyCheck: string; + resolveSnapshotPath(testPath: Config.Path, extension?: string): Config.Path; + resolveTestPath(snapshotPath: Config.Path, extension?: string): Config.Path; +}; export const EXTENSION = 'snap'; export const DOT_EXTENSION = '.' + EXTENSION; @@ -11,32 +21,34 @@ export const DOT_EXTENSION = '.' + EXTENSION; export const isSnapshotPath = (path: string): boolean => path.endsWith(DOT_EXTENSION); -const cache: Map = new Map(); +const cache: Map = new Map(); export const buildSnapshotResolver = ( - config: ProjectConfig, + config: Config.ProjectConfig, ): SnapshotResolver => { const key = config.rootDir; if (!cache.has(key)) { cache.set(key, createSnapshotResolver(config.snapshotResolver)); } - return cache.get(key); + return cache.get(key)!; }; -function createSnapshotResolver(snapshotResolverPath: ?Path): SnapshotResolver { +function createSnapshotResolver( + snapshotResolverPath?: Config.Path | null, +): SnapshotResolver { return typeof snapshotResolverPath === 'string' ? createCustomSnapshotResolver(snapshotResolverPath) : createDefaultSnapshotResolver(); } -function createDefaultSnapshotResolver() { +function createDefaultSnapshotResolver(): SnapshotResolver { return { - resolveSnapshotPath: (testPath: Path) => + resolveSnapshotPath: (testPath: Config.Path) => path.join( path.join(path.dirname(testPath), '__snapshots__'), path.basename(testPath) + DOT_EXTENSION, ), - resolveTestPath: (snapshotPath: Path) => + resolveTestPath: (snapshotPath: Config.Path) => path.resolve( path.dirname(snapshotPath), '..', @@ -52,24 +64,25 @@ function createDefaultSnapshotResolver() { } function createCustomSnapshotResolver( - snapshotResolverPath: Path, + snapshotResolverPath: Config.Path, ): SnapshotResolver { - const custom = (require(snapshotResolverPath): SnapshotResolver); + const custom: SnapshotResolver = require(snapshotResolverPath); - [ + const keys: [keyof SnapshotResolver, string][] = [ ['resolveSnapshotPath', 'function'], ['resolveTestPath', 'function'], ['testPathForConsistencyCheck', 'string'], - ].forEach(([propName, requiredType]) => { + ]; + keys.forEach(([propName, requiredType]) => { if (typeof custom[propName] !== requiredType) { throw new TypeError(mustImplement(propName, requiredType)); } }); const customResolver = { - resolveSnapshotPath: testPath => + resolveSnapshotPath: (testPath: Config.Path) => custom.resolveSnapshotPath(testPath, DOT_EXTENSION), - resolveTestPath: snapshotPath => + resolveTestPath: (snapshotPath: Config.Path) => custom.resolveTestPath(snapshotPath, DOT_EXTENSION), testPathForConsistencyCheck: custom.testPathForConsistencyCheck, }; diff --git a/packages/jest-snapshot/src/types.ts b/packages/jest-snapshot/src/types.ts new file mode 100644 index 000000000000..439a6d013ed1 --- /dev/null +++ b/packages/jest-snapshot/src/types.ts @@ -0,0 +1,8 @@ +/** + * 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 SnapshotData = {[key: string]: string}; diff --git a/packages/jest-snapshot/src/utils.js b/packages/jest-snapshot/src/utils.ts similarity index 85% rename from packages/jest-snapshot/src/utils.js rename to packages/jest-snapshot/src/utils.ts index 61b812ebdf68..992fa72926d0 100644 --- a/packages/jest-snapshot/src/utils.js +++ b/packages/jest-snapshot/src/utils.ts @@ -3,19 +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 {Path, SnapshotUpdateState} from 'types/Config'; - -import {getSerializers} from './plugins'; -import chalk from 'chalk'; import fs from 'fs'; +import path from 'path'; import mkdirp from 'mkdirp'; import naturalCompare from 'natural-compare'; -import path from 'path'; +import chalk from 'chalk'; +import {Config} from '@jest/types'; import prettyFormat from 'pretty-format'; +import {getSerializers} from './plugins'; +import {SnapshotData} from './types'; export const SNAPSHOT_VERSION = '1'; const SNAPSHOT_VERSION_REGEXP = /^\/\/ Jest Snapshot v(.+),/; @@ -76,14 +74,14 @@ const validateSnapshotVersion = (snapshotContents: string) => { return null; }; -function isObject(item) { +function isObject(item: unknown): boolean { return item && typeof item === 'object' && !Array.isArray(item); } -export const testNameToKey = (testName: string, count: number) => +export const testNameToKey = (testName: Config.Path, count: number): string => testName + ' ' + count; -export const keyToTestName = (key: string) => { +export const keyToTestName = (key: string): string => { if (!/ \d+$/.test(key)) { throw new Error('Snapshot keys must end with a number.'); } @@ -92,9 +90,12 @@ export const keyToTestName = (key: string) => { }; export const getSnapshotData = ( - snapshotPath: Path, - update: SnapshotUpdateState, -) => { + snapshotPath: Config.Path, + update: Config.SnapshotUpdateState, +): { + data: SnapshotData; + dirty: boolean; +} => { const data = Object.create(null); let snapshotContents = ''; let dirty = false; @@ -104,7 +105,6 @@ export const getSnapshotData = ( snapshotContents = fs.readFileSync(snapshotPath, 'utf8'); // eslint-disable-next-line no-new-func const populate = new Function('exports', snapshotContents); - // $FlowFixMe populate(data); } catch (e) {} } @@ -120,15 +120,15 @@ export const getSnapshotData = ( dirty = true; } - return ({data, dirty}: {data: any, dirty: boolean}); + return {data, dirty}; }; // Extra line breaks at the beginning and at the end of the snapshot are useful // to make the content of the snapshot easier to read -const addExtraLineBreaks = string => +const addExtraLineBreaks = (string: string): string => string.includes('\n') ? `\n${string}\n` : string; -export const serialize = (data: any): string => +export const serialize = (data: string): string => addExtraLineBreaks( normalizeNewlines( prettyFormat(data, { @@ -140,25 +140,25 @@ export const serialize = (data: any): string => ); // unescape double quotes -export const unescape = (data: any): string => data.replace(/\\(")/g, '$1'); +export const unescape = (data: string): string => data.replace(/\\(")/g, '$1'); -export const escapeBacktickString = (str: string) => +export const escapeBacktickString = (str: string): string => str.replace(/`|\\|\${/g, '\\$&'); -const printBacktickString = (str: string) => +const printBacktickString = (str: string): string => '`' + escapeBacktickString(str) + '`'; -export const ensureDirectoryExists = (filePath: Path) => { +export const ensureDirectoryExists = (filePath: Config.Path) => { try { mkdirp.sync(path.join(path.dirname(filePath)), '777'); } catch (e) {} }; -const normalizeNewlines = string => string.replace(/\r\n|\r/g, '\n'); +const normalizeNewlines = (string: string) => string.replace(/\r\n|\r/g, '\n'); export const saveSnapshotFile = ( snapshotData: {[key: string]: string}, - snapshotPath: Path, + snapshotPath: Config.Path, ) => { const snapshots = Object.keys(snapshotData) .sort(naturalCompare) diff --git a/packages/jest-snapshot/tsconfig.json b/packages/jest-snapshot/tsconfig.json new file mode 100644 index 000000000000..2ed3fb0d58dc --- /dev/null +++ b/packages/jest-snapshot/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + }, + "references": [ + {"path": "../jest-diff"}, + {"path": "../jest-haste-map"}, + {"path": "../jest-matcher-utils"}, + {"path": "../jest-message-util"}, + {"path": "../jest-resolve"}, + {"path": "../jest-types"}, + {"path": "../pretty-format"} + ] +} diff --git a/packages/jest-types/src/Matchers.ts b/packages/jest-types/src/Matchers.ts new file mode 100644 index 000000000000..e4e419e0ae23 --- /dev/null +++ b/packages/jest-types/src/Matchers.ts @@ -0,0 +1,40 @@ +/** + * 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. + */ + +// TODO: Move this to `expect` when it's migrated + +import {Path} from './Config'; + +type Tester = (a: any, b: any) => boolean | undefined; + +export type MatcherState = { + assertionCalls: number; + currentTestName?: string; + dontThrow?: () => void; + error?: Error; + equals: ( + a: unknown, + b: unknown, + customTesters?: Array, + strictCheck?: boolean, + ) => boolean; + expand?: boolean; + expectedAssertionsNumber?: number; + isExpectingAssertions?: boolean; + isNot: boolean; + promise: string; + suppressedErrors: Array; + testPath?: Path; + // This is output from `jest-matcher-utils` plus iterableEquality, subsetEquality + // Type it correctly when moving it to `expect` + utils: { + printExpected: (value: unknown) => string; + printReceived: (value: unknown) => string; + iterableEquality: Tester; + subsetEquality: Tester; + }; +}; diff --git a/packages/jest-types/src/PrettyFormat.ts b/packages/jest-types/src/PrettyFormat.ts new file mode 100644 index 000000000000..89d06d5bd418 --- /dev/null +++ b/packages/jest-types/src/PrettyFormat.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/jest-types/src/index.ts b/packages/jest-types/src/index.ts index 769fb97b881b..5f72f2e75feb 100644 --- a/packages/jest-types/src/index.ts +++ b/packages/jest-types/src/index.ts @@ -11,5 +11,16 @@ import * as SourceMaps from './SourceMaps'; import * as TestResult from './TestResult'; import * as Mocks from './Mocks'; import * as Transform from './Transform'; +import * as PrettyFormat from './PrettyFormat'; +import * as Matchers from './Matchers'; -export {Config, Console, SourceMaps, TestResult, Mocks, Transform}; +export { + Config, + Console, + SourceMaps, + TestResult, + Mocks, + Transform, + PrettyFormat, + Matchers, +}; diff --git a/packages/pretty-format/package.json b/packages/pretty-format/package.json index ae89d57ddda0..ef976df12eef 100644 --- a/packages/pretty-format/package.json +++ b/packages/pretty-format/package.json @@ -13,6 +13,7 @@ "browser": "build-es5/index.js", "author": "James Kyle ", "dependencies": { + "@jest/types": "^24.1.0", "ansi-regex": "^4.0.0", "ansi-styles": "^3.2.0" }, diff --git a/packages/pretty-format/src/types.ts b/packages/pretty-format/src/types.ts index 89d06d5bd418..71f14783ed5f 100644 --- a/packages/pretty-format/src/types.ts +++ b/packages/pretty-format/src/types.ts @@ -5,113 +5,15 @@ * 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; +import {PrettyFormat} from '@jest/types'; + +export type Colors = PrettyFormat.Colors; +export type Config = PrettyFormat.Config; +export type Options = PrettyFormat.Options; +export type OptionsReceived = PrettyFormat.OptionsReceived; +export type NewPlugin = PrettyFormat.NewPlugin; +export type Plugin = PrettyFormat.Plugin; +export type Plugins = PrettyFormat.Plugins; +export type Refs = PrettyFormat.Refs; +export type Theme = PrettyFormat.Theme; +export type Printer = PrettyFormat.Printer; diff --git a/packages/pretty-format/tsconfig.json b/packages/pretty-format/tsconfig.json index 7bb06bce6d20..3046cb6b9b6a 100644 --- a/packages/pretty-format/tsconfig.json +++ b/packages/pretty-format/tsconfig.json @@ -3,5 +3,6 @@ "compilerOptions": { "rootDir": "src", "outDir": "build" - } + }, + "references": [{"path": "../jest-types"}] } diff --git a/yarn.lock b/yarn.lock index 71ed496d78f9..d14756f8cfac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1688,6 +1688,11 @@ dependencies: "@types/node" "*" +"@types/natural-compare@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@types/natural-compare/-/natural-compare-1.4.0.tgz#b3c54f7edc339758d573c5dcac7808c58cf8c31e" + integrity sha512-bNtBj6AF1F90jp54KRPOrYfilGNfPr2kpaUN7rMJjauAtfGBXzT/T/REZN6jb4qUs9FTxU37kir3Nrn5WsTUDw== + "@types/node-notifier@^0.0.28": version "0.0.28" resolved "https://registry.yarnpkg.com/@types/node-notifier/-/node-notifier-0.0.28.tgz#86ba3d3aa8d918352cc3191d88de328b20dc93c1" @@ -1700,6 +1705,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.24.tgz#b13564af612a22a20b5d95ca40f1bffb3af315cf" integrity sha512-GWWbvt+z9G5otRBW8rssOFgRY87J9N/qbhqfjMZ+gUuL6zoL+Hm6gP/8qQBG4jjimqdaNLCehcVapZ/Fs2WjCQ== +"@types/prettier@^1.16.1": + version "1.16.1" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.16.1.tgz#328d1c9b54402e44119398bcb6a31b7bbd606d59" + integrity sha512-db6pZL5QY3JrlCHBhYQzYDci0xnoDuxfseUuguLRr3JNk+bnCfpkK6p8quiUDyO8A0vbpBKkk59Fw125etrNeA== + "@types/prompts@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-1.2.0.tgz#891e73f735ad5e82e8adae3a99424128e105fb62"