Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Back compatibility with old style cucumberjs runtime API #952

Merged
merged 2 commits into from
May 21, 2024
Merged
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
39 changes: 36 additions & 3 deletions packages/allure-cucumberjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ Install the required packages using your favorite package manager:

```shell
# using npm
npm install --save-dev allure-js-commons allure-cucumberjs
npm install --save-dev allure-cucumberjs
# using yarn
yarn add -D allure-js-commons allure-cucumberjs
yarn add -D allure-cucumberjs
# using pnpm
pnpm add -D allure-js-commons allure-cucumberjs
pnpm add -D allure-cucumberjs
```

Create `reporter.js` with following content:
Expand Down Expand Up @@ -86,6 +86,39 @@ Given(/my step/, async () => {
});
```

### Using Allure Cucumber World

If you prefer to use custom Allure World instead of global Allure API, you can use `AllureCucumberWorld` class:

```js
import { AllureCucumberWorld } from "allure-cucumberjs";
import { setWorldConstructor } from "@cucumber/cucumber";

setWorldConstructor(AllureCucumberWorld);
```

Then you'll be able to use Allure Runtime API through `this` in your step definition files:

```js
import { Given } from "@cucumber/cucumber";

Given(/my step/, async function() {
const self = this;

await self.step("step can have anonymous body function", async function() {
await self.label("label_name", "label_value");
await self.attachment(JSON.stringify({ foo: "bar " }), "application/json");
});

await self.step("by the way, body function can be arrow one", async function() {
await self.label("label_name", "label_value");
await self.attachment(JSON.stringify({ foo: "bar " }), "application/json");
});
});
```

If you run your Cucumber features using single thread mode, `AllureCucumberWorld` is set automatically.

### Parameters usage

```ts
Expand Down
185 changes: 5 additions & 180 deletions packages/allure-cucumberjs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,186 +1,9 @@
import { Before, World } from "@cucumber/cucumber";
import { ALLURE_RUNTIME_MESSAGE_CONTENT_TYPE } from "allure-js-commons/internal";
import {
ContentType,
Label,
LabelName,
Link,
LinkType,
MessagesHolder,
ParameterOptions,
RuntimeMessage,
Stage,
Status,
TestRuntime,
getStatusFromError,
setGlobalTestRuntime,
} from "allure-js-commons/sdk/node";

export class AllureCucumberTestRuntime extends World implements TestRuntime {
messagesHolder = new MessagesHolder();

async label(name: LabelName | string, value: string) {
await this.sendMessage({
type: "metadata",
data: {
labels: [{ name, value }],
},
});
}

async labels(...labels: Label[]) {
await this.sendMessage({
type: "metadata",
data: {
labels,
},
});
}

async link(url: string, type?: LinkType | string, name?: string) {
await this.sendMessage({
type: "metadata",
data: {
links: [{ type, url, name }],
},
});
}

async links(...links: Link[]) {
await this.sendMessage({
type: "metadata",
data: {
links,
},
});
}

async parameter(name: string, value: string, options?: ParameterOptions) {
await this.sendMessage({
type: "metadata",
data: {
parameters: [
{
name,
value,
...options,
},
],
},
});
}

async description(markdown: string) {
await this.sendMessage({
type: "metadata",
data: {
description: markdown,
},
});
}

async descriptionHtml(html: string) {
await this.sendMessage({
type: "metadata",
data: {
descriptionHtml: html,
},
});
}

async displayName(name: string) {
await this.sendMessage({
type: "metadata",
data: {
displayName: name,
},
});
}

async historyId(value: string) {
await this.sendMessage({
type: "metadata",
data: {
historyId: value,
},
});
}

async testCaseId(value: string) {
await this.sendMessage({
type: "metadata",
data: {
testCaseId: value,
},
});
}

async attachment(name: string, content: Buffer | string, type: string | ContentType) {
await this.sendMessage({
type: "raw_attachment",
data: {
name,
content: Buffer.from(content).toString("base64"),
contentType: type,
encoding: "base64",
},
});
}

async step(name: string, body: () => void | PromiseLike<void>) {
await this.sendMessage({
type: "step_start",
data: {
name,
start: Date.now(),
},
});

try {
await body();

await this.sendMessage({
type: "step_stop",
data: {
status: Status.PASSED,
stage: Stage.FINISHED,
stop: Date.now(),
},
});
} catch (err) {
const status = getStatusFromError(err as Error);

await this.sendMessage({
type: "step_stop",
data: {
status,
stage: Stage.FINISHED,
stop: Date.now(),
statusDetails: {
message: (err as Error).message,
trace: (err as Error).stack,
},
},
});

throw err;
}
}

async stepDisplayName() {}

async stepParameter() {}

sendMessage(message: RuntimeMessage) {
this.attach(JSON.stringify(message), ALLURE_RUNTIME_MESSAGE_CONTENT_TYPE as string);

return Promise.resolve();
}
}
import { Before } from "@cucumber/cucumber";
import { setGlobalTestRuntime } from "allure-js-commons/sdk/node";
import { AllureCucumberTestRuntime } from "./runtime.js";

Before(function () {
// TODO: we can implement testplan logic there

setGlobalTestRuntime(
new AllureCucumberTestRuntime({
attach: this.attach,
Expand All @@ -189,3 +12,5 @@ Before(function () {
}),
);
});

export { AllureCucumberTestRuntime };
11 changes: 9 additions & 2 deletions packages/allure-cucumberjs/src/reporter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Formatter, IFormatterOptions, TestCaseHookDefinition } from "@cucumber/cucumber";
import { Formatter, IFormatterOptions, TestCaseHookDefinition, World } from "@cucumber/cucumber";
import * as messages from "@cucumber/messages";
import { PickleTag, Tag, TestStepResult, TestStepResultStatus } from "@cucumber/messages";
import os from "node:os";
Expand All @@ -19,7 +19,8 @@ import {
createStepResult,
getWorstStepResultStatus,
} from "allure-js-commons/sdk/node";
import { AllureCucumberReporterConfig, LabelConfig, LinkConfig } from "./model";
import { AllureCucumberReporterConfig, LabelConfig, LinkConfig } from "./model.js";
import { AllureCucumberTestRuntime } from "./runtime.js";

const { ALLURE_THREAD_NAME } = process.env;

Expand Down Expand Up @@ -71,6 +72,12 @@ export default class AllureCucumberReporter extends Formatter {

this.beforeHooks = options.supportCodeLibrary.beforeTestCaseHookDefinitions;
this.afterHooks = options.supportCodeLibrary.afterTestCaseHookDefinitions;

// set custom Allure World for single thread mode
if (options.supportCodeLibrary.World === World) {
// @ts-ignore
options.supportCodeLibrary.World = AllureCucumberTestRuntime;
}
}

private get tagsIgnorePatterns(): RegExp[] {
Expand Down
Loading
Loading