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

Cannot use "attach" in an afterEach hook #1051

Closed
3 tasks done
hammzj opened this issue Jul 6, 2023 · 9 comments
Closed
3 tasks done

Cannot use "attach" in an afterEach hook #1051

hammzj opened this issue Jul 6, 2023 · 9 comments

Comments

@hammzj
Copy link

hammzj commented Jul 6, 2023

Current behavior

I am trying to attach screenshots and logs for the Cucumber report, but it fails in the afterEach hook:

  cypress-cucumber-preprocessor testStepStartedHandler() +48ms
  cypress-cucumber-preprocessor afterScreenshotHandler() +2s
    1) An admin can open up the new program form
  cypress-cucumber-preprocessor testStepFinishedHandler() +10ms
  cypress-cucumber-preprocessor testCaseFinishedHandler() +2ms
  cypress-cucumber-preprocessor createStringAttachmentHandler() +57ms
  cypress-cucumber-preprocessor afterScreenshotHandler() +130ms
    2) "after each" hook for "An admin can open up the new program form"
cypress-terminal-report: Wrote custom logs to logs. (2ms)


  0 passing (5s)
  2 failing

  1) Admin index page
       An admin can open up the new program form:
     AssertionError: Timed out retrying after 2000ms: Expected to find content: 'Program Names' but never did.
      at Context.eval (../../e2e/step_definitions/page_steps/common.page.steps.js:193:22)
      at Registry.runStepDefininition (../../../node_modules/@badeball/cypress-cucumber-preprocessor/dist/registry.js:136:0)
      at Object.fn (../../../node_modules/@badeball/cypress-cucumber-preprocessor/dist/browser-runtime.js:348:0)
      at runStepWithLogGroup (../../../node_modules/@badeball/cypress-cucumber-preprocessor/dist/helpers/cypress.js:51:0)
      at Context.eval (../../../node_modules/@badeball/cypress-cucumber-preprocessor/dist/browser-runtime.js:344:0)

  2) Admin index page
       "after each" hook for "An admin can open up the new program form":
     CypressError: `cy.task('cypress-cucumber-preprocessor:create-string-attachment')` failed with the following error:

