Skip to content

Commit

Permalink
feat: report specs early via spec:before
Browse files Browse the repository at this point in the history
use execution state
  • Loading branch information
agoldis committed Jun 1, 2023
1 parent 904b3e4 commit 4a3da39
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 176 deletions.
35 changes: 18 additions & 17 deletions packages/cypress-cloud/lib/cypress/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import Debug from "debug";
import _ from "lodash";
import { getCypressRunAPIParams } from "../config";
import { safe } from "../lang";
import { getWSSPort } from "../ws";

const debug = Debug("currents:cypress");
Expand Down Expand Up @@ -58,20 +59,20 @@ export async function runSpecFile(
return result;
}

export const runSpecFileSafe = async (
{ spec }: RunCypressSpecFile,
cypressRunOptions: ValidatedCurrentsParameters
): Promise<CypressResult> => {
try {
return await runSpecFile({ spec }, cypressRunOptions);
} catch (error) {
debug("cypress run exception %o", error);
return {
status: "failed",
failures: 1,
message: `Cypress process crashed with an error:\n${
(error as Error).message
}\n${(error as Error).stack}}`,
};
}
};
export const runSpecFileSafe = (
...args: Parameters<typeof runSpecFile>
): Promise<CypressResult> =>
safe(
runSpecFile,
(error) => {
debug("cypress run exception %o", error);
return {
status: "failed" as const,
failures: 1,
message: `Cypress process crashed with an error:\n${
(error as Error).message
}\n${(error as Error).stack}}`,
};
},
() => {}
)(...args);
6 changes: 3 additions & 3 deletions packages/cypress-cloud/lib/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ bluebird.Promise.config({
export const BPromise = bluebird.Promise;

export const safe =
<T extends any[], R extends any>(
<T extends any[], R extends any, F extends any>(
fn: (...args: T) => Promise<R>,
ifFaled: (e: unknown) => any,
ifFaled: (e: unknown) => F,
ifSucceed: () => any
) =>
async (...args: T) => {
Expand All @@ -17,6 +17,6 @@ export const safe =
ifSucceed();
return r;
} catch (e) {
ifFaled(e);
return ifFaled(e);
}
};
1 change: 1 addition & 0 deletions packages/cypress-cloud/lib/platform/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Debug from "debug";
import getos from "getos";
import { cpus, freemem, platform, release, totalmem } from "os";
import { promisify } from "util";

const debug = Debug("currents:platform");

const getOsVersion = async () => {
Expand Down
35 changes: 12 additions & 23 deletions packages/cypress-cloud/lib/results/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
TestState,
UpdateInstanceResultsPayload,
} from "../api";
import { MergedConfig } from "../config/config";
import { MergedConfig } from "../config";

const debug = Debug("currents:results");

Expand Down Expand Up @@ -249,9 +249,9 @@ export function getFailedDummyResult({
video: null,
spec: {
name: s,
relative: "",
absolute: "",
relativeToCommonRoot: "",
relative: s,
absolute: s,
relativeToCommonRoot: s,
},
tests: [
{
Expand Down Expand Up @@ -281,33 +281,22 @@ export function getFailedDummyResult({
};
}

export function normalizeRawResult(
rawResult: CypressResult,
specs: string[],
config: MergedConfig
): CypressCommandLine.CypressRunResult {
if (!isSuccessResult(rawResult)) {
return getFailedDummyResult({
specs,
error: rawResult.message,
config,
});
export function getCypressRunResultForSpec(
spec: string,
cypressResult: CypressResult
): CypressCommandLine.CypressRunResult | undefined {
if (!isSuccessResult(cypressResult)) {
return;
}
return rawResult;
}

export function getSummaryForSpec(
spec: string,
runResult: CypressCommandLine.CypressRunResult
) {
const run = runResult.runs.find((r) => r.spec.relative === spec);
const run = cypressResult.runs.find((r) => r.spec.relative === spec);
if (!run) {
return;
}
const stats = getStats(run.stats);
// adjust the result for singe spec
return {
...runResult,
...cypressResult,
runs: [run],
totalSuites: 1,
totalDuration: stats.wallClockDuration,
Expand Down
30 changes: 1 addition & 29 deletions packages/cypress-cloud/lib/results/uploadResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,10 @@ import { uploadArtifacts, uploadStdoutSafe } from "../artifacts";
import { setCancellationReason } from "../cancellation";
import { getInitialOutput } from "../capture";
import { isCurrents } from "../env";
import { warn } from "../log";
import { getInstanceResultPayload, getInstanceTestsPayload } from "./results";
const debug = Debug("currents:results");

export async function getUploadResultsTask({
instanceId,
spec,
runResult,
output,
}: {
instanceId: string;
spec: string;
runResult: CypressCommandLine.CypressRunResult;
output: string;
}) {
const run = runResult.runs.find((r) => r.spec.relative === spec);
if (!run) {
warn('Cannot determine run result for spec "%s"', spec);
return;
}
return processCypressResults(
instanceId,
{
// replace the runs with the run for the specified spec
...runResult,
runs: [run],
},
output
);
}

export async function processCypressResults(
export async function getReportResultsTask(
instanceId: string,
results: CypressCommandLine.CypressRunResult,
stdout: string
Expand Down
23 changes: 9 additions & 14 deletions packages/cypress-cloud/lib/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ import { getPlatform } from "./platform";
import { pubsub } from "./pubsub";
import { summarizeTestResults, summaryTable } from "./results";
import {
executionState,
getExecutionStateResults,
reportTasks,
runTillDoneOrCancelled,
setSpecAfter,
setSpecBefore,
summary,
uploadTasks,
} from "./runner";
import { getSpecFiles } from "./specMatcher";
import { startWSS } from "./ws";
Expand Down Expand Up @@ -118,8 +117,8 @@ export async function run(params: CurrentsRunParameters = {}) {

divider();

await Promise.allSettled(uploadTasks);
const _summary = summarizeTestResults(Object.values(summary), config);
await Promise.allSettled(reportTasks);
const _summary = summarizeTestResults(getExecutionStateResults(), config);

title("white", "Cloud Run Finished");
console.log(summaryTable(_summary));
Expand All @@ -136,17 +135,13 @@ export async function run(params: CurrentsRunParameters = {}) {
}

function listenToSpecEvents() {
pubsub.on("before:spec", async ({ spec }: { spec: Cypress.Spec }) => {
console.log("before:spec", spec.relative);
setSpecBefore(spec.relative);
console.log(executionState);
});
pubsub.on("before:spec", async ({ spec }: { spec: Cypress.Spec }) =>
setSpecBefore(spec.relative)
);

pubsub.on(
"after:spec",
async ({ spec, results }: { spec: Cypress.Spec; results: any }) => {
console.log("after:spec", spec.relative);
setSpecAfter(spec.relative, results);
}
async ({ spec, results }: { spec: Cypress.Spec; results: any }) =>
setSpecAfter(spec.relative, results)
);
}
5 changes: 2 additions & 3 deletions packages/cypress-cloud/lib/runner/cancellable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { BPromise } from "../lang";
import { warn } from "../log";
import { Event, pubsub } from "../pubsub";
import { runTillDone } from "./runner";
import { summary } from "./state";

let cancellable: {
cancel: () => void;
Expand All @@ -24,11 +23,11 @@ export async function runTillDoneOrCancelled(
_reject(new Error("BlueBird is misconfigured: onCancel is undefined"));
return;
}
onCancel(() => _resolve(summary));
onCancel(() => _resolve(void 0));
runTillDone(...args).then(
() => {
resolve();
_resolve(summary);
_resolve(void 0);
},
(error) => {
reject();
Expand Down
85 changes: 85 additions & 0 deletions packages/cypress-cloud/lib/runner/mapResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
CypressScreenshot,
CypressTest,
CypressTestAttempt,
} from "cypress-cloud/types";

import * as SpecAfter from "./spec.type";

function getScreenshot(s: SpecAfter.Screenshot): CypressScreenshot {
return {
...s,
name: s.name ?? "screenshot",
};
}

function getTestAttempt(
attempt: SpecAfter.TestAttempt,
screenshots: SpecAfter.Screenshot[]
): CypressTestAttempt {
return {
...attempt,
startedAt: attempt.wallClockStartedAt,
duration: attempt.wallClockDuration,
screenshots: screenshots.map(getScreenshot),
};
}

function getTest(
t: SpecAfter.Test,
screenshots: SpecAfter.Screenshot[]
): CypressTest {
const _screenshots = screenshots.filter((s) => s.testId === t.testId);
return {
...t,
attempts: t.attempts.map((a, i) =>
getTestAttempt(
a,
_screenshots.filter((s) => s.testAttemptIndex === i)
)
),
};
}

export function specResultsToCypressResults(
specAfterResult: SpecAfter.SpecResult
): CypressCommandLine.CypressRunResult {
const tests: CypressTest[] = specAfterResult.tests.map((t) =>
getTest(t, specAfterResult.screenshots)
);

return {
status: "finished",
totalDuration: specAfterResult.stats.wallClockDuration,
totalSuites: specAfterResult.stats.suites,
totalTests: specAfterResult.stats.tests,
totalFailed: specAfterResult.stats.failures,
totalPassed: specAfterResult.stats.passes,
totalPending: specAfterResult.stats.pending,
totalSkipped: specAfterResult.stats.skipped,
startedTestsAt: specAfterResult.stats.wallClockStartedAt,
endedTestsAt: specAfterResult.stats.wallClockEndedAt,
runs: [
{
stats: {
...specAfterResult.stats,
startedAt: specAfterResult.stats.wallClockStartedAt,
endedAt: specAfterResult.stats.wallClockEndedAt,
duration: specAfterResult.stats.wallClockDuration,
},
reporter: specAfterResult.reporter,
reporterStats: specAfterResult.reporterStats,
spec: specAfterResult.spec,
error: specAfterResult.error,
video: specAfterResult.video,
// TODO: really?
shouldUploadVideo: true,
// @ts-ignore
// wrong typedef for CypressCommandLine.CypressRunResult
// actual HookName is "before all" | "before each" | "after all" | "after each"
hooks: specAfterResult.hooks,
tests,
},
],
};
}
Loading

0 comments on commit 4a3da39

Please sign in to comment.