Skip to content

Commit

Permalink
Move toMatchSnapshot to jest-matchers package
Browse files Browse the repository at this point in the history
  • Loading branch information
maximderbin authored and aaronabramov committed Sep 20, 2016
1 parent 047144b commit 49ba0cc
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 100 deletions.
2 changes: 1 addition & 1 deletion integration_tests/snapshot/__tests__/snapshot-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe('snapshot', () => {

it('cannot be used with .not', () => {
expect(() => expect('').not.toMatchSnapshot()).toThrow(
new Error('Jest: `.not` can not be used with `.toMatchSnapShot()`.')
new Error('Jest: `.not` can not be used with `.toMatchSnapshot()`.')
);
});
});
14 changes: 9 additions & 5 deletions packages/jest-jasmine2/src/extendJasmineExpect.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ const jestExpect = require('jest-matchers').expect;

const jasmineExpect = global.expect;

console.log(jasmine.Spec);

// extend jasmine matchers with `jest-matchers`
global.expect = actual => {
const jasmineMatchers = jasmineExpect(actual);
const jestMatchers = jestExpect(actual);
const not = Object.assign(jasmineMatchers.not, jestMatchers.not);
return Object.assign(jasmineMatchers, jestMatchers, {not});
module.exports = matchersContext => {
global.expect = actual => {
const jasmineMatchers = jasmineExpect(actual);
const jestMatchers = jestExpect(actual, matchersContext);
const not = Object.assign(jasmineMatchers.not, jestMatchers.not);
return Object.assign(jasmineMatchers, jestMatchers, {not});
};
};
10 changes: 1 addition & 9 deletions packages/jest-jasmine2/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,6 @@ function jasmine2(
);

env.beforeEach(() => {
jasmine.addMatchers({
toMatchSnapshot: snapshot.matcher(
testPath,
config,
snapshotState,
),
});

if (config.resetModules) {
runtime.resetModules();
}
Expand All @@ -127,7 +119,7 @@ function jasmine2(
// class of the test and `error instanceof Error` will return `false`.
runtime.requireInternalModule(
path.resolve(__dirname, './extendJasmineExpect.js'),
);
)({snapshotState, updateSnapshot: config.updateSnapshot});

if (config.setupTestFrameworkScriptFile) {
runtime.requireModule(config.setupTestFrameworkScriptFile);
Expand Down
1 change: 1 addition & 0 deletions packages/jest-matchers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"dependencies": {
"jest-diff": "^15.1.0",
"jest-matcher-utils": "^15.1.0",
"jest-snapshot": "^15.1.1",
"jest-util": "^15.1.1"
},
"devDependencies": {
Expand Down
18 changes: 14 additions & 4 deletions packages/jest-matchers/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const toThrowMatchers = require('./toThrowMatchers');
const {stringify} = require('jest-matcher-utils');

const GLOBAL_MATCHERS_OBJECT_SYMBOL = Symbol.for('$$jest-matchers-object');
const CAN_NOT_BE_USED_WITH_NOT = [
'toMatchSnapshot',
];

class JestAssertionError extends Error {}

Expand All @@ -38,14 +41,20 @@ if (!global[GLOBAL_MATCHERS_OBJECT_SYMBOL]) {
);
}

const expect: Expect = (actual: any): ExpectationObject => {
const expect: Expect = (
actual: any,
matchersContext: MatchersContext,
): ExpectationObject => {
const allMatchers = global[GLOBAL_MATCHERS_OBJECT_SYMBOL];
const expectation = {not: {}};
Object.keys(allMatchers).forEach(name => {
expectation[name] =
makeThrowingMatcher(allMatchers[name], false, actual);
expectation.not[name] =
makeThrowingMatcher(allMatchers[name], true, actual);
makeThrowingMatcher(allMatchers[name], false, actual, matchersContext);
expectation.not[name] = CAN_NOT_BE_USED_WITH_NOT.indexOf(name) >= 0
? () => {
throw new Error(`Jest: \`.not\` can not be used with \`.${name}()\`.`);
}
: makeThrowingMatcher(allMatchers[name], true, actual, matchersContext);
});

return expectation;
Expand All @@ -55,6 +64,7 @@ const makeThrowingMatcher = (
matcher: RawMatcherFn,
isNot: boolean,
actual: any,
matchersContext: MatchersContext,
): ThrowingMatcherFn => {
return function throwingMatcher(expected, ...rest) {
const matcherContext: MatcherContext = {isNot};
Expand Down
15 changes: 13 additions & 2 deletions packages/jest-matchers/src/matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@

'use strict';

import type {MatchersObject} from './types';
import type {
MatchersObject,
MatchersContext,
} from './types';

const snapshot = require('jest-snapshot');
const diff = require('jest-diff');
const {escapeStrForRegex} = require('jest-util');
const {
Expand Down Expand Up @@ -338,7 +342,12 @@ const matchers: MatchersObject = {
return {message, pass};
},

toBeCloseTo(actual: number, expected: number, precision?: number = 2) {
toBeCloseTo(
actual: number,
expected: number,
matchersContext: MatchersContext,
precision?: number = 2,
) {
ensureNumbers(actual, expected, '.toBeCloseTo');
const pass = Math.abs(expected - actual) < (Math.pow(10, -precision) / 2);
const message = pass
Expand Down Expand Up @@ -392,6 +401,8 @@ const matchers: MatchersObject = {

return {message, pass};
},

toMatchSnapshot: snapshot.matcher,
};

module.exports = matchers;
11 changes: 10 additions & 1 deletion packages/jest-matchers/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
'use strict';

import type {SnapshotState} from '../../jest-snapshot/src/SnapshotState';

export type ExpectationResult = {
pass: boolean,
message: string | () => string,
Expand All @@ -23,8 +25,15 @@ export type RawMatcherFn = (
export type ThrowingMatcherFn = (actual: any) => void;
export type MatcherContext = {isNot: boolean};
export type MatchersObject = {[id:string]: RawMatcherFn};
export type Expect = (expected: any) => ExpectationObject;
export type Expect = (
expected: any,
matchersContext: MatchersContext,
) => ExpectationObject;
export type ExpectationObject = {
[id: string]: ThrowingMatcherFn,
not: {[id: string]: ThrowingMatcherFn},
};
export type MatchersContext = {
snapshotState: SnapshotState,
updateSnapshot: boolean,
};
127 changes: 49 additions & 78 deletions packages/jest-snapshot/src/matcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
*/
'use strict';

import type {Path} from 'types/Config';
import type {SnapshotState} from './SnapshotState';
import type {MatchersContext} from '../../jest-matchers/src/types';

const diff = require('jest-diff');
const {
Expand All @@ -19,89 +18,61 @@ const {
RECEIVED_COLOR,
} = require('jest-matcher-utils');

type CompareResult = {
pass: boolean,
message: ?string,
};

module.exports = (
filePath: Path,
options: Object,
snapshotState: SnapshotState,
) => (util: any, customEquality: any) => {
return {
negativeCompare() {
throw new Error(
'Jest: `.not` can not be used with `.toMatchSnapshot()`.',
);
},
compare(actual: any, expected: any): CompareResult {
if (expected !== undefined) {
throw new Error(
'Jest: toMatchSnapshot() does not accept parameters.',
);
}
actual: any,
expected: void,
{snapshotState, updateSnapshot}: MatchersContext,
) => {
const snapshot = snapshotState.snapshot;
const count = snapshotState.incrementCounter();
const key = snapshotState.getSpecName() + ' ' + count;
const hasSnapshot = snapshot.has(key);
let pass = false;
let message = '';

const snapshot = snapshotState.snapshot;
const count = snapshotState.incrementCounter();
const key = snapshotState.getSpecName() + ' ' + count;
const hasSnapshot = snapshot.has(key);
let pass = false;
let message;

if (
!snapshot.fileExists() ||
(hasSnapshot && options.updateSnapshot) ||
!hasSnapshot
) {
if (options.updateSnapshot) {
if (!snapshot.matches(key, actual).pass) {
if (hasSnapshot) {
snapshotState.updated++;
} else {
snapshotState.added++;
}
snapshot.add(key, actual);
} else {
snapshotState.matched++;
}
if (
!snapshot.fileExists() ||
(hasSnapshot && updateSnapshot) ||
!hasSnapshot
) {
if (updateSnapshot) {
if (!snapshot.matches(key, actual).pass) {
if (hasSnapshot) {
snapshotState.updated++;
} else {
snapshot.add(key, actual);
snapshotState.added++;
}
pass = true;
snapshot.add(key, actual);
} else {
const matches = snapshot.matches(key, actual);
pass = matches.pass;
if (!pass) {
snapshotState.unmatched++;
const expectedString = matches.expected.trim();
const actualString = matches.actual.trim();
const diffMessage = diff(
expectedString,
actualString,
{
aAnnotation: 'Snapshot',
bAnnotation: 'Received',
},
);
message =
matcherHint('.toMatchSnapshot', 'value', '') + '\n\n' +
`${RECEIVED_COLOR('Received value')} does not match ` +
`${EXPECTED_COLOR('stored snapshot ' + count)}.\n\n` +
(diffMessage || (
RECEIVED_COLOR('- ' + expectedString) + '\n' +
EXPECTED_COLOR('+ ' + actualString)
));
} else {
snapshotState.matched++;
}
snapshotState.matched++;
}
} else {
snapshot.add(key, actual);
snapshotState.added++;
}
pass = true;
} else {
const matches = snapshot.matches(key, actual);
pass = matches.pass;
if (!pass) {
snapshotState.unmatched++;
message =
`Received value does not match the stored snapshot ${count}.\n\n` +
diff(
matches.expected.trim(),
matches.actual.trim(),
{
aAnnotation: 'Snapshot',
bAnnotation: 'Received',
},
);
} else {
snapshotState.matched++;
}
}

return {
pass,
message,
};
},
return {
pass,
message,
};
};

0 comments on commit 49ba0cc

Please sign in to comment.