> Unexpected state in createStringAttachmentHandler: test-finished (this might be a bug, please report at https://github.com/badeball/cypress-cucumber-preprocessor)

https://on.cypress.io/api/task

Because this error occurred during a `after each` hook we are skipping all of the remaining tests.
      at <unknown> (https:/<removed>.comm/__cypress/runner/cypress_runner.js:150983:78)
      at tryCatcher (https:/<removed>.comm/__cypress/runner/cypress_runner.js:18744:23)
      at Promise._settlePromiseFromHandler (https:/<removed>.comm/__cypress/runner/cypress_runner.js:16679:31)
      at Promise._settlePromise (https:/<removed>.comm/__cypress/runner/cypress_runner.js:16736:18)
      at Promise._settlePromise0 (https:/<removed>.comm/__cypress/runner/cypress_runner.js:16781:10)
      at Promise._settlePromises (https:/<removed>.comm/__cypress/runner/cypress_runner.js:16857:18)
      at _drainQueueStep (https:/<removed>.comm/__cypress/runner/cypress_runner.js:13451:12)
      at _drainQueue (https:/<removed>.comm/__cypress/runner/cypress_runner.js:13444:9)
      at ../../node_modules/bluebird/js/release/async.js.Async._drainQueues (https:/<removed>.comm/__cypress/runner/cypress_runner.js:13460:5)
      at Async.drainQueues (https:/<removed>.comm/__cypress/runner/cypress_runner.js:13330:14)
  From Your Spec Code:
      at createStringAttachment (../../../node_modules/@badeball/cypress-cucumber-preprocessor/dist/entrypoint-browser.js:92:0)
      at attach (../../../node_modules/@badeball/cypress-cucumber-preprocessor/dist/entrypoint-browser.js:101:0)
      at Context.eval (../../e2e/step_definitions/_setup/hooks.js:39:8)
  
  From Node.js Internals:
    Error: Unexpected state in createStringAttachmentHandler: test-finished (this might be a bug, please report at https://github.com/badeball/cypress-cucumber-preprocessor)
        at createError (~/<cypress_project>/node_modules/@badeball/cypress-cucumber-preprocessor/dist/helpers/error.js:9:12)
        at createStringAttachmentHandler (~/<cypress_project>/node_modules/@badeball/cypress-cucumber-preprocessor/dist/plugin-event-handlers.js:434:43)
        at processTicksAndRejections (node:internal/process/task_queues:95:5)



  cypress-cucumber-preprocessor afterSpecHandler() +81ms
  Hook failures can't be represented in messages / JSON reports, thus none is created for cypress/e2e/common/admin/index.page.feature.

Desired behavior

Attachments using attach should be allowed to occur in the afterEach hook, even if the test has completed.

Test code to reproduce

//hooks.js
const {attach} = require("@badeball/cypress-cucumber-preprocessor");

afterEach(function () {
  attach({message: 'hello there'}, `application/json`);
});

//You can also try this, which attaches on test failure
afterEach(function () {
  if (this.currentTest?.state === "failed") {
    attach({message: 'error'}, `application/json`);
  }
});

Versions

  • Cypress version: 12.12.0
  • Preprocessor version: 18.0.1
  • Node version: 18.16.0

Checklist

@badeball
Copy link
Owner

badeball commented Jul 7, 2023

As per now, this is unfortunately intended behavior. Attachments is a Cucumber-term that must be associated with a step and afterEach hooks aren't part of any steps. What is your use-case here, spesifically?

@hammzj
Copy link
Author

hammzj commented Jul 7, 2023

For the way our tests run through Jenkins CI/CD, we can only have one instance of a workspace available for the newest job run. In this workspace, I can see any screenshots collected by Cypress for failed tests, but as soon as a new job begins, those are wiped out.

By attaching these screenshots and additional log files to the scenario in Cucumber report, I'll have a constant history of what failed since those reports could be retained in Jenkins for a longer time. I've used other reporting tools for non-Cypress projects and we're able to add attachments post-scenario. I know this isn't the case for Cypress, but it feels like there is a discrepancy.

Cucumber messages are appended linearly. While the scenario may have ended, the afterEach hook allows me to attach a screenshot which will appear for the last step in that scenario; when the next scenario begins, it's ok that I don't have access to the previous scenario since it finished and a new one began. But using the afterEach hook comes directly after the testCaseFinished message completes, so I know I will still have access to attachments in the scenario. I did test this by editing the preprocessor to skip that error, and I saw an attachment added to the last step in the scenario.

@badeball
Copy link
Owner

badeball commented Jul 7, 2023

Screenshots of failed tests are automatically added to reports, as well as the error causing the test to fail. What else is there to add?

@hammzj
Copy link
Author

hammzj commented Jul 10, 2023

Ok, so did a re-run and at first, screenshots were not being added at first due to a custom configuration, but I see it available now. I misspoke on the first part.

However, in our suite's particular case, we prefer to track the Cypress logs using cypress-terminal-report as it contains specific datasets that we sometimes need to track within our tests. Since we only will create these files on test failure, it is important to add them to the report's last step if possible so we may see the full Cypress logs.

@MDG-JHowley
Copy link

I have a similar requirement and resolve this with the Cypress fail event i.e. Cypress.on('fail',...). The below is extracted from a load of other code but the principle should be fine.

Like this:

In whatever your support file is:

import { attach } from '@badeball/cypress-cucumber-preprocessor';

const attachLogs = () => {

  // this will be specific to your setup...
  const logPath = [urlPrefix(), 'logs', `${getFeatureFilename()}`].join('/');

  // I'm using test/html because our cucumber reports end up in a third party service but you could attach the string rather than a URL
  attach(
    btoa(
      `<strong>Feature file Cypress command log:</strong><ul><li><a href="${logPath}.txt">txt format</a></li><li><a href="${logPath}.json">JSON format</a></li></ul>`
    ),
    'base64:text/html'
  );
};


Cypress.on('fail', (e, runnable) => {
  const { actual, expected, message } = e;

  try {
    //only add attachments if we are on the final attempt?
    if (runnable._retries == runnable._currentRetry) {
     attachLogs()
    }
  } catch (error) {
    // Any failure here should not impact the test itself!
  }
});

If you did want to always attach logs, even when a test passes you could additionally utilise a common After hook (note this must be the cucumber-style hook from the pre-processor). Due to the pre-preocessor implementation this will run while a test context still exists.

@badeball
Copy link
Owner

@MDG-JHowley, does calling attach in the fail-handler actually work and generate correct result? Generally speaking, you can't invoke any commands in such handlers, which attach does under the hood.

@badeball
Copy link
Owner

badeball commented Jul 10, 2023

@hammzj, said project appears to be able to log to file, which can be retained in Jenkins. This also feels a lot like a XY problem, which is a huge waste of someones' time.

@hammzj
Copy link
Author

hammzj commented Jul 10, 2023

It seems like this is related similarly to #824, for which I reported the behavior of how Cucumber-js handles it. The same behavior exists for attachments in an After hook where it is possible to add them to a scenario as soon as it finishes. In this case, I'm using a Mocha hook rather than the Cucumber hook due to the above limitation.

I understand this limitation, but this isn't the XY problem since the behavior of the preprocessor differs from the official Cucumber implementation; however, due to the issue with running After hooks on failures described in issue 824, this can be closed out as it seems that neither attempt will be accessible.

@MDG-JHowley
Copy link

MDG-JHowley commented Jul 10, 2023

@MDG-JHowley, does calling attach in the fail-handler actually work and generate correct result? Generally speaking, you can't invoke any commands in such handlers, which attach does under the hood.

@badeball Seems to work fine. I mean I'm actively using it to embed links to screenshots, videos and logs to cucumber reports.

Incidentally I had some issues with the screenshots because you are embedding the image inline and in my workflow I need to upload the cucumber JSON file to a 3rd party service so this makes the filesize a bit large (the screenshots/videos are upload to hosted storage separately anyway). If it were possible to use attach in a node context if would be much simpler but your plugin doesn't support that. Instead I am using omitAfterScreenshotHandler in the plugin options and just working out the eventual local file path and eventual hosted URL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants