Skip to content

Commit

Permalink
Implement numPassingAsserts of testCaseResult (#13795)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymqy committed Jan 26, 2023
1 parent be021fa commit c78905c
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

### Features

- `[expect, jest-circus, @jest/types]` Implement `numPassingAsserts` of testResults to track the number of passing asserts in a test ([#13795](https://github.com/facebook/jest/pull/13795))
- `[jest-core]` Add newlines to JSON output ([#13817](https://github.com/facebook/jest/pull/13817))

### Fixes
Expand Down
11 changes: 11 additions & 0 deletions e2e/__tests__/__snapshots__/customReportersOnCircus.test.ts.snap
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Custom Reporters Integration on jest-circus valid failing assertion counts for adding reporters 1`] = `
"onTestCaseResult: adds fail, status: failed, numExpectations: 0
onTestFileResult testCaseResult 0: adds fail, status: failed, numExpectations: 0"
`;

exports[`Custom Reporters Integration on jest-circus valid passing assertion counts for adding reporters 1`] = `
"onTestCaseResult: adds ok, status: passed, numExpectations: 3
onTestFileResult testCaseResult 0: adds ok, status: passed, numExpectations: 3"
`;
42 changes: 42 additions & 0 deletions e2e/__tests__/customReportersOnCircus.test.ts
@@ -0,0 +1,42 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {skipSuiteOnJasmine} from '@jest/test-utils';
import runJest from '../runJest';

skipSuiteOnJasmine();

describe('Custom Reporters Integration on jest-circus', () => {
test('valid passing assertion counts for adding reporters', () => {
const {stdout} = runJest('custom-reporters', [
'--config',
JSON.stringify({
reporters: [
'default',
'<rootDir>/reporters/AssertionCountsReporter.js',
],
}),
'add.test.js',
]);

expect(stdout).toMatchSnapshot();
});

test('valid failing assertion counts for adding reporters', () => {
const {stdout} = runJest('custom-reporters', [
'--config',
JSON.stringify({
reporters: [
'default',
'<rootDir>/reporters/AssertionCountsReporter.js',
],
}),
'addFail.test.js',
]);

expect(stdout).toMatchSnapshot();
});
});
29 changes: 29 additions & 0 deletions e2e/custom-reporters/reporters/AssertionCountsReporter.js
@@ -0,0 +1,29 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

class AssertionCountsReporter {
onTestFileResult(test, testResult, aggregatedResult) {
testResult.testResults.forEach((testCaseResult, index) => {
console.log(
`onTestFileResult testCaseResult ${index}: ${testCaseResult.title}, ` +
`status: ${testCaseResult.status}, ` +
`numExpectations: ${testCaseResult.numPassingAsserts}`,
);
});
}
onTestCaseResult(test, testCaseResult) {
console.log(
`onTestCaseResult: ${testCaseResult.title}, ` +
`status: ${testCaseResult.status}, ` +
`numExpectations: ${testCaseResult.numPassingAsserts}`,
);
}
}

module.exports = AssertionCountsReporter;
1 change: 1 addition & 0 deletions packages/expect/__typetests__/expect.test.ts
Expand Up @@ -77,6 +77,7 @@ expectType<void>(
expectType<boolean>(this.isExpectingAssertions);
expectType<Error | undefined>(this.isExpectingAssertionsError);
expectType<boolean | undefined>(this.isNot);
expectType<number>(this.numPassingAsserts);
expectType<string | undefined>(this.promise);
expectType<Array<Error>>(this.suppressedErrors);
expectType<string | undefined>(this.testPath);
Expand Down
32 changes: 32 additions & 0 deletions packages/expect/src/__tests__/assertionCounts.test.ts
Expand Up @@ -44,3 +44,35 @@ describe('.hasAssertions()', () => {

it('hasAssertions not leaking to global state', () => {});
});

describe('numPassingAsserts', () => {
it('verify the default value of numPassingAsserts', () => {
const {numPassingAsserts} = jestExpect.getState();
expect(numPassingAsserts).toBe(0);
});

it('verify the resetting of numPassingAsserts after a test', () => {
expect('a').toBe('a');
expect('a').toBe('a');
// reset state
jestExpect.extractExpectedAssertionsErrors();
const {numPassingAsserts} = jestExpect.getState();
expect(numPassingAsserts).toBe(0);
});

it('verify the correctness of numPassingAsserts count for passing test', () => {
expect('a').toBe('a');
expect('a').toBe('a');
const {numPassingAsserts} = jestExpect.getState();
expect(numPassingAsserts).toBe(2);
});

it('verify the correctness of numPassingAsserts count for failing test', () => {
expect('a').toBe('a');
try {
expect('a').toBe('b');
} catch (error) {}
const {numPassingAsserts} = jestExpect.getState();
expect(numPassingAsserts).toBe(1);
});
});
1 change: 1 addition & 0 deletions packages/expect/src/extractExpectedAssertionsErrors.ts
Expand Up @@ -20,6 +20,7 @@ const resetAssertionsLocalState = () => {
assertionCalls: 0,
expectedAssertionsNumber: null,
isExpectingAssertions: false,
numPassingAsserts: 0,
});
};

Expand Down
2 changes: 2 additions & 0 deletions packages/expect/src/index.ts
Expand Up @@ -337,6 +337,8 @@ const makeThrowingMatcher = (
} else {
getState().suppressedErrors.push(error);
}
} else {
getState().numPassingAsserts++;
}
};

Expand Down
1 change: 1 addition & 0 deletions packages/expect/src/jestMatchersObject.ts
Expand Up @@ -29,6 +29,7 @@ if (!Object.prototype.hasOwnProperty.call(globalThis, JEST_MATCHERS_OBJECT)) {
assertionCalls: 0,
expectedAssertionsNumber: null,
isExpectingAssertions: false,
numPassingAsserts: 0,
suppressedErrors: [], // errors that are not thrown immediately.
};
Object.defineProperty(globalThis, JEST_MATCHERS_OBJECT, {
Expand Down
1 change: 1 addition & 0 deletions packages/expect/src/types.ts
Expand Up @@ -65,6 +65,7 @@ export interface MatcherState {
isExpectingAssertions: boolean;
isExpectingAssertionsError?: Error;
isNot?: boolean;
numPassingAsserts: number;
promise?: string;
suppressedErrors: Array<Error>;
testPath?: string;
Expand Down
Expand Up @@ -178,7 +178,7 @@ export const runAndTransformResultsToJestFormat = async ({
: ancestorTitles.join(' '),
invocations: testResult.invocations,
location: testResult.location,
numPassingAsserts: 0,
numPassingAsserts: testResult.numPassingAsserts,
retryReasons: testResult.retryReasons,
status,
title: testResult.testPath[testResult.testPath.length - 1],
Expand Down Expand Up @@ -238,6 +238,7 @@ const eventHandler = async (event: Circus.Event) => {
break;
}
case 'test_done': {
event.test.numPassingAsserts = jestExpect.getState().numPassingAsserts;
_addSuppressedErrors(event.test);
_addExpectedAssertionErrors(event.test);
break;
Expand Down
4 changes: 3 additions & 1 deletion packages/jest-circus/src/utils.ts
Expand Up @@ -78,6 +78,7 @@ export const makeTest = (
invocations: 0,
mode,
name: convertDescriptorToString(name),
numPassingAsserts: 0,
parent,
retryReasons: [],
seenDone: false,
Expand Down Expand Up @@ -363,6 +364,7 @@ export const makeSingleTestResult = (
errorsDetailed,
invocations: test.invocations,
location,
numPassingAsserts: test.numPassingAsserts,
retryReasons: test.retryReasons.map(_getError).map(getErrorStack),
status,
testPath: Array.from(testPath),
Expand Down Expand Up @@ -484,7 +486,7 @@ export const parseSingleTestResult = (
: ancestorTitles.join(' '),
invocations: testResult.invocations,
location: testResult.location,
numPassingAsserts: 0,
numPassingAsserts: testResult.numPassingAsserts,
retryReasons: Array.from(testResult.retryReasons),
status,
title: testResult.testPath[testResult.testPath.length - 1],
Expand Down
1 change: 1 addition & 0 deletions packages/jest-types/__typetests__/expect.test.ts
Expand Up @@ -446,6 +446,7 @@ expectType<void>(
expectType<boolean>(this.isExpectingAssertions);
expectType<Error | undefined>(this.isExpectingAssertionsError);
expectType<boolean | undefined>(this.isNot);
expectType<number>(this.numPassingAsserts);
expectType<string | undefined>(this.promise);
expectType<Array<Error>>(this.suppressedErrors);
expectType<string | undefined>(this.testPath);
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-types/src/Circus.ts
Expand Up @@ -185,6 +185,7 @@ export type TestResult = {
invocations: number;
status: TestStatus;
location?: {column: number; line: number} | null;
numPassingAsserts: number;
retryReasons: Array<FormattedError>;
testPath: Array<TestName | BlockName>;
};
Expand Down Expand Up @@ -245,6 +246,7 @@ export type TestEntry = {
mode: TestMode;
concurrent: boolean;
name: TestName;
numPassingAsserts: number;
parent: DescribeBlock;
startedAt?: number | null;
duration?: number | null;
Expand Down

0 comments on commit c78905c

Please sign in to comment.