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

Fix pretty print for closeTo matcher #12626

Merged
merged 15 commits into from Apr 14, 2022
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -59,6 +59,7 @@
- `[expect]` Move typings of `.not`, `.rejects` and `.resolves` modifiers outside of `Matchers` interface ([#12346](https://github.com/facebook/jest/pull/12346))
- `[expect]` Throw useful error if `expect.extend` is called with invalid matchers ([#12488](https://github.com/facebook/jest/pull/12488))
- `[expect]` Fix `iterableEquality` ignores other properties ([#8359](https://github.com/facebook/jest/pull/8359))
- `[expect]` Fix print for the `closeTo` matcher ([#12626](https://github.com/facebook/jest/pull/12626))
- `[jest-circus, @jest/types]` Disallow undefined value in `TestContext` type ([#12507](https://github.com/facebook/jest/pull/12507))
- `[jest-config]` Correctly detect CI environment and update snapshots accordingly ([#12378](https://github.com/facebook/jest/pull/12378))
- `[jest-config]` Pass `moduleTypes` to `ts-node` to enforce CJS when transpiling ([#12397](https://github.com/facebook/jest/pull/12397))
Expand Down
9 changes: 9 additions & 0 deletions packages/expect/src/asymmetricMatchers.ts
Expand Up @@ -13,6 +13,7 @@ import {
subsetEquality,
} from '@jest/expect-utils';
import * as matcherUtils from 'jest-matcher-utils';
import {pluralize} from 'jest-util';
import {getState} from './jestMatchersObject';
import type {
AsymmetricMatcher as AsymmetricMatcherInterface,
Expand Down Expand Up @@ -329,6 +330,14 @@ class CloseTo extends AsymmetricMatcher<number> {
override getExpectedType() {
return 'number';
}

override toAsymmetricMatcher(): string {
return [
this.toString(),
this.sample,
`(${pluralize('digit', this.precision)})`,
].join(' ');
}
}

export const any = (expectedObject: unknown): Any => new Any(expectedObject);
Expand Down
1 change: 1 addition & 0 deletions packages/expect/src/index.ts
Expand Up @@ -49,6 +49,7 @@ import type {
ThrowingMatcherFn,
} from './types';

export {AsymmetricMatcher} from './asymmetricMatchers';
export type {
AsymmetricMatchers,
BaseExpect,
Expand Down
1 change: 1 addition & 0 deletions packages/pretty-format/package.json
Expand Up @@ -29,6 +29,7 @@
"@types/react": "*",
"@types/react-is": "^17.0.0",
"@types/react-test-renderer": "*",
"expect": "^28.0.0-alpha.8",
"immutable": "^4.0.0",
"jest-util": "^28.0.0-alpha.8",
"react": "*",
Expand Down
55 changes: 55 additions & 0 deletions packages/pretty-format/src/__tests__/AsymmetricMatcher.test.ts
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import {AsymmetricMatcher as AbstractAsymmetricMatcher} from 'expect';
import prettyFormat, {plugins} from '../';
import type {OptionsReceived} from '../types';

Expand Down Expand Up @@ -131,6 +132,42 @@ test('stringNotMatching(string)', () => {
expect(result).toEqual('StringNotMatching /jest/');
});

test('closeTo(number, precision)', () => {
const result = prettyFormat(expect.closeTo(1.2345, 4), options);
expect(result).toEqual('NumberCloseTo 1.2345 (4 digits)');
});

test('notCloseTo(number, precision)', () => {
const result = prettyFormat(expect.not.closeTo(1.2345, 1), options);
expect(result).toEqual('NumberNotCloseTo 1.2345 (1 digit)');
});

test('closeTo(number)', () => {
const result = prettyFormat(expect.closeTo(1.2345), options);
expect(result).toEqual('NumberCloseTo 1.2345 (2 digits)');
});

test('closeTo(Infinity)', () => {
const result = prettyFormat(expect.closeTo(-Infinity), options);
expect(result).toEqual('NumberCloseTo -Infinity (2 digits)');
});

test('closeTo(scientific number)', () => {
const result = prettyFormat(expect.closeTo(1.56e-3, 4), options);
expect(result).toEqual('NumberCloseTo 0.00156 (4 digits)');
});

test('closeTo(very small scientific number)', () => {
const result = prettyFormat(expect.closeTo(1.56e-10, 4), options);
expect(result).toEqual('NumberCloseTo 1.56e-10 (4 digits)');
});

test('correctly handles inability to pretty-print matcher', () => {
expect(() => prettyFormat(new DummyMatcher(1), options)).toThrow(
'Asymmetric matcher DummyMatcher does not implement toAsymmetricMatcher()',
);
});

test('supports multiple nested asymmetric matchers', () => {
const result = prettyFormat(
{
Expand Down Expand Up @@ -311,3 +348,21 @@ test('min option', () => {
'{"test": {"nested": ObjectContaining {"a": ArrayContaining [1], "b": Anything, "c": Any<String>, "d": StringContaining "jest", "e": StringMatching /jest/, "f": ObjectContaining {"test": "case"}}}}',
);
});

class DummyMatcher extends AbstractAsymmetricMatcher<number> {
constructor(sample: number) {
super(sample);
}

asymmetricMatch(other: number) {
return this.sample === other;
}

toString() {
return 'DummyMatcher';
}

override getExpectedType() {
return 'number';
}
}
6 changes: 6 additions & 0 deletions packages/pretty-format/src/plugins/AsymmetricMatcher.ts
Expand Up @@ -80,6 +80,12 @@ export const serialize: NewPlugin['serialize'] = (
);
}

if (typeof val.toAsymmetricMatcher !== 'function') {
throw new Error(
`Asymmetric matcher ${val.constructor.name} does not implement toAsymmetricMatcher()`,
SimenB marked this conversation as resolved.
Show resolved Hide resolved
);
}

return val.toAsymmetricMatcher();
};

Expand Down
1 change: 1 addition & 0 deletions packages/pretty-format/tsconfig.json
Expand Up @@ -6,5 +6,6 @@
},
"include": ["./src/**/*"],
"exclude": ["./**/__tests__/**/*"],
// no `expect`, only used in tests
"references": [{"path": "../jest-schemas"}, {"path": "../jest-util"}]
}
9 changes: 8 additions & 1 deletion scripts/buildTs.mjs
Expand Up @@ -62,6 +62,13 @@ import {getPackages} from './buildUtils.mjs';
}
}

// dev dep
if (pkg.name === 'pretty-format') {
if (dep === 'expect') {
return false;
}
}

return true;
})
.map(dep =>
Expand All @@ -84,7 +91,7 @@ import {getPackages} from './buildUtils.mjs';
assert.deepStrictEqual(
references,
jestDependenciesOfPackage,
`Expected declared references to match dependencies in packages ${
`Expected declared references to match dependencies in package ${
pkg.name
}. Got:\n\n${references.join(
'\n',
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Expand Up @@ -17974,6 +17974,7 @@ __metadata:
"@types/react-test-renderer": "*"
ansi-regex: ^5.0.1
ansi-styles: ^5.0.0
expect: ^28.0.0-alpha.8
immutable: ^4.0.0
jest-util: ^28.0.0-alpha.8
react: "*"
Expand Down