17

When one of my Jest tests fails I want to store a screenshot, but only when it fails.

Here is a piece of my test code as an example, the !passed part in the afterEach is not working.

describe('Page', () => {  
  it('should contain Text in the header', async () => {
    // Arrange
    const page = new Page(driver);

    // Act
    await page.open();

    // Assert
    expect(await page.getHeaderText()).toBe('Something');
  });

  afterEach(async () => {
    if (!passed) takeScreenshot();
    await driver.quit();
  });
});

With jasmine I would do something like:

  var passed = jasmine.getEnv().currentSpec.results().passed();

But I cannot find something similar for Jest. Maybe there is another solution like taking a screenshot on each failing expect? I tried a try/catch around the expect, but then the test always passes...

How can I check with Jest if my test failed in the afterEach?

Niels van Reijmersdal
  • 2,038
  • 1
  • 20
  • 36

4 Answers4

7

Store current spec results in Jasmine and access it in afterEach.

@Niels van Reijmersdal is on the right track. However, the downside of taking a screenshot in specDone is that it runs after afterEach, so if there's something in afterEach that, say, navigates back a few screens, the screenshot you end up taking won't be representative of where the error took place. Here's an answer that allows you to take a screenshot immediately after the error occurs.

  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();
      }
    } );
    
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
5

Here is an example how I solved it in my project: (Assuming that afterEach is used only for taking screenshots and not for cleanup and other navigates)

const testIt = (name, action) => {
    test(name, async () => {        
        try {         
            await action()} 
        catch (error) {           
            await screenshots.createScreenshot(page) //take screenshot 
            throw error
        }
    })
  }

describe('Test scenario 1', () => {
   
    testIt('test1 will Pass', async () => {
        expect(true).toBe(true)
    })
        
    testIt('test2 will Fail', async () => {
        expect(true).toBe(false)
    })

    afterEach(async () => {
        //ignored
    })

})

I use jest-html-reporters, and only failed tests will have attachment there (this solution did not require any other configurations). Result:

  • test1 - passed, no screenshot
  • test2 - failed, has screenshot
jwir3
  • 6,019
  • 5
  • 47
  • 92
Larisa
  • 131
  • 2
  • 4
3

Seems the jasmine object can be used in Jest tests, but the currentSpec has been removed in the 2.x version.

I have found an alternative with the use of jasmine custom reports. Just make sure you also move the driver.quit() to the reporter as you might still need the driver after the test.

Here is an simple example for the reporter handling failing tests at the end of the test:

const reporter = {
  specDone: async (result) => {
    if (result.status === 'failed') {
      takeScreenshot(result.description);
    }
    await driver.quit();
  },
};

jasmine.getEnv().addReporter(reporter);

describe('Page', () => {  
  it('should contain Text in the header', async () => {
    // Arrange
    const page = new Page(driver);

    // Act
    await page.open();

    // Assert
    expect(await page.getHeaderText()).toBe('Something');
  });
});
Niels van Reijmersdal
  • 2,038
  • 1
  • 20
  • 36
  • The downside of taking a screenshot in `specDone` is that it runs after `afterEach`, so if there's something in `afterEach` that, say, navigates back a few screens, the screenshot you end up taking won't be representative of the actual error. I'll add an answer that still allows you to do it right after the `test` fails. – Joshua Pinter Jun 24 '20 at 14:19
1

Provided answers to not work anymore, because jest is using jest-circus now, not jasmine. See thread with possible solutions: https://github.com/facebook/jest/issues/5292#issuecomment-1328993445

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/34164615) – Nol4635 Apr 09 '23 at 16:53