Friday, August 18Be an Automation Engineer

Take screenshot for every failed spec in protractor+jasmine

Why we need screenshots?

Generally we need screenshot of the browser where the protractor got failed. It would increase our chances to quickly figure out the issue before getting into the code debug. 

How to take a screen shot in protractor?

Below is the code to take a screenshot using protractor.

browser.takeScreenshot().then(function (png) {
       var dirPath = './reports/screenshots/';
       if (!fs.existsSync('./reports')) {
           fs.mkdirSync('./reports');
           if (!fs.existsSync(dirPath))
               fs.mkdirSync(dirPath);
       }
       var stream = fs.createWriteStream(dirPath + 'Failed_spec_screenshot.png');
       stream.write(new Buffer(png, 'base64'));
             stream.end();
       }, function (error) {
             console.log("failed to take screenshot");
}
Confusion: You might have already got a doubt that where do we need to put this code in our framework. Clarity: It depends on the unit test framework that we are using(Ex: jasmine, mocha, cucumber etc..) and your need whether to take screen shot for every spec irrespective of it’s result or to capture for only failed specs.

Now, without any delay lets jump onto the coding part.

What I am explaining here?

Here i am going to explain it with Jasmine and for failed specs why because taking screenshot for failed specs is needed and mostly used case.

Note: Here i am not going to explain about identifying failed specs in jasmine. I will write one more post for to explain that.

I am giving sample programs in typescript. If you are new to protractor with typescript. See my detailed example here.

In jasmine we need to add a custom reporter and write our capturing screen shot code in there when spec got failed. We can add a custom reporter as follows.

import { browser } from 'protractor';
import fs = require('fs');
declare var module: NodeModule;

var myReporter = {
    specDone: function (result) {
        if (result.failedExpectations.length > 0) {
            browser.getProcessedConfig().then(function (config) {
                browser.takeScreenshot().then(function (png) {
                    var dirPath = './reports/screenshots/';
                    if (!fs.existsSync('./reports')) {
                        fs.mkdirSync('./reports');
                        if (!fs.existsSync(dirPath))
                            fs.mkdirSync(dirPath);
                    }
                    var fileName = (config.capabilities.browserName + '-' + result.fullName).replace(/[\/\\]/g, ' ').substring(0, 230);
                    var stream = fs.createWriteStream(dirPath + fileName + '.png');
                    stream.write(new Buffer(png, 'base64'));
                    stream.end();
                }, function (error) {
                    console.log("failed to take screenshot");
                })
            })
        }
    }
}
module.exports = myReporter;
Add the jasmine custom reporter to protractor config file

Now, we need to use the above written custom reporter in config file.

import myReporter = ('jasmine_reporter');
jasmine.getEnv().addReporter(myReporter)

Our whole config file would look like below.

import { ProtractorBrowser, Config } from 'protractor';
import reporter = require('jasmine_reporter');
export let config: Config = {
    //seleniumAddress: 'http://localhost:4444/wd/hub',
    capabilities: {
        'directConnect': true,
        'browserName': 'chrome'
    },
    framework: 'jasmine',
    specs: ['./specs/**/*.js'],
    jasmineNodeOpts: {
        defaultTimeoutInterval: 90000
    },
    onPrepare: () => {
        let globals = require('protractor');
        jasmine.getEnv().addReporter(reporter);
        let browser = globals.browser;
        browser.manage().window().maximize();
        browser.manage().timeouts().implicitlyWait(5000);
    }
}

Now, our config file is also ready for taking screenshots.

Write a sample protractor failing spec:

Below is the sample program.

import { ElementFinder, browser, by, element } from 'protractor';
describe('Screenshots', function () {
    it('Failing spec', function () {
        browser.get('http://angularjs.org');
        element.all(by.tagName('a')).count().then(function (count) { expect(count).toEqual(0); });
    });
});

The above spec has a failing expectation. So the test would definitely fail and a screenshot would be captured.

Lets Run:

Note:I assume that you have followed my example mentioned above to know about protractor with typescript.

Execute the below command to run the tests.

npm test

The spec would run and fail because of the count mismatch in the spec. Now you can see a screen shot in 'reports/screenshots/' folder.

Happy Testing!!!

%d bloggers like this: