@fgv/ts-utils-jest 5.0.0-2 → 5.0.0-21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +16 -0
- package/README.md +11 -0
- package/config/api-extractor.json +343 -0
- package/config/jest-disable-colors.js +34 -0
- package/config/rig.json +16 -0
- package/lib/helpers/fsHelpers.test.d.ts +2 -0
- package/lib/index.test.d.ts +2 -0
- package/lib/matchers/toFail/index.test.d.ts +2 -0
- package/lib/matchers/toFail/predicate.test.d.ts +2 -0
- package/lib/matchers/toFailTest/index.test.d.ts +2 -0
- package/lib/matchers/toFailTest/predicate.test.d.ts +2 -0
- package/lib/matchers/toFailTestAndMatchSnapshot/index.js +2 -1
- package/lib/matchers/toFailTestAndMatchSnapshot/index.test.d.ts +2 -0
- package/lib/matchers/toFailTestAndMatchSnapshot/predicate.test.d.ts +2 -0
- package/lib/matchers/toFailTestWith/index.test.d.ts +2 -0
- package/lib/matchers/toFailTestWith/predicate.test.d.ts +2 -0
- package/lib/matchers/toFailWith/index.test.d.ts +2 -0
- package/lib/matchers/toFailWith/predicate.test.d.ts +2 -0
- package/lib/matchers/toFailWithDetail/index.test.d.ts +2 -0
- package/lib/matchers/toFailWithDetail/predicate.test.d.ts +2 -0
- package/lib/matchers/toHaveBeenCalledWithArgumentsMatching/index.test.d.ts +2 -0
- package/lib/matchers/toHaveBeenCalledWithArgumentsMatching/predicate.test.d.ts +2 -0
- package/lib/matchers/toSucceed/index.test.d.ts +2 -0
- package/lib/matchers/toSucceed/predicate.test.d.ts +2 -0
- package/lib/matchers/toSucceedAndMatchInlineSnapshot/index.test.d.ts +2 -0
- package/lib/matchers/toSucceedAndMatchSnapshot/index.test.d.ts +2 -0
- package/lib/matchers/toSucceedAndSatisfy/index.test.d.ts +2 -0
- package/lib/matchers/toSucceedAndSatisfy/predicate.test.d.ts +2 -0
- package/lib/matchers/toSucceedWith/index.test.d.ts +2 -0
- package/lib/matchers/toSucceedWith/predicate.test.d.ts +2 -0
- package/lib/matchers/toSucceedWithDetail/index.test.d.ts +2 -0
- package/lib/matchers/toSucceedWithDetail/predicate.test.d.ts +2 -0
- package/lib/resolvers/resolvers.test.d.ts +2 -0
- package/lib/tsdoc-metadata.json +1 -1
- package/lib/utils/colorHelpers.d.ts +54 -0
- package/lib/utils/colorHelpers.js +84 -0
- package/lib/utils/matcherHelpers.js +9 -5
- package/package.json +8 -8
- package/src/__snapshots__/index.test.ts.snap +24 -0
- package/src/helpers/fsHelpers.ts +184 -0
- package/src/helpers/index.ts +1 -0
- package/src/index.ts +27 -0
- package/src/matchers/index.ts +29 -0
- package/src/matchers/toFail/__snapshots__/index.test.ts.snap +17 -0
- package/src/matchers/toFail/index.ts +45 -0
- package/src/matchers/toFail/predicate.ts +7 -0
- package/src/matchers/toFailTest/__snapshots__/index.test.ts.snap +15 -0
- package/src/matchers/toFailTest/index.ts +48 -0
- package/src/matchers/toFailTest/predicate.ts +8 -0
- package/src/matchers/toFailTestAndMatchSnapshot/__snapshots__/index.test.ts.snap +14 -0
- package/src/matchers/toFailTestAndMatchSnapshot/index.ts +48 -0
- package/src/matchers/toFailTestAndMatchSnapshot/predicate.ts +12 -0
- package/src/matchers/toFailTestWith/__snapshots__/index.test.ts.snap +34 -0
- package/src/matchers/toFailTestWith/index.ts +56 -0
- package/src/matchers/toFailTestWith/predicate.ts +24 -0
- package/src/matchers/toFailWith/__snapshots__/index.test.ts.snap +25 -0
- package/src/matchers/toFailWith/index.ts +52 -0
- package/src/matchers/toFailWith/predicate.ts +16 -0
- package/src/matchers/toFailWithDetail/__snapshots__/index.test.ts.snap +41 -0
- package/src/matchers/toFailWithDetail/index.ts +63 -0
- package/src/matchers/toFailWithDetail/predicate.ts +27 -0
- package/src/matchers/toHaveBeenCalledWithArgumentsMatching/__snapshots__/index.test.ts.snap +82 -0
- package/src/matchers/toHaveBeenCalledWithArgumentsMatching/index.ts +100 -0
- package/src/matchers/toHaveBeenCalledWithArgumentsMatching/predicate.ts +18 -0
- package/src/matchers/toSucceed/__snapshots__/index.test.ts.snap +17 -0
- package/src/matchers/toSucceed/index.ts +45 -0
- package/src/matchers/toSucceed/predicate.ts +7 -0
- package/src/matchers/toSucceedAndMatchInlineSnapshot/__snapshots__/index.test.ts.snap +15 -0
- package/src/matchers/toSucceedAndMatchInlineSnapshot/index.ts +44 -0
- package/src/matchers/toSucceedAndMatchSnapshot/__snapshots__/index.test.ts.snap +27 -0
- package/src/matchers/toSucceedAndMatchSnapshot/index.ts +47 -0
- package/src/matchers/toSucceedAndSatisfy/__snapshots__/index.test.ts.snap +37 -0
- package/src/matchers/toSucceedAndSatisfy/index.ts +78 -0
- package/src/matchers/toSucceedAndSatisfy/predicate.ts +22 -0
- package/src/matchers/toSucceedWith/__snapshots__/index.test.ts.snap +25 -0
- package/src/matchers/toSucceedWith/index.ts +58 -0
- package/src/matchers/toSucceedWith/predicate.ts +14 -0
- package/src/matchers/toSucceedWithDetail/__snapshots__/index.test.ts.snap +41 -0
- package/src/matchers/toSucceedWithDetail/index.ts +62 -0
- package/src/matchers/toSucceedWithDetail/predicate.ts +23 -0
- package/src/resolvers/cli.ts +21 -0
- package/src/resolvers/ide.ts +21 -0
- package/src/ts-utils.ts +1 -0
- package/src/types/index.ts +107 -0
- package/src/utils/colorHelpers.ts +82 -0
- package/src/utils/matcherHelpers.ts +64 -0
- package/src/utils/snapshotResolver.ts +28 -0
- package/test/data/testData.json +4 -0
- package/CHANGELOG.md +0 -105
- package/lib/helpers/fsHelpers.d.ts.map +0 -1
- package/lib/helpers/fsHelpers.js.map +0 -1
- package/lib/helpers/index.d.ts.map +0 -1
- package/lib/helpers/index.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/matchers/index.d.ts.map +0 -1
- package/lib/matchers/index.js.map +0 -1
- package/lib/matchers/toFail/index.d.ts.map +0 -1
- package/lib/matchers/toFail/index.js.map +0 -1
- package/lib/matchers/toFail/predicate.d.ts.map +0 -1
- package/lib/matchers/toFail/predicate.js.map +0 -1
- package/lib/matchers/toFailTest/index.d.ts.map +0 -1
- package/lib/matchers/toFailTest/index.js.map +0 -1
- package/lib/matchers/toFailTest/predicate.d.ts.map +0 -1
- package/lib/matchers/toFailTest/predicate.js.map +0 -1
- package/lib/matchers/toFailTestAndMatchSnapshot/index.d.ts.map +0 -1
- package/lib/matchers/toFailTestAndMatchSnapshot/index.js.map +0 -1
- package/lib/matchers/toFailTestAndMatchSnapshot/predicate.d.ts.map +0 -1
- package/lib/matchers/toFailTestAndMatchSnapshot/predicate.js.map +0 -1
- package/lib/matchers/toFailTestWith/index.d.ts.map +0 -1
- package/lib/matchers/toFailTestWith/index.js.map +0 -1
- package/lib/matchers/toFailTestWith/predicate.d.ts.map +0 -1
- package/lib/matchers/toFailTestWith/predicate.js.map +0 -1
- package/lib/matchers/toFailWith/index.d.ts.map +0 -1
- package/lib/matchers/toFailWith/index.js.map +0 -1
- package/lib/matchers/toFailWith/predicate.d.ts.map +0 -1
- package/lib/matchers/toFailWith/predicate.js.map +0 -1
- package/lib/matchers/toFailWithDetail/index.d.ts.map +0 -1
- package/lib/matchers/toFailWithDetail/index.js.map +0 -1
- package/lib/matchers/toFailWithDetail/predicate.d.ts.map +0 -1
- package/lib/matchers/toFailWithDetail/predicate.js.map +0 -1
- package/lib/matchers/toHaveBeenCalledWithArgumentsMatching/index.d.ts.map +0 -1
- package/lib/matchers/toHaveBeenCalledWithArgumentsMatching/index.js.map +0 -1
- package/lib/matchers/toHaveBeenCalledWithArgumentsMatching/predicate.d.ts.map +0 -1
- package/lib/matchers/toHaveBeenCalledWithArgumentsMatching/predicate.js.map +0 -1
- package/lib/matchers/toSucceed/index.d.ts.map +0 -1
- package/lib/matchers/toSucceed/index.js.map +0 -1
- package/lib/matchers/toSucceed/predicate.d.ts.map +0 -1
- package/lib/matchers/toSucceed/predicate.js.map +0 -1
- package/lib/matchers/toSucceedAndMatchInlineSnapshot/index.d.ts.map +0 -1
- package/lib/matchers/toSucceedAndMatchInlineSnapshot/index.js.map +0 -1
- package/lib/matchers/toSucceedAndMatchSnapshot/index.d.ts.map +0 -1
- package/lib/matchers/toSucceedAndMatchSnapshot/index.js.map +0 -1
- package/lib/matchers/toSucceedAndSatisfy/index.d.ts.map +0 -1
- package/lib/matchers/toSucceedAndSatisfy/index.js.map +0 -1
- package/lib/matchers/toSucceedAndSatisfy/predicate.d.ts.map +0 -1
- package/lib/matchers/toSucceedAndSatisfy/predicate.js.map +0 -1
- package/lib/matchers/toSucceedWith/index.d.ts.map +0 -1
- package/lib/matchers/toSucceedWith/index.js.map +0 -1
- package/lib/matchers/toSucceedWith/predicate.d.ts.map +0 -1
- package/lib/matchers/toSucceedWith/predicate.js.map +0 -1
- package/lib/matchers/toSucceedWithDetail/index.d.ts.map +0 -1
- package/lib/matchers/toSucceedWithDetail/index.js.map +0 -1
- package/lib/matchers/toSucceedWithDetail/predicate.d.ts.map +0 -1
- package/lib/matchers/toSucceedWithDetail/predicate.js.map +0 -1
- package/lib/resolvers/cli.d.ts.map +0 -1
- package/lib/resolvers/cli.js.map +0 -1
- package/lib/resolvers/ide.d.ts.map +0 -1
- package/lib/resolvers/ide.js.map +0 -1
- package/lib/ts-utils.d.ts.map +0 -1
- package/lib/ts-utils.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/index.js.map +0 -1
- package/lib/utils/matcherHelpers.d.ts.map +0 -1
- package/lib/utils/matcherHelpers.js.map +0 -1
- package/lib/utils/snapshotResolver.d.ts.map +0 -1
- package/lib/utils/snapshotResolver.js.map +0 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`.toFailTestWith logs failure correctly when callback fails with .not: toFailTestAndMatchSnapshot 1`] = `
|
|
4
|
+
"expect(callback).not.toFailTestWith(expectedMessage)
|
|
5
|
+
Expected:
|
|
6
|
+
Not failure with /expect/i
|
|
7
|
+
Received: Callback failed with:
|
|
8
|
+
>>>>
|
|
9
|
+
expect(received).toBe(expected) // Object.is equality
|
|
10
|
+
|
|
11
|
+
Expected: false
|
|
12
|
+
Received: true
|
|
13
|
+
<<<<"
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
exports[`.toFailTestWith logs failure correctly when callback returns an unexpected value: toFailTestAndMatchSnapshot 1`] = `
|
|
17
|
+
"expect(callback).toFailTestWith(expectedMessage)
|
|
18
|
+
Expected:
|
|
19
|
+
Failure with /random text/i
|
|
20
|
+
Received: Callback failed with:
|
|
21
|
+
>>>>
|
|
22
|
+
expect(received).toBe(expected) // Object.is equality
|
|
23
|
+
|
|
24
|
+
Expected: \\"goodbye\\"
|
|
25
|
+
Received: \\"hello\\"
|
|
26
|
+
<<<<"
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
exports[`.toFailTestWith logs failure correctly when callback succeeds: toFailTestAndMatchSnapshot 1`] = `
|
|
30
|
+
"expect(callback).toFailTestWith(expectedMessage)
|
|
31
|
+
Expected:
|
|
32
|
+
Failure with \\"whatever\\"
|
|
33
|
+
Received: Callback succeeded"
|
|
34
|
+
`;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars,no-unused-vars */
|
|
2
|
+
import { Failure, Success } from '../../ts-utils';
|
|
3
|
+
import { matcherName, predicate } from './predicate';
|
|
4
|
+
|
|
5
|
+
import { matcherHint } from 'jest-matcher-utils';
|
|
6
|
+
import { printExpectedResult } from '../../utils/matcherHelpers';
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
10
|
+
namespace jest {
|
|
11
|
+
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention
|
|
12
|
+
interface Matchers<R, T> {
|
|
13
|
+
/**
|
|
14
|
+
* Use .toFailTestWith to test a custom matcher by
|
|
15
|
+
* verifying that a test case fails as expected and
|
|
16
|
+
* reports an error matching a supplied value.
|
|
17
|
+
* @param expected -
|
|
18
|
+
*/
|
|
19
|
+
toFailTestWith<T>(expected: string | string[] | RegExp): R;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function passMessage<T>(cbResult: Success<string>, expected: RegExp | string | string[]): () => string {
|
|
25
|
+
return () =>
|
|
26
|
+
[
|
|
27
|
+
matcherHint(`.not.${matcherName}`, 'callback', 'expectedMessage'),
|
|
28
|
+
printExpectedResult('failure', false, expected),
|
|
29
|
+
` Received: Callback failed with:\n>>>>\n${cbResult.value}\n<<<<`
|
|
30
|
+
].join('\n');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function failMessage<T>(cbResult: Failure<string>, expected: RegExp | string | string[]): () => string {
|
|
34
|
+
return () =>
|
|
35
|
+
[
|
|
36
|
+
matcherHint(`${matcherName}`, 'callback', 'expectedMessage'),
|
|
37
|
+
printExpectedResult('failure', true, expected),
|
|
38
|
+
cbResult.message === ''
|
|
39
|
+
? ' Received: Callback succeeded'
|
|
40
|
+
: ` Received: Callback failed with:\n>>>>\n${cbResult.message}\n<<<<`
|
|
41
|
+
].join('\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
toFailTestWith: function <T>(
|
|
46
|
+
cb: () => void,
|
|
47
|
+
expected: RegExp | string | string[]
|
|
48
|
+
): jest.CustomMatcherResult {
|
|
49
|
+
const cbResult = predicate(cb, expected);
|
|
50
|
+
if (cbResult.isSuccess()) {
|
|
51
|
+
return { pass: true, message: passMessage(cbResult, expected) };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { pass: false, message: failMessage(cbResult, expected) };
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars,no-unused-vars */
|
|
2
|
+
import { equals } from '@jest/expect-utils';
|
|
3
|
+
import { stringify } from 'jest-matcher-utils';
|
|
4
|
+
import { Result, captureResult, fail, succeed } from '../../ts-utils';
|
|
5
|
+
|
|
6
|
+
export const matcherName: string = 'toFailTestWith';
|
|
7
|
+
|
|
8
|
+
export function predicate<T>(cb: () => void, expected: string | string[] | RegExp): Result<string> {
|
|
9
|
+
const cbResult = captureResult(() => cb());
|
|
10
|
+
if (cbResult.isFailure()) {
|
|
11
|
+
let success = false;
|
|
12
|
+
if (expected instanceof RegExp) {
|
|
13
|
+
success = cbResult.message.match(expected) !== null;
|
|
14
|
+
} else if (typeof expected === 'string') {
|
|
15
|
+
success = cbResult.message === expected;
|
|
16
|
+
} else if (Array.isArray(expected)) {
|
|
17
|
+
success = equals(cbResult.message.split('\n'), expected);
|
|
18
|
+
} else {
|
|
19
|
+
return fail(`Unsupported expected value "${stringify(expected)}" for toFailTestWith`);
|
|
20
|
+
}
|
|
21
|
+
return success ? succeed(cbResult.message) : fail(cbResult.message);
|
|
22
|
+
}
|
|
23
|
+
return fail('');
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`.toFailWith reports details correctly on a failure due to a success result: toFailTestAndMatchSnapshot 1`] = `
|
|
4
|
+
"expect(received).toFailWith(expected)
|
|
5
|
+
Expected:
|
|
6
|
+
Failure with \\"hello\\"
|
|
7
|
+
Received:
|
|
8
|
+
Success with \\"hello\\""
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
exports[`.toFailWith reports details correctly on a failure due to non-matching failure value: toFailTestAndMatchSnapshot 1`] = `
|
|
12
|
+
"expect(received).toFailWith(expected)
|
|
13
|
+
Expected:
|
|
14
|
+
Failure with \\"error\\"
|
|
15
|
+
Received:
|
|
16
|
+
Failure with \\"oops\\""
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
exports[`.toFailWith reports details correctly on a failure with a .not: toFailTestAndMatchSnapshot 1`] = `
|
|
20
|
+
"expect(received).not.toFailWith(expected)
|
|
21
|
+
Expected:
|
|
22
|
+
Not failure with \\"oops\\"
|
|
23
|
+
Received:
|
|
24
|
+
Failure with \\"oops\\""
|
|
25
|
+
`;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { printExpectedResult, printReceivedResult } from '../../utils/matcherHelpers';
|
|
2
|
+
import { matcherName, predicate } from './predicate';
|
|
3
|
+
|
|
4
|
+
import { Result } from '@fgv/ts-utils';
|
|
5
|
+
import { matcherHint } from 'jest-matcher-utils';
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
|
+
namespace jest {
|
|
10
|
+
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention
|
|
11
|
+
interface Matchers<R, T> {
|
|
12
|
+
/**
|
|
13
|
+
* Use .toFailWith to verify that a Result<T> is a failure
|
|
14
|
+
* that matches a supplied string, RegExp or undefined value
|
|
15
|
+
* @param message -
|
|
16
|
+
*/
|
|
17
|
+
toFailWith(message: string | RegExp | undefined): R;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function passMessage<T>(received: Result<T>, expected: string | RegExp | undefined): () => string {
|
|
23
|
+
return () =>
|
|
24
|
+
[
|
|
25
|
+
matcherHint(`.not.${matcherName}`),
|
|
26
|
+
printExpectedResult('failure', false, expected),
|
|
27
|
+
printReceivedResult(received)
|
|
28
|
+
].join('\n');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function failMessage<T>(received: Result<T>, expected: string | RegExp | undefined): () => string {
|
|
32
|
+
return () =>
|
|
33
|
+
[
|
|
34
|
+
matcherHint(`${matcherName}`),
|
|
35
|
+
printExpectedResult('failure', true, expected),
|
|
36
|
+
printReceivedResult(received)
|
|
37
|
+
].join('\n');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default {
|
|
41
|
+
toFailWith: function <T>(
|
|
42
|
+
received: Result<T>,
|
|
43
|
+
expected: string | RegExp | undefined
|
|
44
|
+
): jest.CustomMatcherResult {
|
|
45
|
+
const pass = predicate(received, expected);
|
|
46
|
+
if (pass) {
|
|
47
|
+
return { pass: true, message: passMessage(received, expected) };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { pass: false, message: failMessage(received, expected) };
|
|
51
|
+
}
|
|
52
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Result } from '../../ts-utils';
|
|
2
|
+
|
|
3
|
+
export const matcherName: string = 'toFailWith';
|
|
4
|
+
|
|
5
|
+
export function predicate<T>(received: Result<T>, expected: string | RegExp | undefined): boolean {
|
|
6
|
+
if (received.isFailure()) {
|
|
7
|
+
if (expected === undefined) {
|
|
8
|
+
return received.message === undefined;
|
|
9
|
+
} else if (expected instanceof RegExp) {
|
|
10
|
+
return received.message.match(expected) !== null;
|
|
11
|
+
} else {
|
|
12
|
+
return received.message === expected;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`.toFailWithDetail reports details correctly on a failure due to a success result: toFailTestAndMatchSnapshot 1`] = `
|
|
4
|
+
"expect(received).toFailWith(expected)
|
|
5
|
+
Expected:
|
|
6
|
+
Failure with \\"hello\\"
|
|
7
|
+
Detail: \\"\\"detail\\"\\"
|
|
8
|
+
Received:
|
|
9
|
+
Success with \\"\\"hello\\"\\"
|
|
10
|
+
Detail: \\"undefined\\""
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
exports[`.toFailWithDetail reports details correctly on a failure due to non-matching detail value: toFailTestAndMatchSnapshot 1`] = `
|
|
14
|
+
"expect(received).toFailWith(expected)
|
|
15
|
+
Expected:
|
|
16
|
+
Failure with \\"error\\"
|
|
17
|
+
Detail: \\"\\"detail\\"\\"
|
|
18
|
+
Received:
|
|
19
|
+
Failure with \\"error\\"
|
|
20
|
+
Detail: \\"\\"other detail\\"\\""
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
exports[`.toFailWithDetail reports details correctly on a failure due to non-matching failure value: toFailTestAndMatchSnapshot 1`] = `
|
|
24
|
+
"expect(received).toFailWith(expected)
|
|
25
|
+
Expected:
|
|
26
|
+
Failure with \\"error\\"
|
|
27
|
+
Detail: \\"\\"detail\\"\\"
|
|
28
|
+
Received:
|
|
29
|
+
Failure with \\"oops\\"
|
|
30
|
+
Detail: \\"\\"detail\\"\\""
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
exports[`.toFailWithDetail reports details correctly on a failure with a .not: toFailTestAndMatchSnapshot 1`] = `
|
|
34
|
+
"expect(received).not.toFailWith(expected)
|
|
35
|
+
Expected:
|
|
36
|
+
Not failure with \\"oops\\"
|
|
37
|
+
Detail: \\"\\"detail\\"\\"
|
|
38
|
+
Received:
|
|
39
|
+
Failure with \\"oops\\"
|
|
40
|
+
Detail: \\"\\"detail\\"\\""
|
|
41
|
+
`;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DetailedResult, ResultDetailType } from '@fgv/ts-utils';
|
|
2
|
+
import { printExpectedDetailedResult, printReceivedDetailedResult } from '../../utils/matcherHelpers';
|
|
3
|
+
import { matcherName, predicate } from './predicate';
|
|
4
|
+
|
|
5
|
+
import { matcherHint } from 'jest-matcher-utils';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
|
|
8
|
+
declare global {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
10
|
+
namespace jest {
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars, @typescript-eslint/naming-convention
|
|
12
|
+
interface Matchers<R, T> {
|
|
13
|
+
/**
|
|
14
|
+
* Use .toFailWithDetail to verify that a DetailedResult<T> is
|
|
15
|
+
* a failure that matches both a supplied expected failure message
|
|
16
|
+
* (string, RegExp or undefined) and a supplied failure detail.
|
|
17
|
+
* @param message -
|
|
18
|
+
*/
|
|
19
|
+
toFailWithDetail(message: string | RegExp | undefined, detail: ResultDetailType<T>): R;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function passMessage<T, TD>(
|
|
25
|
+
received: DetailedResult<T, TD>,
|
|
26
|
+
expectedMessage: string | RegExp | undefined,
|
|
27
|
+
expectedDetail: TD
|
|
28
|
+
): () => string {
|
|
29
|
+
return () =>
|
|
30
|
+
[
|
|
31
|
+
matcherHint(`.not.${matcherName}`),
|
|
32
|
+
printExpectedDetailedResult('failure', false, expectedMessage, expectedDetail),
|
|
33
|
+
printReceivedDetailedResult(received)
|
|
34
|
+
].join('\n');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function failMessage<T, TD>(
|
|
38
|
+
received: DetailedResult<T, TD>,
|
|
39
|
+
expectedMessage: string | RegExp | undefined,
|
|
40
|
+
expectedDetail: TD
|
|
41
|
+
): () => string {
|
|
42
|
+
return () =>
|
|
43
|
+
[
|
|
44
|
+
matcherHint(`${matcherName}`),
|
|
45
|
+
printExpectedDetailedResult('failure', true, expectedMessage, expectedDetail),
|
|
46
|
+
printReceivedDetailedResult(received)
|
|
47
|
+
].join('\n');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default {
|
|
51
|
+
toFailWithDetail: function <T extends DetailedResult<unknown, unknown>>(
|
|
52
|
+
received: T,
|
|
53
|
+
expectedMessage: string | RegExp | undefined,
|
|
54
|
+
expectedDetail: ResultDetailType<T>
|
|
55
|
+
): jest.CustomMatcherResult {
|
|
56
|
+
const pass = predicate(received, expectedMessage, expectedDetail);
|
|
57
|
+
if (pass) {
|
|
58
|
+
return { pass: true, message: passMessage(received, expectedMessage, expectedDetail) };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { pass: false, message: failMessage(received, expectedMessage, expectedDetail) };
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { equals } from '@jest/expect-utils';
|
|
2
|
+
import { DetailedResult } from '../../ts-utils';
|
|
3
|
+
|
|
4
|
+
export const matcherName: string = 'toFailWith';
|
|
5
|
+
|
|
6
|
+
export function predicate<T, TD>(
|
|
7
|
+
received: DetailedResult<T, TD>,
|
|
8
|
+
expectedResult: string | RegExp | undefined,
|
|
9
|
+
expectedDetail: TD
|
|
10
|
+
): boolean {
|
|
11
|
+
if (received.isFailure()) {
|
|
12
|
+
if (expectedResult === undefined) {
|
|
13
|
+
if (received.message !== undefined) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
} else if (expectedResult instanceof RegExp) {
|
|
17
|
+
if (received.message.match(expectedResult) === null) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
} else if (received.message !== expectedResult) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return equals(received.detail, expectedDetail);
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a .not test fails with few calls 1`] = `
|
|
4
|
+
"expect(received).not.toHaveBeenCalledWithArgumentsMatching(expected)
|
|
5
|
+
Expected no call with arguments matching:
|
|
6
|
+
[Any<String>]
|
|
7
|
+
Received (1 total):
|
|
8
|
+
*000: [\\"arg1\\"]"
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a .not test fails with many calls "for a call in the middle" 1`] = `
|
|
12
|
+
"expect(received).not.toHaveBeenCalledWithArgumentsMatching(expected)
|
|
13
|
+
Expected no call with arguments matching:
|
|
14
|
+
[\\"arg3\\"]
|
|
15
|
+
Received (7 total):
|
|
16
|
+
002: [\\"arg2\\"]
|
|
17
|
+
*003: [\\"arg3\\"]
|
|
18
|
+
004: [\\"arg4\\"]"
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a .not test fails with many calls "for the first call" 1`] = `
|
|
22
|
+
"expect(received).not.toHaveBeenCalledWithArgumentsMatching(expected)
|
|
23
|
+
Expected no call with arguments matching:
|
|
24
|
+
[\\"arg0\\"]
|
|
25
|
+
Received (7 total):
|
|
26
|
+
*000: [\\"arg0\\"]
|
|
27
|
+
001: [\\"arg1\\"]
|
|
28
|
+
002: [\\"arg2\\"]"
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a .not test fails with many calls "for the last call" 1`] = `
|
|
32
|
+
"expect(received).not.toHaveBeenCalledWithArgumentsMatching(expected)
|
|
33
|
+
Expected no call with arguments matching:
|
|
34
|
+
[\\"arg6\\"]
|
|
35
|
+
Received (7 total):
|
|
36
|
+
004: [\\"arg4\\"]
|
|
37
|
+
005: [\\"arg5\\"]
|
|
38
|
+
*006: [\\"arg6\\"]"
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a .not test fails with many calls "for the second call" 1`] = `
|
|
42
|
+
"expect(received).not.toHaveBeenCalledWithArgumentsMatching(expected)
|
|
43
|
+
Expected no call with arguments matching:
|
|
44
|
+
[StringMatching /1/]
|
|
45
|
+
Received (7 total):
|
|
46
|
+
000: [\\"arg0\\"]
|
|
47
|
+
*001: [\\"arg1\\"]
|
|
48
|
+
002: [\\"arg2\\"]"
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a .not test fails with many calls "for the second-to-last-call" 1`] = `
|
|
52
|
+
"expect(received).not.toHaveBeenCalledWithArgumentsMatching(expected)
|
|
53
|
+
Expected no call with arguments matching:
|
|
54
|
+
[\\"arg5\\"]
|
|
55
|
+
Received (7 total):
|
|
56
|
+
004: [\\"arg4\\"]
|
|
57
|
+
*005: [\\"arg5\\"]
|
|
58
|
+
006: [\\"arg6\\"]"
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if a call is not matched 1`] = `
|
|
62
|
+
"expect(received).toHaveBeenCalledWithArgumentsMatching(expected)
|
|
63
|
+
Expected call with arguments matching:
|
|
64
|
+
[\\"call7\\"]
|
|
65
|
+
Received (6 total):
|
|
66
|
+
003: [\\"call4\\"]
|
|
67
|
+
004: [\\"call5\\"]
|
|
68
|
+
005: [\\"call6\\"]"
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching reports a helpful message if function was not called 1`] = `
|
|
72
|
+
"expect(received).toHaveBeenCalledWithArgumentsMatching(expected)
|
|
73
|
+
Expected call with arguments matching:
|
|
74
|
+
[\\"call7\\"]
|
|
75
|
+
Received (0 total):"
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching throws if argument is "an object" 1`] = `"Test error: toHaveBeenCalledWithArgumentsMatching called with other than jest.Mock"`;
|
|
79
|
+
|
|
80
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching throws if argument is "not a mock function" 1`] = `"Test error: toHaveBeenCalledWithArgumentsMatching called with other than jest.Mock"`;
|
|
81
|
+
|
|
82
|
+
exports[`.toHaveBeenCalledWithArgumentsMatching throws if argument is "null" 1`] = `"Test error: toHaveBeenCalledWithArgumentsMatching called with other than jest.Mock"`;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { getTypeOfProperty, getValueOfPropertyOrDefault } from '@fgv/ts-utils';
|
|
2
|
+
import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils';
|
|
3
|
+
import { IMatchedCall, matcherName, predicate } from './predicate';
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
7
|
+
namespace jest {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars, @typescript-eslint/naming-convention
|
|
9
|
+
interface Matchers<R> {
|
|
10
|
+
/**
|
|
11
|
+
* Use .toSucceedWith to verify that a Result<T> is a success
|
|
12
|
+
* and that the result value matches the supplied value
|
|
13
|
+
* @param expected -
|
|
14
|
+
*/
|
|
15
|
+
toHaveBeenCalledWithArgumentsMatching(expected: unknown): R;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getRange(length: number, cursor: number): { start: number; end: number } {
|
|
21
|
+
// less than 3 return everything
|
|
22
|
+
if (length < 3) {
|
|
23
|
+
return { start: 0, end: length };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (cursor === 0) {
|
|
27
|
+
return { start: 0, end: 3 };
|
|
28
|
+
} else if (cursor >= length - 1) {
|
|
29
|
+
return { start: length - 3, end: length };
|
|
30
|
+
}
|
|
31
|
+
return { start: cursor - 1, end: cursor + 2 };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formatOneCall(index: number, received: unknown, cursor: boolean): string {
|
|
35
|
+
const indexString = index.toLocaleString([], { maximumFractionDigits: 0, minimumIntegerDigits: 3 });
|
|
36
|
+
const cursorString = cursor ? '*' : ' ';
|
|
37
|
+
return `${cursorString}${indexString}: ${printReceived(received)}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function formatArgsMessage(received: jest.Mock, cursor?: number): string[] {
|
|
41
|
+
const calls = received.mock.calls;
|
|
42
|
+
|
|
43
|
+
if (calls.length > 0) {
|
|
44
|
+
// if there's no cursor, show the last 3
|
|
45
|
+
const { start, end } = getRange(calls.length, cursor !== undefined ? cursor : calls.length - 1);
|
|
46
|
+
const callsToShow = calls.slice(start, end);
|
|
47
|
+
return callsToShow.map((c, i) => formatOneCall(start + i, c, start + i === cursor));
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function passMessage(received: jest.Mock, expected: unknown, matched: IMatchedCall): () => string {
|
|
53
|
+
return () =>
|
|
54
|
+
[
|
|
55
|
+
matcherHint(`.not.${matcherName}`),
|
|
56
|
+
'Expected no call with arguments matching:',
|
|
57
|
+
` ${printExpected(expected)}`,
|
|
58
|
+
`Received (${received.mock.calls.length} total):`,
|
|
59
|
+
...formatArgsMessage(received, matched.index)
|
|
60
|
+
].join('\n');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function failMessage(received: jest.Mock, expected: unknown): () => string {
|
|
64
|
+
return () =>
|
|
65
|
+
[
|
|
66
|
+
matcherHint(`${matcherName}`),
|
|
67
|
+
'Expected call with arguments matching:',
|
|
68
|
+
` ${printExpected(expected)}`,
|
|
69
|
+
`Received (${received.mock.calls.length} total):`,
|
|
70
|
+
...formatArgsMessage(received)
|
|
71
|
+
].join('\n');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isMock(received: unknown): received is jest.Mock {
|
|
75
|
+
if (received !== null && !Array.isArray(received)) {
|
|
76
|
+
return (
|
|
77
|
+
getValueOfPropertyOrDefault('_isMockFunction', received as object) === true &&
|
|
78
|
+
getTypeOfProperty('mock', received as object) === 'object'
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export default {
|
|
85
|
+
toHaveBeenCalledWithArgumentsMatching: function (
|
|
86
|
+
received: jest.Mock,
|
|
87
|
+
expected: unknown
|
|
88
|
+
): jest.CustomMatcherResult {
|
|
89
|
+
if (!isMock(received)) {
|
|
90
|
+
throw new Error('Test error: toHaveBeenCalledWithArgumentsMatching called with other than jest.Mock');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const matched = predicate(received, expected);
|
|
94
|
+
if (matched !== undefined) {
|
|
95
|
+
return { pass: true, message: passMessage(received, expected, matched) };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { pass: false, message: failMessage(received, expected) };
|
|
99
|
+
}
|
|
100
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { equals } from '@jest/expect-utils';
|
|
2
|
+
|
|
3
|
+
export const matcherName: string = 'toHaveBeenCalledWithArgumentsMatching';
|
|
4
|
+
|
|
5
|
+
export interface IMatchedCall {
|
|
6
|
+
index: number;
|
|
7
|
+
arguments: unknown[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function predicate(received: jest.Mock, expected: unknown): undefined | IMatchedCall {
|
|
11
|
+
for (let i = 0; i < received.mock.calls.length; i++) {
|
|
12
|
+
const args = received.mock.calls[i];
|
|
13
|
+
if (equals(args, expected)) {
|
|
14
|
+
return { index: i, arguments: args };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`.toSucceed reports details for a failed .not test: toFailTestAndMatchSnapshot 1`] = `
|
|
4
|
+
"expect(received).not.toSucceed(expected)
|
|
5
|
+
Expected:
|
|
6
|
+
Not success
|
|
7
|
+
Received:
|
|
8
|
+
Success with \\"hello\\""
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
exports[`.toSucceed reports details for a failed test: toFailTestAndMatchSnapshot 1`] = `
|
|
12
|
+
"expect(received).toSucceed(expected)
|
|
13
|
+
Expected:
|
|
14
|
+
Success
|
|
15
|
+
Received:
|
|
16
|
+
Failure with \\"oops\\""
|
|
17
|
+
`;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { printExpectedResult, printReceivedResult } from '../../utils/matcherHelpers';
|
|
2
|
+
import { matcherName, predicate } from './predicate';
|
|
3
|
+
|
|
4
|
+
import { Result } from '@fgv/ts-utils';
|
|
5
|
+
import { matcherHint } from 'jest-matcher-utils';
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
9
|
+
namespace jest {
|
|
10
|
+
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention
|
|
11
|
+
interface Matchers<R, T> {
|
|
12
|
+
/**
|
|
13
|
+
* Use .toSucceed to verify that a Result<T> is a success
|
|
14
|
+
*/
|
|
15
|
+
toSucceed(): R;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function passMessage<T>(received: Result<T>): () => string {
|
|
21
|
+
return () =>
|
|
22
|
+
[
|
|
23
|
+
matcherHint(`.not.${matcherName}`),
|
|
24
|
+
printExpectedResult('success', false),
|
|
25
|
+
printReceivedResult(received)
|
|
26
|
+
].join('\n');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function failMessage<T>(received: Result<T>): () => string {
|
|
30
|
+
return () =>
|
|
31
|
+
[matcherHint(`${matcherName}`), printExpectedResult('success', true), printReceivedResult(received)].join(
|
|
32
|
+
'\n'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default {
|
|
37
|
+
toSucceed: function <T>(received: Result<T>): jest.CustomMatcherResult {
|
|
38
|
+
const pass = predicate(received);
|
|
39
|
+
if (pass) {
|
|
40
|
+
return { pass: true, message: passMessage(received) };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { pass: false, message: failMessage(received) };
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`.toSucceedAndMatchSnapshot logs details correctly for a failed result: toFailTestAndMatchSnapshot 1`] = `
|
|
4
|
+
"expect(callback).toSucceedAndMatchInlineSnapshot(expected)
|
|
5
|
+
Expected:
|
|
6
|
+
Callback to succeed with a result that matches the snapshot
|
|
7
|
+
Received:
|
|
8
|
+
Failure with \\"oopsy\\""
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
exports[`.toSucceedAndMatchSnapshot logs details correctly for a failed result: toFailTestAndMatchSnapshot 2`] = `
|
|
12
|
+
"expect(received).not.toMatchInlineSnapshot(properties, snapshot)
|
|
13
|
+
|
|
14
|
+
Matcher error: Snapshot matchers cannot be used with not"
|
|
15
|
+
`;
|