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

Legacy runtime API for Allure Mocha #975

Closed
wants to merge 10 commits into from
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = {
sourceType: "module",
warnOnUnsupportedTypeScriptVersion: false,
},
ignorePatterns: ["./**/dist/**/*"],
plugins: [
"eslint-plugin-no-null",
"eslint-plugin-prefer-arrow",
Expand Down
36 changes: 17 additions & 19 deletions packages/allure-js-commons/src/sdk/ReporterRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,23 @@ export class ReporterRuntime {
this.writeAttachmentForItem(attachment, targetResult);
};

/* TODO: Add executors.json */
writeAttachmentForItem = (attachment: RawAttachment, item: Executable) => {
const attachmentFilename = this.buildAttachmentFileName(attachment);

this.writer.writeAttachment(
attachmentFilename,
attachment.content,
(attachment.encoding as BufferEncoding) || "base64",
);

const rawAttachment = {
name: attachment.name,
source: attachmentFilename,
type: attachment.contentType,
};

item.attachments.push(rawAttachment);
};

writeEnvironmentInfo = () => {
if (!this.environmentInfo) {
Expand Down Expand Up @@ -852,24 +868,6 @@ export class ReporterRuntime {
this.writeAttachmentForItem(message.data, step ?? root);
};

private writeAttachmentForItem = (attachment: RawAttachment, item: Executable) => {
const attachmentFilename = this.buildAttachmentFileName(attachment);

this.writer.writeAttachment(
attachmentFilename,
attachment.content,
(attachment.encoding as BufferEncoding) || "base64",
);

const rawAttachment = {
name: attachment.name,
source: attachmentFilename,
type: attachment.contentType,
};

item.attachments.push(rawAttachment);
};

private startScopeWithUuid = (uuid: string, { manual, parent }: StartScopeOpts = {}) => {
const newScope = this.state.setScope(uuid);

Expand Down
16 changes: 16 additions & 0 deletions packages/allure-mocha/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,20 @@ module.exports = {
parserOptions: {
project: "./tsconfig.json",
},
overrides: [
{
files: ["**/*.cjs"],
rules: {
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-var-requires": "off",
},
},
{
files: ["./test/fixtures/samples/**/*.js", "./test/fixtures/runner.js"],
rules: {
"no-undef": "off",
"@typescript-eslint/no-unsafe-argument": "off",
},
},
],
};
18 changes: 13 additions & 5 deletions packages/allure-mocha/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,22 @@
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts",
"default": "./dist/index.cjs"
},
"./runtime": {
"import": "./dist/legacy.mjs",
"require": "./dist/legacy.cjs",
"types": "./dist/legacy.d.ts",
"default": "./dist/legacy.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist",
"runtime.js",
"runtime.d.ts"
"dist"
],
"scripts": {
"allure-report": "allure serve ./out/allure-results",
Expand All @@ -44,7 +50,9 @@
"lint:fix": "eslint ./src ./test --ext .ts --fix",
"test": "yarn run test:serial && yarn run test:parallel",
"test:serial": "vitest run ./test/spec/**/*.test.ts",
"test:parallel": "ALLURE_MOCHA_TEST_PARALLEL=true vitest run ./test/spec/**/*.test.ts"
"test:parallel": "ALLURE_MOCHA_TEST_PARALLEL=true vitest run ./test/spec/**/*.test.ts",
"test:esm": "ALLURE_MOCHA_TEST_RUNNER=esm ALLURE_MOCHA_TEST_SPEC_FORMAT=esm vitest run ./test/spec/**/*.test.ts",
"test:cjs": "ALLURE_MOCHA_TEST_RUNNER=cjs ALLURE_MOCHA_TEST_SPEC_FORMAT=cjs vitest run ./test/spec/**/*.test.ts"
},
"dependencies": {
"allure-js-commons": "workspace:*"
Expand Down
69 changes: 30 additions & 39 deletions packages/allure-mocha/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,30 @@ import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { defineConfig } from "rollup";

const dirname = fileURLToPath(new URL(".", import.meta.url));
const outdir = join(fileURLToPath(new URL(".", import.meta.url)), "dist");
const external = [
"mocha",
"node:os",
"node:fs",
"node:path",
"node:process",
"node:url",
"node:worker_threads",
"allure-js-commons",
"allure-js-commons/sdk",
"allure-js-commons/sdk/node",
"mocha/lib/nodejs/reporters/parallel-buffered.js",
];

const createNodeEntry = (inputFile) => {
const outputFileBase = inputFile.replace(/^src/, "dist");
const external = [
"mocha",
"node:os",
"node:fs",
"node:path",
"node:process",
"node:worker_threads",
"allure-js-commons",
"allure-js-commons/sdk/node",
"mocha/lib/nodejs/reporters/parallel-buffered.js",
];

return [
defineConfig({
input: inputFile,
output: {
file: join(dirname, outputFileBase.replace(/\.ts$/, ".mjs")),
format: "esm",
exports: "named",
sourcemap: true,
},
plugins: [
typescriptPlugin({
tsconfig: "./tsconfig.rollup.json",
}),
],
external,
}),
defineConfig({
input: inputFile,
const createEntryConfigs = (entry, { format = ["cjs", "esm"], exports = "default" } = {}) => {
return (format instanceof Array ? format : [format]).map((f) => {
const outext = f === "cjs" ? ".cjs" : ".mjs";
return defineConfig({
input: join("src", `${entry}.ts`),
output: {
file: join(dirname, outputFileBase.replace(/\.ts$/, ".cjs")),
format: "cjs",
exports: "named",
file: join(outdir, `${entry}${outext}`),
format: f,
exports: exports,
sourcemap: true,
},
plugins: [
Expand All @@ -50,10 +36,15 @@ const createNodeEntry = (inputFile) => {
}),
],
external,
}),
];
});
});
};

export default () => {
return [createNodeEntry("src/index.ts"), createNodeEntry("src/setupAllureMochaParallel.ts")].flat();
return [
createEntryConfigs("index", { format: "cjs" }),
createEntryConfigs("index", { format: "esm", exports: "named" }),
createEntryConfigs("legacy", { exports: "named" }),
createEntryConfigs("setupAllureMochaParallel", { exports: "none" }),
].flat();
};
5 changes: 4 additions & 1 deletion packages/allure-mocha/src/MochaTestRuntime.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MessageTestRuntime, ReporterRuntime, RuntimeMessage, setGlobalTestRuntime } from "allure-js-commons/sdk/node";
import { setLegacyApiRuntime } from "./legacyUtils.js";

export class MochaTestRuntime extends MessageTestRuntime {
constructor(private readonly reporterRuntime: ReporterRuntime) {
Expand All @@ -11,5 +12,7 @@ export class MochaTestRuntime extends MessageTestRuntime {
}
}

export const setUpTestRuntime = (reporterRuntime: ReporterRuntime) =>
export const setUpTestRuntime = (reporterRuntime: ReporterRuntime) => {
setGlobalTestRuntime(new MochaTestRuntime(reporterRuntime));
setLegacyApiRuntime(reporterRuntime);
};
4 changes: 2 additions & 2 deletions packages/allure-mocha/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { MochaAllureReporter } from "./reporter.js";
import { AllureMochaReporter } from "./reporter.js";

export default MochaAllureReporter;
export default AllureMochaReporter;
155 changes: 155 additions & 0 deletions packages/allure-mocha/src/legacy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import * as commons from "allure-js-commons";
import type { Category, ContentType, ParameterOptions } from "allure-js-commons";
import { Stage, Status, getStatusFromError, isPromise } from "allure-js-commons/sdk";
import { getLegacyApiRuntime } from "./legacyUtils.js";

interface StepInterface {
parameter(name: string, value: string): void;
name(name: string): void;
}

interface AttachmentOptions {
contentType: ContentType | string;
fileExtension?: string;
}

class LegacyAllureApi {
epic = (epic: string) => Promise.resolve(commons.epic(epic));
feature = (feature: string) => Promise.resolve(commons.feature(feature));
story = (story: string) => Promise.resolve(commons.story(story));
suite = (name: string) => Promise.resolve(commons.suite(name));
parentSuite = (name: string) => Promise.resolve(commons.parentSuite(name));
subSuite = (name: string) => Promise.resolve(commons.subSuite(name));
label = (name: string, value: string) => Promise.resolve(commons.label(name, value));
parameter = (name: string, value: any, options?: ParameterOptions) =>
Promise.resolve(commons.parameter(name, commons.serialize(value), options));
link = (url: string, name?: string, type?: string) => Promise.resolve(commons.link(url, type, name));
issue = (name: string, url: string) => Promise.resolve(commons.issue(url, name));
tms = (name: string, url: string) => Promise.resolve(commons.tms(url, name));
description = (markdown: string) => Promise.resolve(commons.description(markdown));
descriptionHtml = (html: string) => Promise.resolve(commons.descriptionHtml(html));
owner = (owner: string) => Promise.resolve(commons.owner(owner));
severity = (severity: string) => Promise.resolve(commons.severity(severity));
layer = (layer: string) => Promise.resolve(commons.layer(layer));
id = (allureId: string) => Promise.resolve(commons.allureId(allureId));
tag = (tag: string) => Promise.resolve(commons.tag(tag));
writeEnvironmentInfo = (info: Record<string, string>) => {
getLegacyApiRuntime()?.writer.writeEnvironmentInfo(info);
};
writeCategoriesDefinitions = (categories: Category[]) => {
getLegacyApiRuntime()?.writer.writeCategoriesDefinitions(categories);
};
attachment = (name: string, content: Buffer | string, options: ContentType | string | AttachmentOptions) =>
Promise.resolve(commons.attachment(name, content, typeof options === "string" ? options : options.contentType));
testAttachment = (name: string, content: Buffer | string, options: ContentType | string | AttachmentOptions) => {
const runtime = getLegacyApiRuntime();
const currentTest = runtime?.getCurrentTest();
if (currentTest) {
runtime?.writeAttachmentForItem(
{
name,
content: Buffer.from(content).toString("base64"),
contentType: typeof options === "string" ? options : options.contentType,
encoding: "base64",
fileExtension: typeof options === "string" ? undefined : options.fileExtension,
},
currentTest,
);
}
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
logStep = (name: string, status?: Status) => {
this.step(name, () => {
getLegacyApiRuntime()?.updateStep((s) => (s.status = status));
});
};
// It's sync-first. That's why we can't simply reuse commons.step.
step = <T>(name: string, body: (step: StepInterface) => T): T => {
const runtime = getLegacyApiRuntime();
runtime?.applyRuntimeMessages([
{
type: "step_start",
data: {
name,
start: Date.now(),
},
},
]);
try {
const result = body({
name: this.renameStep,
parameter: this.addStepParameter,
});
if (isPromise(result)) {
const promise = result as Promise<any>;
return promise
.then((v) => {
this.stopStepSuccess();
return v;
})
.catch((e) => {
this.stopStepWithError(e);
throw e;
}) as T;
}
this.stopStepSuccess();
return result;
} catch (e) {
this.stopStepWithError(e);
throw e;
}
};

private renameStep = (name: string) => {
getLegacyApiRuntime()?.applyRuntimeMessages([
{
type: "step_metadata",
data: { name },
},
]);
};

private addStepParameter = (name: string, value: string) => {
getLegacyApiRuntime()?.applyRuntimeMessages([
{
type: "step_metadata",
data: {
parameters: [{ name, value }],
},
},
]);
};

private stopStepSuccess = () => {
getLegacyApiRuntime()?.applyRuntimeMessages([
{
type: "step_stop",
data: {
status: Status.PASSED,
stage: Stage.FINISHED,
stop: Date.now(),
},
},
]);
};

private stopStepWithError = (error: unknown) => {
const { message, stack } = error as Error;
getLegacyApiRuntime()?.applyRuntimeMessages([
{
type: "step_stop",
data: {
status: getStatusFromError(error as Error),
stage: Stage.FINISHED,
stop: Date.now(),
statusDetails: {
message,
trace: stack,
},
},
},
]);
};
}

export const allure = new LegacyAllureApi();
8 changes: 8 additions & 0 deletions packages/allure-mocha/src/legacyUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { ReporterRuntime } from "allure-js-commons/sdk";

const ALLURE_TEST_RUNTIME_KEY = "__allure_mocha_legacy_runtime__";

export const getLegacyApiRuntime = () => (globalThis as any)[ALLURE_TEST_RUNTIME_KEY] as ReporterRuntime;

export const setLegacyApiRuntime = (runtime: ReporterRuntime) =>
((globalThis as any)[ALLURE_TEST_RUNTIME_KEY] = runtime);
2 changes: 1 addition & 1 deletion packages/allure-mocha/src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const {
EVENT_HOOK_END,
} = Mocha.Runner.constants;

export class MochaAllureReporter extends Mocha.reporters.Base {
export class AllureMochaReporter extends Mocha.reporters.Base {
private readonly runtime: AllureNodeReporterRuntime;

constructor(runner: Mocha.Runner, opts: Mocha.MochaOptions) {
Expand Down
Loading
Loading