Skip to content

Commit

Permalink
[CSR-1339] fix: reporter issues (#2)
Browse files Browse the repository at this point in the history
* fix: test expectedStatus and isFlaky determination

* fix: make wallClockStartedAt and wallClockEndedAt required

* fix: examples package

* fix: status

* fix: isTestFlaky
  • Loading branch information
vCaisim authored Jul 16, 2024
1 parent 9c00a59 commit ca33f5a
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 141 deletions.
2 changes: 1 addition & 1 deletion examples/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const config = {
testTimeout: 10000,
reporters: [
// "default",
["@currents/jest-reporter", {}],
["@currents/jest", {}],
],
projects: [
{
Expand Down
2 changes: 1 addition & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"devDependencies": {
"@babel/preset-env": "^7.24.3",
"@babel/preset-typescript": "^7.24.1",
"@currents/jest-reporter": "*",
"@currents/jest": "*",
"@currents/cmd": "*",
"@types/jest": "^29.5.12",
"jest": "^29.7.0"
Expand Down
27 changes: 2 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 17 additions & 20 deletions packages/cmd/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
export enum TestState {
Failed = "failed",
Passed = "passed",
Pending = "pending",
Skipped = "skipped",
}

export enum TestExpectedStatus {
Passed = "passed",
Failed = "failed",
TimedOut = "timedOut",
Skipped = "skipped",
Interrupted = "interrupted",
}
// possible currents test case statuses from reported results
export type TestCaseStatus = "passed" | "failed" | "pending";

// currents values suitable for jest status
export type TestRunnerStatus = "passed" | "failed" | "skipped";

// currents values suitable for jest expected status
export type ExpectedStatus = "passed" | "skipped";

// jest test case statuses available in results
export type JestTestCaseStatus = "pending" | "todo" | "failed" | "passed";

export type InstanceReportStats = {
suites: number;
Expand All @@ -21,8 +18,8 @@ export type InstanceReportStats = {
skipped: number;
failures: number;
flaky: number;
wallClockStartedAt: string | null;
wallClockEndedAt: string | null;
wallClockStartedAt: string;
wallClockEndedAt: string;
wallClockDuration: number;
};

Expand All @@ -46,7 +43,7 @@ export type WorkerInfo = {
};

export type InstanceReportTestAttempt = {
_s: TestState;
_s: TestCaseStatus;
attempt: number;
workerIndex: number;
parallelIndex: number;
Expand All @@ -55,7 +52,7 @@ export type InstanceReportTestAttempt = {
steps: unknown[];

duration: number;
status: TestExpectedStatus;
status: TestRunnerStatus;

stderr?: string[];
stdout?: string[];
Expand All @@ -68,10 +65,10 @@ export type InstanceReportTest = {
_t: number;
testId: string;
title: string[];
state: TestState;
state: TestCaseStatus;
isFlaky?: boolean;
retries: number;
expectedStatus?: TestExpectedStatus;
expectedStatus?: ExpectedStatus;
annotations?: unknown[];
timeout: number;
location: LocationSchema;
Expand Down
91 changes: 55 additions & 36 deletions packages/jest/src/lib/test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Test, TestCaseResult } from "@jest/reporters";
import type { Circus } from "@jest/types";
import { flowRight } from "lodash";
import crypto from "node:crypto";
import { P, match } from "ts-pattern";
import { TestExpectedStatus, TestState } from "../types";
import {
ExpectedStatus,
JestTestCaseStatus,
TestCaseStatus,
TestRunnerStatus,
} from "../types";
import { getRelativeFileLocation } from "./relativeFileLocation";

export type TestCaseInvocationStart = {
Expand Down Expand Up @@ -71,54 +74,70 @@ export function getWorker() {
};
}

export function statusToCurrentsStatus(
testStatus: TestCaseResult["status"]
): TestState {
export function getTestCaseStatus(
testStatus: JestTestCaseStatus
): TestCaseStatus {
switch (testStatus) {
case "passed":
return TestState.Passed;
return "passed";
case "failed":
return TestState.Failed;
case "skipped":
return "failed";
case "pending":
case "todo":
return "pending";

default:
throw new Error("Invalid Jest test case status");
}
}

export function getTestRunnerStatus(
status: JestTestCaseStatus
): TestRunnerStatus {
switch (status) {
case "passed":
return "passed";
case "failed":
return "failed";
case "pending":
case "disabled":
return TestState.Pending;
case "todo":
return "skipped";

// case "focused":
default:
throw new Error("Invalid Jest test case status");
}
}

export function getExpectedStatus(status: JestTestCaseStatus): ExpectedStatus {
switch (status) {
case "pending":
case "todo":
return "skipped";

default:
return TestState.Failed;
return "passed";
}
}

export function getRawTestStatus(
testCaseResults: TestCaseResult[]
): TestExpectedStatus {
const allStatuses = testCaseResults.map((i) => i.status);

// if all the attempts have similar status
if (allStatuses.every((status) => status === allStatuses[0])) {
return match(allStatuses[0])
.with(
P.union("disabled", "skipped", "todo", "pending"),
() => TestExpectedStatus.Skipped
)
.with("passed", () => TestExpectedStatus.Passed)
.with("failed", () => TestExpectedStatus.Failed)
.otherwise(() => TestExpectedStatus.Failed);
export function jestStatusFromInvocations(testResults: TestCaseResult[]) {
const statuses = testResults.map((r) => r.status as JestTestCaseStatus);
if (statuses.every((status) => status === statuses[0])) {
return statuses[0];
}

// otherwise, it is a mix of passed and failed attempts, so it is flaky
// and it doesn't pass the expected status
return TestExpectedStatus.Failed;
return "failed";
}

export const getTestCaseStatus = flowRight(
statusToCurrentsStatus,
getRawTestStatus
);

export function getAttemptNumber(result: TestCaseResult) {
return result?.invocations ?? 1;
}

// Test that has "passed" and "failed" invocations is `'flaky'`
export function isTestFlaky(testResults: TestCaseResult[]): boolean {
const statuses = testResults.map((r) => r.status);
return (
testResults.length > 1 &&
statuses.includes("failed") &&
statuses.includes("passed")
);
}
Loading

0 comments on commit ca33f5a

Please sign in to comment.