Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions packages/allure-bun/test/spec/runtime/sync/steps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,81 @@ describe("sync steps", () => {
expect(readAttachment(attachments, attachmentRef.source)).toBe("bar");
});

bunIt("handles sync runtime stages", async () => {
const { tests, exitCode } = await runBunInlineTest({
"sample.test.ts": `
import { test } from "bun:test";
import { logStep, stage, step } from "allure-js-commons/sync";

test("sync stages", () => {
stage("stage 1");
logStep("a");
step("b", () => {
logStep("b 1");
stage("b 2");
logStep("b 2 nested");
});

stage("stage 2");
logStep("c");
});
`,
});

expect(exitCode).toBe(0);
expect(tests).toHaveLength(1);
expect(tests[0].steps).toMatchObject([
{
name: "stage 1",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "a",
status: Status.PASSED,
stage: Stage.FINISHED,
},
{
name: "b",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "b 1",
status: Status.PASSED,
stage: Stage.FINISHED,
},
{
name: "b 2",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "b 2 nested",
status: Status.PASSED,
stage: Stage.FINISHED,
},
],
},
],
},
],
},
{
name: "stage 2",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "c",
status: Status.PASSED,
stage: Stage.FINISHED,
},
],
},
]);
});

bunIt("rejects promise-returning sync steps", async () => {
const { tests, exitCode } = await runBunInlineTest({
"sample.test.ts": `
Expand Down
74 changes: 74 additions & 0 deletions packages/allure-codeceptjs/test/spec/runtime/modern/steps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,77 @@ it("handles lambda steps", async () => {
]),
);
});

it("handles runtime stages", async () => {
const { tests } = await runCodeceptJsInlineTest({
"sample.test.js": `
const { logStep, stage, step } = require("allure-js-commons");

Feature("sample-feature-1");
Scenario("scenario1", async () => {
await stage("stage 1");
await logStep("a");
await step("b", async () => {
await logStep("b 1");
await stage("b 2");
await logStep("b 2 nested");
});

await stage("stage 2");
await logStep("c");
});
`,
});

expect(tests).toHaveLength(1);
expect(tests[0].steps).toMatchObject([
{
name: "stage 1",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "a",
status: Status.PASSED,
stage: Stage.FINISHED,
},
{
name: "b",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "b 1",
status: Status.PASSED,
stage: Stage.FINISHED,
},
{
name: "b 2",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "b 2 nested",
status: Status.PASSED,
stage: Stage.FINISHED,
},
],
},
],
},
],
},
{
name: "stage 2",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "c",
status: Status.PASSED,
stage: Stage.FINISHED,
},
],
},
]);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Feature: with runtime stages

Scenario: succeed
Given allows to define runtime stages
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { Given } = require("@cucumber/cucumber");
const { logStep, stage, step } = require("allure-js-commons");

Given("allows to define runtime stages", async () => {
await stage("stage 1");
await logStep("a");
await step("b", async () => {
await logStep("b 1");
await stage("b 2");
await logStep("b 2 nested");
});

await stage("stage 2");
await logStep("c");
});
66 changes: 66 additions & 0 deletions packages/allure-cucumberjs/test/spec/runtime/modern/steps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,69 @@ it("handles runtime steps", async () => {
}),
);
});

it("handles runtime stages", async () => {
const { tests } = await runCucumberInlineTest(["stages"], ["runtime/modern/stages"]);

expect(tests).toHaveLength(1);
expect(tests[0]).toMatchObject({
name: "succeed",
status: Status.PASSED,
stage: Stage.FINISHED,
});
expect(tests[0].steps).toHaveLength(1);
expect(tests[0].steps[0]).toMatchObject({
name: "Given allows to define runtime stages",
stage: Stage.FINISHED,
});
expect(tests[0].steps[0].steps).toMatchObject([
{
name: "stage 1",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "a",
status: Status.PASSED,
stage: Stage.FINISHED,
},
{
name: "b",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "b 1",
status: Status.PASSED,
stage: Stage.FINISHED,
},
{
name: "b 2",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "b 2 nested",
status: Status.PASSED,
stage: Stage.FINISHED,
},
],
},
],
},
],
},
{
name: "stage 2",
status: Status.PASSED,
stage: Stage.FINISHED,
steps: [
{
name: "c",
status: Status.PASSED,
stage: Stage.FINISHED,
},
],
},
]);
});
17 changes: 16 additions & 1 deletion packages/allure-cypress/src/browser/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getGlobalTestRuntime, setGlobalTestRuntime } from "allure-js-commons/sd

import type { AllureCypressTaskArgs, CypressMessage } from "../types.js";
import { enqueueRuntimeMessage, getRuntimeMessages, setRuntimeMessages } from "./state.js";
import { ALLURE_STEP_CMD_SUBJECT, startAllureApiStep, stopCurrentAllureApiStep } from "./steps.js";
import { ALLURE_STEP_CMD_SUBJECT, startAllureApiStep, startAllureStage, stopCurrentAllureApiStep } from "./steps.js";
import { uint8ArrayToBase64 } from "./utils.js";

const SYNC_STEP_PURE_FUNCTION_ERROR =
Expand Down Expand Up @@ -192,6 +192,18 @@ class AllureCypressTestRuntime implements TestRuntime {
});
}

stage(name: string): PromiseLike<void> {
if (this.#isInOriginContext()) {
startAllureStage(name);
return Cypress.Promise.resolve();
}

return cy.wrap(ALLURE_STEP_CMD_SUBJECT, { log: false }).then(() => {
startAllureStage(name);
return Cypress.Promise.resolve();
});
}

step<T = void>(name: string, body: () => T | PromiseLike<T>) {
return cy
.wrap(ALLURE_STEP_CMD_SUBJECT, { log: false })
Expand Down Expand Up @@ -450,6 +462,9 @@ class AllureCypressTestRuntime implements TestRuntime {
startAllureApiStep(name);
stopCurrentAllureApiStep(status, error ? getMessageAndTraceFromError(error) : undefined);
},
stage: (name) => {
startAllureStage(name);
},
step: (name, body) => {
startAllureApiStep(name);

Expand Down
31 changes: 31 additions & 0 deletions packages/allure-cypress/src/browser/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
ApiStepDescriptor,
CypressStepFinalizeMessage,
LogStepDescriptor,
StageDescriptor,
StepDescriptor,
StepFinalizer,
} from "../types.js";
Expand All @@ -14,9 +15,11 @@ import { reportStepStart, reportStepStop } from "./lifecycle.js";
import {
clearStepsToFinalize,
enqueueRuntimeMessage,
getCurrentStep,
getStepStack,
getStepsToFinalize,
popAllSteps,
popStep,
pushStep,
setupStepFinalization,
} from "./state.js";
Expand All @@ -28,18 +31,33 @@ export const isApiStep = (descriptor: StepDescriptor): descriptor is ApiStepDesc
return descriptor.type === "api";
};

export const isStageStep = (descriptor: StepDescriptor): descriptor is StageDescriptor => {
return descriptor.type === "stage";
};

export const isLogStep = (descriptor: StepDescriptor): descriptor is LogStepDescriptor => {
return descriptor.type === "log";
};

export const startAllureApiStep = (name: string) => reportStepStart(pushAllureStep(), name);

export const startAllureStage = (name: string) => {
stopCurrentAllureStages();
reportStepStart(pushAllureStage(), name);
};

export const pushAllureStep = () => {
const id = generateApiStepId();
pushStep({ id, type: "api" });
return id;
};

export const pushAllureStage = () => {
const id = generateApiStepId();
pushStep({ id, type: "stage" });
return id;
};

export const reportStepError = (error: Error) => {
const status = getStatusFromError(error);
const statusDetails = getMessageAndTraceFromError(error);
Expand All @@ -66,6 +84,12 @@ export const reportStepError = (error: Error) => {
export const stopCurrentAllureApiStep = (status?: Status, statusDetails?: StatusDetails) =>
findAndStopStepWithSubsteps((stepDescriptor) => isApiStep(stepDescriptor), status, statusDetails);

export const stopCurrentAllureStages = (status?: Status, statusDetails?: StatusDetails) => {
while (getCurrentStep() && isStageStep(getCurrentStep()!)) {
stopCurrentStep(status, statusDetails);
}
};

export const findAndStopStepWithSubsteps = (
pred: (stepEntry: StepDescriptor) => boolean,
status?: Status,
Expand All @@ -75,6 +99,13 @@ export const findAndStopStepWithSubsteps = (
export const stopAllSteps = (status?: Status, statusDetails?: StatusDetails) =>
stopSelectedSteps(popAllSteps(), status, statusDetails);

export const stopCurrentStep = (status?: Status, statusDetails?: StatusDetails) => {
const step = getCurrentStep();
if (step) {
stopSelectedSteps([popStep()!], status, statusDetails);
}
};

export const finalizeSteps = () => {
// This will stop all dangling steps (like log groups with missing endGroup calls or logs that haven't been
// finished by Cypress due to an error).
Expand Down
6 changes: 5 additions & 1 deletion packages/allure-cypress/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ export type ApiStepDescriptor = StepDescriptorBase & {
type: "api";
};

export type StepDescriptor = LogStepDescriptor | ApiStepDescriptor;
export type StageDescriptor = StepDescriptorBase & {
type: "stage";
};

export type StepDescriptor = LogStepDescriptor | ApiStepDescriptor | StageDescriptor;

export type StepFinalizer = (message: CypressStepFinalizeMessage["data"]) => void;

Expand Down
Loading
Loading