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

Expose this.equals to custom matchers. #3469

Merged
merged 1 commit into from
May 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/en/ExpectAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ These helper functions can be found on `this` inside a custom matcher:

A boolean to let you know this matcher was called with the negated `.not` modifier allowing you to flip your assertion.

#### `this.equals(a, b)`

This is a deep-equality function that will return `true` if two objects have the same values (recursively).

#### `this.utils`

There are a number of helpful tools exposed on `this.utils` primarily consisting of the exports from [`jest-matcher-utils`](https://github.com/facebook/jest/tree/master/packages/jest-matcher-utils).
Expand Down
14 changes: 14 additions & 0 deletions packages/jest-matchers/src/__tests__/extend-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

'use strict';

const {equals} = require('../jasmine-utils');
const jestExpect = require('../');
const matcherUtils = require('jest-matcher-utils');

Expand Down Expand Up @@ -60,3 +61,16 @@ it('is ok if there is no message specified', () => {
jestExpect(true).toFailWithoutMessage(),
).toThrowErrorMatchingSnapshot();
});

it('exposes an equality function to custom matchers', () => {
// jestExpect and expect share the same global state
expect.assertions(3);
jestExpect.extend({
toBeOne() {
expect(this.equals).toBe(equals);
return {pass: !!this.equals(1, 1)};
},
});

expect(() => jestExpect().toBeOne()).not.toThrow();
});
11 changes: 6 additions & 5 deletions packages/jest-matchers/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
Expect,
ExpectationObject,
ExpectationResult,
MatcherContext,
MatcherState,
MatchersObject,
RawMatcherFn,
ThrowingMatcherFn,
Expand All @@ -24,7 +24,7 @@ import type {
const matchers = require('./matchers');
const spyMatchers = require('./spyMatchers');
const toThrowMatchers = require('./toThrowMatchers');

const {equals} = require('./jasmine-utils');
const utils = require('jest-matcher-utils');
const {
any,
Expand Down Expand Up @@ -194,7 +194,7 @@ const makeThrowingMatcher = (
): ThrowingMatcherFn => {
return function throwingMatcher(...args) {
let throws = true;
const matcherContext: MatcherContext = Object.assign(
const matcherContext: MatcherState = Object.assign(
// When throws is disabled, the matcher will not throw errors during test
// execution but instead add them to the global matcher state. If a
// matcher throws, test execution is normally stopped immediately. The
Expand All @@ -203,6 +203,7 @@ const makeThrowingMatcher = (
{dontThrow: () => (throws = false)},
global[GLOBAL_STATE].state,
{
equals,
isNot,
utils,
},
Expand Down Expand Up @@ -241,8 +242,8 @@ const makeThrowingMatcher = (
};
};

expect.extend = (matchersObj: MatchersObject): void => {
Object.assign(global[GLOBAL_STATE].matchers, matchersObj);
expect.extend = (matchers: MatchersObject): void => {
Object.assign(global[GLOBAL_STATE].matchers, matchers);
};

expect.anything = anything;
Expand Down
3 changes: 2 additions & 1 deletion types/Matchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ export type RawMatcherFn = (

export type ThrowingMatcherFn = (actual: any) => void;
export type PromiseMatcherFn = (actual: any) => Promise<void>;
export type MatcherContext = {isNot: boolean};
export type MatcherState = {
assertionCalls: number,
currentTestName?: string,
equals: (any, any) => boolean,
expand?: boolean,
expectedAssertionsNumber: ?number,
isExpectingAssertions: ?boolean,
isNot: boolean,
snapshotState: SnapshotState,
suppressedErrors: Array<Error>,
testPath?: Path,
utils: Object,
};

export type AsymmetricMatcher = Object;
Expand Down