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

情到浓时终转凉″ 提交于 2019-12-04 20:44:31
C Snover
  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.

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);
        })
}

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.

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();
    },

    ...

  };
});

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.

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