Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jest snapshot - TS migration #7899

Merged
merged 37 commits into from Feb 16, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0ecbf42
WIP - migration to ts (part 1)
doniyor2109 Feb 14, 2019
7a181dc
Remove old snapshots
doniyor2109 Feb 14, 2019
60c07cd
Merge remote-tracking branch 'jest/master' into jest-snapshot/ts_migr…
doniyor2109 Feb 14, 2019
f12de38
Use MatcherState type from expect (not implemented yet)
doniyor2109 Feb 14, 2019
1c70f23
Handle when line and column are zero
doniyor2109 Feb 14, 2019
934b93c
Remove extra exports
doniyor2109 Feb 14, 2019
b94d602
Minor tweaks
doniyor2109 Feb 15, 2019
7dc5065
Small tweaks
SimenB Feb 15, 2019
b6522be
Small tweaks
doniyor2109 Feb 15, 2019
27837ec
Revert underscores
doniyor2109 Feb 15, 2019
c7991d8
Private methods
doniyor2109 Feb 15, 2019
6cd97aa
Minor tweaks
doniyor2109 Feb 15, 2019
cdb6096
Meaningful name
SimenB Feb 15, 2019
5706125
Remove extra ts-ignore
doniyor2109 Feb 15, 2019
835974d
Small change
SimenB Feb 15, 2019
e6b14dc
Migrate tests to es modules
doniyor2109 Feb 15, 2019
d0f3789
Small tweak
doniyor2109 Feb 15, 2019
81cec4a
Eslint fixes
doniyor2109 Feb 15, 2019
9c16d91
Fix `import =` is not supported in test
doniyor2109 Feb 15, 2019
36d32f3
Remove extra dep
doniyor2109 Feb 15, 2019
1fb3194
Add Frame type to jest-message-util
doniyor2109 Feb 15, 2019
84ae5ca
Minor tweaks
doniyor2109 Feb 15, 2019
4a14bc4
Better types
SimenB Feb 15, 2019
caf2268
Minor tweaks
doniyor2109 Feb 15, 2019
1202434
Fix Frame types in tests
doniyor2109 Feb 15, 2019
cc59272
Resolve unused vars
doniyor2109 Feb 15, 2019
3c906c3
es imports
doniyor2109 Feb 15, 2019
9bd4eb0
Added package.json types
doniyor2109 Feb 16, 2019
3de88c4
Added @types/natural-comapre
doniyor2109 Feb 16, 2019
bb89663
Merge branch 'master' into jest-snapshot/ts_migration
SimenB Feb 16, 2019
186194e
fix type import
SimenB Feb 16, 2019
9288a1d
remove unused eslint supression comment
SimenB Feb 16, 2019
19aa286
chore: add missing copyright header
SimenB Feb 16, 2019
d9e9314
tweak some types
SimenB Feb 16, 2019
7590af9
explicit export
SimenB Feb 16, 2019
b915c81
changelog
SimenB Feb 16, 2019
2a8795e
prettify tsconfig
SimenB Feb 16, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/jest-message-util/src/index.ts
Expand Up @@ -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 * from './types';
SimenB marked this conversation as resolved.
Show resolved Hide resolved

type Path = Config.Path;
type AssertionResult = TestResult.AssertionResult;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}

Expand Down
5 changes: 5 additions & 0 deletions packages/jest-message-util/src/types.ts
@@ -0,0 +1,5 @@
import {StackData} from 'stack-utils';

export interface Frame extends StackData {
file: string;
}
4 changes: 4 additions & 0 deletions packages/jest-snapshot/dts/natural-compare.d.ts
@@ -0,0 +1,4 @@
declare module 'natural-compare' {
doniyor2109 marked this conversation as resolved.
Show resolved Hide resolved
SimenB marked this conversation as resolved.
Show resolved Hide resolved
const NaturalCompare: (a: string, b: string) => number;
export default NaturalCompare;
}
3 changes: 3 additions & 0 deletions packages/jest-snapshot/package.json
Expand Up @@ -10,6 +10,7 @@
"main": "build/index.js",
"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",
Expand All @@ -22,7 +23,9 @@
},
"devDependencies": {
"@types/mkdirp": "^0.5.2",
"@types/prettier": "^1.16.1",
"@types/semver": "^5.5.0",
"jest-haste-map": "^24.0.0",
"prettier": "^1.13.4"
},
"engines": {
Expand Down
Expand Up @@ -4,12 +4,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,
Expand All @@ -19,41 +18,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 {
doniyor2109 marked this conversation as resolved.
Show resolved Hide resolved
_counters: Map<string, number>;
_dirty: boolean;
_index: number;
_updateSnapshot: SnapshotUpdateState;
_snapshotData: {[key: string]: string};
_snapshotPath: Path;
_inlineSnapshots: Array<InlineSnapshot>;
_uncheckedKeys: Set<string>;
_getBabelTraverse: () => Function;
_getPrettier: () => null | any;
private _counters: Map<string, number>;
private _dirty: boolean;
// @ts-ignore
private _index: number;
private _updateSnapshot: Config.SnapshotUpdateState;
private _snapshotData: SnapshotData;
private _snapshotPath: Config.Path;
private _inlineSnapshots: Array<InlineSnapshot>;
private _uncheckedKeys: Set<string>;
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,
Expand Down Expand Up @@ -83,15 +85,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(
Expand Down Expand Up @@ -251,7 +253,7 @@ export default class SnapshotState {
}
}

fail(testName: string, received: any, key?: string) {
fail(testName: string, _: any, key?: string) {
this._counters.set(testName, (this._counters.get(testName) || 0) + 1);
const count = Number(this._counters.get(testName));

Expand Down
Expand Up @@ -4,59 +4,47 @@
* 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';

const {saveInlineSnapshots} = require('../inline_snapshots');
import {saveInlineSnapshots} from '../inline_snapshots';

const writeFileSync = fs.writeFileSync;
const readFileSync = fs.readFileSync;
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(
[
Expand All @@ -79,12 +67,11 @@ 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(
[
Expand All @@ -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,
Expand All @@ -108,10 +97,9 @@ 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(
[
Expand All @@ -132,10 +120,9 @@ 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(
Expand All @@ -154,10 +141,9 @@ 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 save = () =>
Expand All @@ -174,10 +160,9 @@ 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};
saveInlineSnapshots([{frame, snapshot: '`'}], prettier, babelTraverse);
Expand All @@ -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,
});
Expand Down
Expand Up @@ -5,15 +5,19 @@
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';

const {toMatchSnapshot} = require('../');
const jestSnapshot = require('../');
doniyor2109 marked this conversation as resolved.
Show resolved Hide resolved

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: {
// @ts-ignore
match: (testName: string, received: any) => ({actual, expected}), // eslint-disable-line
SimenB marked this conversation as resolved.
Show resolved Hide resolved
},
});

const matcherResult = matcher({a: 1});
Expand Down
Expand Up @@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';

import prettyFormat from 'pretty-format';

Expand Down
Expand Up @@ -5,11 +5,10 @@
* 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 =>
Expand Down