18

I want to run a function / task whenever any jest test fails. Instead of wrapping all of my test's with try / catch or add an if check, is there a way I can utilize the afterEach ?

If the test fails then I want it to fail, just run a separate function.

For example:

test('nav loads correctly', async () => {
    const listItems = await page.$$('[data-testid="navBarLi"]')

    expect(listItems.length).toBe(4)

    if (listItems.length !== 4)
      await page.screenshot({path: 'screenshot.png'})

  })

This is adding an if check... But I want something more robust for all of my tests.

Towkir
  • 3,889
  • 2
  • 22
  • 41
Tyler Clark
  • 181
  • 1
  • 3
  • What will be the purpose of this function? will it log the failure? – Or B Jan 22 '18 at 19:05
  • 3
    basically I want to take a screenshot when a test fails.. (I'm using google's puppeteer). AfterEach would work if it had access to the current test. To check if it passes or fails. But looks like this is not built in https://github.com/facebook/jest/issues/5292 – Tyler Clark Jan 22 '18 at 19:25
  • 4
    The other option I could think of, is implementing a [reporter](https://facebook.github.io/jest/docs/en/configuration.html#reporters-array-modulename-modulename-options) (in addition to the default one). – Or B Jan 22 '18 at 19:36
  • there is discussion in https://github.com/smooth-code/jest-puppeteer/issues/43 with some workarounds. Also [jest-screenshot-reporter](https://github.com/alexeyraspopov/jest-webdriver/blob/master/packages/jest-screenshot-reporter/modules/JestScreenshotReporter.js) sounds like exactly what you need – skyboyer Oct 21 '18 at 07:41
  • Possible duplicate of [Check if test failed in afterEach of Jest](https://stackoverflow.com/questions/42000137/check-if-test-failed-in-aftereach-of-jest) – A Jar of Clay May 20 '19 at 10:53

3 Answers3

4

@Tyler Clark I haven't attempted this with afterEach, but I suspect you could apply something similar this my SO answer here. (pasting a version of it below for context - altered to work with afterEach)

const GLOBAL_STATE = Symbol.for('$$jest-matchers-object');

describe('Describe test', () => {
  afterEach(() => {
    if (global[GLOBAL_STATE].state.snapshotState.matched !== 1) {
      console.log(`\x1b[31mWARNING!!! Catch snapshot failure here and print some message about it...`);
    }
  });

  it('should test something', () => {
    expect({}).toMatchSnapshot(); // replace {} with whatever you're trying to test
  });
});
Jeremy
  • 1,717
  • 5
  • 30
  • 49
2

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(); // Or whatever else you want to do when a failure occurs.
      }
    } );
    
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
0

Why not use try/catch?

If you don't like how it looks, you can hide the ugliness away in a function:

function runAssertion(assertion, onFailure) {
    try {
        assertion();
    } catch (exception) {
        onFailure();
        throw exception;
    }
}

Then call it like so:

test('nav loads correctly', async () => {
    const listItems = await page.$$('[data-testid="navBarLi"]')

    runAssertion(
        () => { expect(listItems.length).toBe(4) },
        () => { await page.screenshot({path: 'screenshot.png'}) }
    )
})

This is the approach our team has taken to avoid using try/catch everywhere.

byxor
  • 5,930
  • 4
  • 27
  • 44
  • 1
    This doesn't seem to work when using `toMatchSnapshot` – Jeremy Dec 10 '19 at 00:49
  • @Jeremy Sorry, I've never used `toMatchSnapshot`. It must not throw an exception when it fails. – byxor Dec 10 '19 at 11:05
  • 2
    that's exactly it - see [this github issue](https://github.com/facebook/jest/issues/5802). My [SO answer here](https://stackoverflow.com/a/59258872/4064901) addresses a solution – Jeremy Dec 10 '19 at 15:39
  • 1
    You shouldn't have to write a method to be able to get the test status from a test runner... this is a workaround at best, but still kind of sloppy imo – zmorris Mar 03 '21 at 14:43