How do I take a screenshot when a test in internjs fails?

安稳与你 提交于 2020-01-13 07:11:28

问题


I am having issues figuring out how to take a screenshot ONLY when a test fails in InternJs. I have this simple test in my registerSuite;

'verify google homepage': function () {
    var url = 'https://www.google.com/';
    return this.remote
        .get(url)
        .getCurrentUrl()
        .then(function (data) {
            assert.strictEqual(data, url, 'Incorrect URL');
        })
        .findByName('q')
            .click()
 }

I can simply create a screenshot using the following code;

.takeScreenshot
.then(function (data) {
    fs.writeFileSync('/path/to/some/file', data, 'base64');
)}

I want to only take a screenshot, if the above test fails the assertion or is unable to find the locator.

I looked into the afterEach method, but I can't figure out how to get the status of the last test to apply a conditional.

So my question is, has anyone setup their internjs test to only take screenshots on failures and how was it accomplished?


回答1:


  1. It is not currently possible to interact with the currently executing test from beforeEach or afterEach methods; this capability is coming in the next version of Intern.

  2. Selenium server, by default, provides a screenshot on every Selenium command failure, which is a Buffer object on the error.detail.screen property. If a Selenium command fails, just use this property which already has the screenshot waiting for you.

  3. For assertion failures, you can create a simple promise helper to take a screenshot for you:

function screenshotOnError(callback) {
  return function () {
    try {
      return callback.apply(this, arguments);
    }
    catch (error) {
      return this.remote.takeScreenshot().then(function (buffer) {
        fs.writeFileSync('/path/to/some/file', buffer);
        throw error;
      });
    }
  };
}

// ...

'verify google homepage': function () {
  return this.remote.get(url).getCurrentUrl().then(screenshotOnError(function (actualUrl) {
    assert.strictEqual(actualUrl, url);
  }));
}

If it’s too inconvenient to wrap all your callbacks manually like this, you can also create and use a custom interface for registering your tests that wraps the test functions automatically for you in a similar manner. I’ll leave that as an exercise for the reader.




回答2:


You can use catch method at the end of your chain and use error.detail.screen as suggested by C Snover.

'verify google homepage': function () {
    return this.remote
        .get(require.toUrl('./fixture.html'))
        .findById('operation')
            .click()
            .type('hello, world')
        .end()
        .findById('submit')
            .click()
        .end()
        .catch(function(error){
          fs.writeFileSync('/tmp/screenshot.png', error.detail.screen);
        })
}



回答3:


I've been playing with this today and have managed to get it for an entire suite rather than needing to add the code to every single test which seems quite needless.

var counter = -1,
suite = {
    beforeEach: function () {
        counter++;
    },
    afterEach: function () {
        var currentTest = this.tests[counter];
        if (!currentTest.error) {
            return;
        }
        this.remote
            .takeScreenshot().then(function (buffer) {
                if (!fs.existsSync(path)) {
                    fs.mkdirSync(path);
                }
                fs.writeFileSync('/tmp/' + currentTest.name + '.png', buffer);
            });
    }
};

The annoying thing you will need to do is do this for every test suite rather than "globally" but is much better than doing it for every test.




回答4:


Building on the answer by Hugo Oshiro,

// tests/support/CleanScreenshots.js

define([
  'intern/dojo/node!path',
  'intern/dojo/node!del',
], function(path, del) {

  return new Promise((resolve, reject) => {
    let directory = 'tests/screenshots';
    del(path.join(directory, '**/*'))
      .then(resolve)
      .catch(reject);
  });

});

Then in your intern config:

/* global define */

define([
    'tests/support/CleanScreenshots'
  ], function (CleanScreenshots) {


  return {

    ...

    setup: function () {
      return CleanScreenshots();
    },

    ...

  };
});



回答5:


According to this issue, starting with the Intern 3.0 you can do a custom reporter that take an Screenshots when test fail. So you can centralize it in a simple way, just referencing the custom reporter in your config.js. In my case, what can I just add a reporter array in the config.js with the path to my custom array:

reporters: [
        { id: 'tests/support/ScreenShot' }
],

than I made an custom reporter overriding testFail:

'use strict';

define([
    'intern/dojo/node!fs',
], function(fs) {

    function ScreenShot(config) {
        config = config || {};
    }

    ScreenShot.prototype.testFail = function(test) {
        test.remote.takeScreenshot().then(function(buffer) {

            try {
                fs.writeFileSync('./screenshots/' + test.parent.name.replace(/ /g, '') + '-' +
                    test.name.replace(/ /g, '') + '.png', buffer);

            } catch (err) {
                console.log('Failed to take a screenshot: ' + err);
            }
        });
    };

    return ScreenShot;
});

Pay attention to the relative paths both to reference the custom reporter and the place for screenshots. They all seems to be taken considering where you run intern-runner, not the place the source files are located. For more info about custom reporters go to this page.



来源:https://stackoverflow.com/questions/27850786/how-do-i-take-a-screenshot-when-a-test-in-internjs-fails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!