Skip to content

Commit

Permalink
cypress test plan support (via #1037)
Browse files Browse the repository at this point in the history
  • Loading branch information
epszaw authored Jul 2, 2024
1 parent bf85b9d commit 08eea54
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 19 deletions.
38 changes: 33 additions & 5 deletions packages/allure-cypress/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AttachmentOptions, Label, Link, ParameterMode, ParameterOptions, StatusDetails } from "allure-js-commons";
import { ContentType, Status } from "allure-js-commons";
import type { RuntimeMessage } from "allure-js-commons/sdk";
import type { RuntimeMessage, TestPlanV1 } from "allure-js-commons/sdk";
import { getUnfinishedStepsMessages, hasStepMessage } from "allure-js-commons/sdk";
import type { TestRuntime } from "allure-js-commons/sdk/runtime";
import { getGlobalTestRuntime, setGlobalTestRuntime } from "allure-js-commons/sdk/runtime";
Expand All @@ -13,12 +13,13 @@ import type {
CypressTest,
CypressTestStartMessage,
} from "./model.js";
import { ALLURE_REPORT_SHUTDOWN_HOOK, ALLURE_REPORT_STEP_COMMAND } from "./model.js";
import { ALLURE_REPORT_STEP_COMMAND, ALLURE_REPORT_SYSTEM_HOOK } from "./model.js";
import {
getHookType,
getSuitePath,
isCommandShouldBeSkipped,
isGlobalHook,
isTestPresentInTestPlan,
toReversed,
uint8ArrayToBase64,
} from "./utils.js";
Expand Down Expand Up @@ -231,7 +232,7 @@ const initializeAllure = () => {
setGlobalTestRuntime(testRuntime);
})
.on(EVENT_HOOK_BEGIN, (hook: CypressHook) => {
if (hook.title.includes(ALLURE_REPORT_SHUTDOWN_HOOK)) {
if (hook.title.includes(ALLURE_REPORT_SYSTEM_HOOK)) {
return;
}

Expand All @@ -252,7 +253,7 @@ const initializeAllure = () => {
});
})
.on(EVENT_HOOK_END, (hook: CypressHook) => {
if (hook.title.includes(ALLURE_REPORT_SHUTDOWN_HOOK)) {
if (hook.title.includes(ALLURE_REPORT_SYSTEM_HOOK)) {
return;
}

Expand Down Expand Up @@ -408,6 +409,11 @@ const initializeAllure = () => {
})
.on(EVENT_TEST_PENDING, (test: CypressTest) => {
const testRuntime = new AllureCypressTestRuntime();
const testPlan = Cypress.env("allureTestPlan") as TestPlanV1;

if (testPlan && !isTestPresentInTestPlan(Cypress.currentTest, Cypress.spec, testPlan)) {
return;
}

testRuntime.sendMessageAsync({
type: "cypress_test_start",
Expand Down Expand Up @@ -516,7 +522,29 @@ const initializeAllure = () => {
});
});

after(ALLURE_REPORT_SHUTDOWN_HOOK, () => {
before(ALLURE_REPORT_SYSTEM_HOOK, () => {
cy.task("readAllureTestPlan", {}, { log: false }).then((testPlan) => {
if (!testPlan) {
return;
}

Cypress.env("allureTestPlan", testPlan);
});
});

beforeEach(ALLURE_REPORT_SYSTEM_HOOK, function () {
const testPlan = Cypress.env("allureTestPlan") as TestPlanV1;

if (!testPlan) {
return;
}

if (!isTestPresentInTestPlan(Cypress.currentTest, Cypress.spec, testPlan)) {
this.skip();
}
});

after(ALLURE_REPORT_SYSTEM_HOOK, () => {
const runtimeMessages = Cypress.env("allureRuntimeMessages") as CypressMessage[];

cy.task(
Expand Down
2 changes: 1 addition & 1 deletion packages/allure-cypress/src/model.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Status, StatusDetails } from "allure-js-commons";
import type { RuntimeMessage } from "allure-js-commons/sdk";

export const ALLURE_REPORT_SHUTDOWN_HOOK = "__allure_report_shutdown_hook__";
export const ALLURE_REPORT_SYSTEM_HOOK = "__allure_report_system_hook__";

export const ALLURE_REPORT_STEP_COMMAND = "__allure_report_step_command__";

Expand Down
5 changes: 4 additions & 1 deletion packages/allure-cypress/src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type Cypress from "cypress";
import { ContentType, LabelName, Stage, Status } from "allure-js-commons";
import type { RuntimeMessage } from "allure-js-commons/sdk";
import { extractMetadataFromString } from "allure-js-commons/sdk";
import { FileSystemWriter, ReporterRuntime, getSuiteLabels } from "allure-js-commons/sdk/reporter";
import { FileSystemWriter, ReporterRuntime, getSuiteLabels, parseTestPlan } from "allure-js-commons/sdk/reporter";
import type { Config } from "allure-js-commons/sdk/reporter";
import type {
CypressHookEndMessage,
Expand Down Expand Up @@ -42,6 +42,9 @@ export class AllureCypress {

attachToCypress(on: Cypress.PluginEvents) {
on("task", {
readAllureTestPlan: () => {
return parseTestPlan() ?? null;
},
allureReportTest: ({ messages, absolutePath }: { messages: CypressMessage[]; absolutePath: string }) => {
this.messagesByAbsolutePath.set(absolutePath, messages);

Expand Down
34 changes: 23 additions & 11 deletions packages/allure-cypress/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { LabelName } from "allure-js-commons";
import type { TestPlanV1 } from "allure-js-commons/sdk";
import { extractMetadataFromString } from "allure-js-commons/sdk";
import type { CypressCommand } from "./model.js";
import { ALLURE_REPORT_STEP_COMMAND } from "./model.js";

Expand All @@ -13,17 +16,6 @@ export const uint8ArrayToBase64 = (data: unknown) => {
return btoa(String.fromCharCode.apply(null, data as number[]));
};

export const normalizeAttachmentContentEncoding = (data: unknown, encoding: BufferEncoding): BufferEncoding => {
// @ts-ignore
const u8arrayLike = Array.isArray(data) || data.buffer;

if (u8arrayLike) {
return "base64";
}

return encoding;
};

export const getSuitePath = (test: Mocha.Test): string[] => {
const path: string[] = [];
let currentSuite: Mocha.Suite | undefined = test.parent;
Expand Down Expand Up @@ -82,3 +74,23 @@ export const getHookType = (hookName: string) => {
export const last = <T = unknown>(arr: T[]): T | undefined => {
return arr[arr.length - 1];
};

export const isTestPresentInTestPlan = (
test: {
title: string;
titlePath: string[];
},
spec: Cypress.Spec,
testPlan: TestPlanV1,
) => {
const testFullName = `${spec.relative}#${test.titlePath.join(" ")}`;
const { labels } = extractMetadataFromString(test.title);
const allureIdLabel = labels.find(({ name }) => name === LabelName.ALLURE_ID);

return testPlan.tests.some(({ id, selector = "" }) => {
const idMatched = id ? String(id) === allureIdLabel?.value : false;
const selectorMatched = selector === testFullName;

return idMatched || selectorMatched;
});
};
83 changes: 83 additions & 0 deletions packages/allure-cypress/test/spec/testplan.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { join } from "node:path";
import { expect, it } from "vitest";
import type { TestPlanV1 } from "allure-js-commons/sdk";
import { runCypressInlineTest } from "../utils.js";

it("respects testplan", async () => {
const exampleTestPlan: TestPlanV1 = {
version: "1.0",
tests: [
{
id: 1,
selector: "cypress/e2e/nested/super strange nested/super strange name.cy.js#also nested should execute",
},
{
id: 2,
selector: "cypress/e2e/b.cy.js#should execute",
},
{
id: 3,
selector: "cypress/e2e/.+.cy.js#+.",
},
{
id: 4,
selector: "cypress/e2e/notaga.cy.js#a",
},
],
};
const testPlanFilename = "example-testplan.json";
const { tests } = await runCypressInlineTest(
{
[testPlanFilename]: () => JSON.stringify(exampleTestPlan),
"cypress/e2e/a.test.js": () => `
it('should not execute', () => {
cy.wrap(1).should("eq", 1);
});
`,
"cypress/e2e/b.cy.js": () => `
it('should execute', () => {
cy.wrap(1).should("eq", 1);
});
`,
"cypress/e2e/nested/super strange nested/super strange name.cy.js": () => `
describe('also nested', () => {
it('should execute', () => {
cy.wrap(1).should("eq", 1);
});
});
`,
"cypress/e2e/.+.cy.js": () => `
it('+.', () => {
cy.wrap(1).should("eq", 1);
});
`,
"cypress/e2e/aga.cy.js": () => `
it('a', () => {
cy.wrap(1).should("eq", 1);
});
it('aa', () => {
cy.wrap(1).should("eq", 1);
});
it('selected name @allure.id=5', () => {
cy.wrap(1).should("eq", 1);
});
`,
"cypress/e2e/notaga.cy.js": () => `
it('a', () => {
cy.wrap(1).should("eq", 1);
});
`,
},
(testDir) => ({
ALLURE_TESTPLAN_PATH: join(testDir, testPlanFilename),
}),
);

expect(tests.map(({ fullName }) => fullName)).toEqual(
expect.arrayContaining([
"cypress/e2e/b.cy.js#should execute",
"cypress/e2e/notaga.cy.js#a",
"cypress/e2e/nested/super strange nested/super strange name.cy.js#also nested should execute",
]),
);
});
6 changes: 5 additions & 1 deletion packages/allure-cypress/test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ type CypressTestFiles = Record<
(modulesPaths: { allureCommonsModulePath: string; allureCypressModulePath: string }) => string
>;

export const runCypressInlineTest = async (testFiles: CypressTestFiles): Promise<AllureResults> => {
export const runCypressInlineTest = async (
testFiles: CypressTestFiles,
env?: (testDir: string) => Record<string, string>,
): Promise<AllureResults> => {
const res: AllureResults = {
tests: [],
groups: [],
Expand Down Expand Up @@ -70,6 +73,7 @@ export const runCypressInlineTest = async (testFiles: CypressTestFiles): Promise
const testProcess = fork(modulePath, args, {
env: {
...process.env,
...env?.(testDir),
},
cwd: testDir,
stdio: "pipe",
Expand Down

0 comments on commit 08eea54

Please sign in to comment.