How do I take a screenshot when a test in internjs

2019-04-17 00:56发布

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?

5条回答
放我归山
2楼-- · 2019-04-17 01:27

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.

查看更多
聊天终结者
3楼-- · 2019-04-17 01:35

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

    ...

  };
});
查看更多
倾城 Initia
4楼-- · 2019-04-17 01:48

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.

查看更多
霸刀☆藐视天下
5楼-- · 2019-04-17 01:51
  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.

查看更多
姐就是有狂的资本
6楼-- · 2019-04-17 01:51

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);
        })
}
查看更多
登录 后发表回答