Jest: Need a way to get test status in afterEach() method

Created on 12 Jan 2018  路  19Comments  路  Source: facebook/jest

Do you want to request a _feature_ or report a _bug_?
feature request.
What is the current behavior?
Cannot find a way to get test status in afterEach()

What is the expected behavior?
Need a way to get test status, like mocha can do this with this.currentTest.state.

Please provide your exact Jest configuration and mention your Jest, node,
yarn/npm version and operating system.

Jest 22.0.6

New API proposal

Most helpful comment

+1
In combination with Puppeteer it would be perfect to get the test status in afterEach().
e.g. we could create a screenshot in afterEach() if status is failed

All 19 comments

+1
In combination with Puppeteer it would be perfect to get the test status in afterEach().
e.g. we could create a screenshot in afterEach() if status is failed

As a data point, my company's test suite uses the mocha currentTest.state to rollback the current database transaction in a particular way if there was a failure. Seems to be a blocker for switching to Jest though I confess I'm not very experienced with the ins and outs of either our test suite or Jest :)

I use Browserstack to run my integration test, and I need to flag the browserstack build as complete or fail.
I must be in afterEach and / or afterAll because I need the driver instance currently used (see https://github.com/jeromemacias/nodium/blob/master/src/hook/browserstack.js)

Same as the others, we are using Jest with the TestObject/SauceLabs device farm and we need a way to get the current test status to update the test status on the TestObject website. It would be very useful to have something like this.currentTest in Mocha!

I was able to find a workaround to get the current test status using jasmine custom reports.

const reporter = {
  specDone: async result => {
    console.log(result.status);
    await driver.quit();
  }
};

jasmine.getEnv().addReporter(reporter);

Is there any progress on that?

Will this feature be implemented in the near future
Need to decide whether to use Jest or not for testing based on this feature availability

I believe the category of "passing state into tests/hooks" suggestions is currently not a top priority unfortunately.

Note that we recommend not using any jasmine-specific APIs like one of the comments suggests because jest-jasmine2 will be replaced as a default by jest-circus (likely in the next major).

This seems like something that could be implemented in user land? And made into reusable helpers with something like

test('a', saveTestState(() => {/* ... */}));
afterEach(ifTestFailed(() => {/* ... */}));

Hi @jeysal , thanks for the suggestion!
Can you please elaborate more about how to implement the saveTestState and ifTestFailed ?

I was thinking about something like:

let lastTestFailed;
export const saveTestState = async (testFn) => {
    try {
        await testFn()
        lastTestFailed = false;
    } catch (err) {
        lastTestFailed = true;
        throw err
    }
}
export const ifTestFailed = async (hookFn) => {
    if(lastTestFailed) await hookFn()
}

Not tested and not complete e.g. because it doesn't take the possible done callback into account, but that's the general idea.

I found a solution using jest-circus to implement a new testEnvironment, here is my code:

Create a file in the same directory as jest.config.js, named seleniumEnvironment.js

const JSDOMEnvironment = require('jest-environment-jsdom-fifteen')

class SeleniumEnvironment extends JSDOMEnvironment {
  constructor(config, context) {
    super(config, context)

    this.global.hasTestFailures = false
  }

  handleTestEvent(event, state) {
    if (event.name === 'test_fn_failure') {
      this.global.hasTestFailures = true
    }
  }
}

module.exports = SeleniumEnvironment

In jest.config.js I added: testEnvironment: './seleniumEnvironment',

Now in your afterEach/afterAll/ you can detect test failures via this.global.hasTestFailures.

I am also looking for a way to do this.

@pplante this didn't work for me. I have also never used jest-circus though. Are there any additional steps needed?

@rgomezp You need to define the jest-circus as test runner:
https://github.com/facebook/jest/tree/master/packages/jest-circus

Hack the global.jasmine.currentEnv_.fail works for me.

      describe('Name of the group', () => {

        beforeAll(() => {

          global.__CASE_FAILED__= false

          global.jasmine.currentEnv_.fail = new Proxy(global.jasmine.currentEnv_.fail,{
            apply(target, that, args) {
              global.__CASE__FAILED__ = true
              // you also can record the failed info...
              target.apply(that, args)
              }
            }
          )

        })

        afterAll(async () => {
          if(global.__CASE_FAILED__) {
            console.log("there are some case failed");
            // TODO ...
          }
        })

        it("should xxxx", async () => {
          // TODO ...
          expect(false).toBe(true)
        })
      });

I recently had to get access to the test name during the test, so I followed this comment https://github.com/facebook/jest/issues/7774#issuecomment-520780088.

My plan is to use jasmine.currentTest.failedExpectations.length > 0 to identify if there are errors in afterEach()

EDIT: FWIW, it works with playwright, failedExpectations includes TimeoutError from playwright.

  afterEach(() => {
    console.log(jasmine.currentTest)
    console.table(jasmine.currentTest)
  })

    it("asdf", async () => {
      await page.waitForSelector("does-not-exist", {
        timeout: 1000
      })
      // expect(true).toBe(false)
    })

Leaving our solution here in case it's useful to anybody else.

You can store current spec results in Jasmine and access it in afterEach.

  1. Add a custom Jasmine reporter for specStarted and store the spec results to jasmine.currentTest.

    jasmine.getEnv().addReporter( {
     specStarted: result => jasmine.currentTest = result
    } );
    

    The unintuitive thing about this is that even though we're storing this in specStarted before the results are in, jasmine.currentTest stores a reference to the result object which will get updated dynamically as the spec runs so when we access it in our afterEach, it will be holding the results of the spec properly.

  2. Check for failedExpectations in your afterEach and take a screenshot if there's been any failures.

    afterEach( async () => {
     if ( jasmine.currentTest.failedExpectations.length > 0 ) { // There has been a failure.
       await driver.takeScreenshot();
     }
    } );
    

Here's a link to my StackOverflow answer as well: https://stackoverflow.com/a/62557472/293280

How can I access jasmine in the .test.js files? I'm getting 'jasmine' is not defined. when I try to add a reporter.

How can I access jasmine in the .test.js files? I'm getting 'jasmine' is not defined. when I try to add a reporter.

I added the reporter in our Appium's driver.js file. There, jasmine is automatically setup (by Jest?) as a global. ESLint even complains about it not being defined but it's available at runtime.

as @joshuapinter explained here:

https://stackoverflow.com/a/62557472/293280
you can add an custom reporter to get access.

I created a little helper function:

get-current-spec-result.ts

let currentSpecResult: jasmine.CustomReporterResult;

jasmine.getEnv().addReporter({
  specStarted: (result) => currentSpecResult = result,
});

export function getCurrentSpecResult() {
  return currentSpecResult;
}

so I can import it in any spec and as a side effect, the reporter gets registered (but only if I use it and only once):

get-current-spec-result.spec.ts

import { getCurrentSpecResult } from './get-current-spec-result.ts';

describe('get spec result', () => {
  it('should fail', () => {
    fail('!');
  });

  afterEach(() => {
    const result = getCurrentSpecResult();
    const failed = result.failedExpectations?.pop();
    expect(failed).toBeTruthy();
  });
});

image

wicked? ;-D

Was this page helpful?
0 / 5 - 0 ratings