diff --git a/packages/allure-cypress/src/browser/commandLog.ts b/packages/allure-cypress/src/browser/commandLog.ts index e27d5fa30..fb587e74f 100644 --- a/packages/allure-cypress/src/browser/commandLog.ts +++ b/packages/allure-cypress/src/browser/commandLog.ts @@ -51,6 +51,7 @@ export const setupScreenshotAttachmentStep = (originalName: string | undefined, export const startCommandLogStep = (entry: CypressLogEntry) => { const currentLogEntry = getCurrentLogEntry(); + if (typeof currentLogEntry !== "undefined" && shouldStopCurrentLogStep(currentLogEntry.log, entry)) { stopCommandLogStep(currentLogEntry.log.attributes.id); } @@ -65,12 +66,14 @@ export const stopCommandLogStep = (entryId: string) => findAndStopStepWithSubste const pushLogEntry = (entry: CypressLogEntry) => { const id = entry.attributes.id; const stepDescriptor: LogStepDescriptor = { id, type: "log", log: entry }; + pushStep(stepDescriptor); // Some properties of some Command Log entries are undefined at the time the entry is stopped. An example is the // Yielded property of some queries. We defer converting them to Allure step parameters until the test/hook ends. setupStepFinalization(stepDescriptor, (data) => { data.parameters = getCommandLogStepParameters(entry); + if (stepDescriptor.attachmentName) { // Rename the step to match the attachment name. Once the names are the same, Allure will render the // attachment in the place of the step. @@ -146,18 +149,27 @@ const getLogProps = (entry: CypressLogEntry) => { attributes: { consoleProps }, } = entry; const isAssertionWithMessage = !!maybeGetAssertionLogMessage(entry); + const { props, name } = consoleProps(); + + // accessing LocalStorage after the page reload can stick the test runner + // to avoid the issue, we just need to log the command manually + // the problem potentially can happen with other storage related commands, like `clearAllLocalStorage`, `clearAllSessionStorage`, `getAllLocalStorage`, `getAllSessionStorage`, `setLocalStorage`, `setSessionStorage` + // but probably, we don't need to silent them all at this moment + // the context: https://github.com/allure-framework/allure-js/issues/1222 + if (["clearLocalStorage"].includes(name)) { + return [] as [string, unknown][]; + } // For assertion logs, we interpolate the 'Message' property, which contains unformatted assertion description, // directly into the step's name. // No need to keep the exact same information in the step's parameters. - return Object.entries(consoleProps().props).filter( - ([k, v]) => isDefined(v) && !(isAssertionWithMessage && k === "Message"), - ); + return Object.entries(props).filter(([k, v]) => isDefined(v) && !(isAssertionWithMessage && k === "Message")); }; const maybeGetAssertionLogMessage = (entry: CypressLogEntry) => { if (isAssertLog(entry)) { const message = entry.attributes.consoleProps().props.Message; + if (message && typeof message === "string") { return message; } diff --git a/packages/allure-cypress/src/browser/events/cypress.ts b/packages/allure-cypress/src/browser/events/cypress.ts index fd0514d00..969330e83 100644 --- a/packages/allure-cypress/src/browser/events/cypress.ts +++ b/packages/allure-cypress/src/browser/events/cypress.ts @@ -16,6 +16,7 @@ const onAfterScreenshot = ( ...[, { name: originalName, path }]: Parameters ) => { const name = originalName ?? getFileNameFromPath(path); + reportScreenshot(path, name); setupScreenshotAttachmentStep(originalName, name); }; diff --git a/packages/allure-cypress/src/browser/state.ts b/packages/allure-cypress/src/browser/state.ts index fb6a2154d..aa99d987e 100644 --- a/packages/allure-cypress/src/browser/state.ts +++ b/packages/allure-cypress/src/browser/state.ts @@ -3,6 +3,7 @@ import { DEFAULT_RUNTIME_CONFIG, last, toReversed } from "../utils.js"; export const getAllureState = () => { let state = Cypress.env("allure") as AllureSpecState; + if (!state) { state = { config: DEFAULT_RUNTIME_CONFIG, @@ -15,8 +16,10 @@ export const getAllureState = () => { stepsToFinalize: [], nextApiStepId: 0, }; + Cypress.env("allure", state); } + return state; }; diff --git a/packages/allure-cypress/src/browser/utils.ts b/packages/allure-cypress/src/browser/utils.ts index 573a11e30..2f9615589 100644 --- a/packages/allure-cypress/src/browser/utils.ts +++ b/packages/allure-cypress/src/browser/utils.ts @@ -30,7 +30,10 @@ export const uint8ArrayToBase64 = (data: unknown) => { export const getTestStartData = (test: CypressTest) => ({ ...getNamesAndLabels(Cypress.spec, test), - start: test.wallClockStartedAt?.getTime() || Date.now(), + start: + typeof test.wallClockStartedAt === "string" + ? Date.parse(test.wallClockStartedAt) + : test.wallClockStartedAt?.getTime?.() || Date.now(), }); export const getTestStopData = (test: CypressTest) => ({ diff --git a/packages/allure-cypress/test/spec/security.test.ts b/packages/allure-cypress/test/spec/security.test.ts new file mode 100644 index 000000000..608343d2e --- /dev/null +++ b/packages/allure-cypress/test/spec/security.test.ts @@ -0,0 +1,21 @@ +import { expect, it } from "vitest"; +import { Stage, Status } from "allure-js-commons"; +import { runCypressInlineTest } from "../utils.js"; + +it("shouldn't break the flow when access storage after the page reload", async () => { + const { tests } = await runCypressInlineTest({ + "cypress/e2e/sample.cy.js": () => ` + it("passed", () => { + cy.visit("https://allurereport.org"); + cy.clearLocalStorage(); + cy.wait(200); + cy.reload(); + cy.wait(200); + }); + `, + }); + + expect(tests).toHaveLength(1); + expect(tests[0].status).toBe(Status.PASSED); + expect(tests[0].stage).toBe(Stage.FINISHED); +});