Nightwatch: Enhancement: Screenshot of particular element?

Created on 6 Jul 2015  路  6Comments  路  Source: nightwatchjs/nightwatch

It would be nice to be able to take a screenshot of a particular element instead of the entire page.

  • Could do this by taking the screenshot of page, then cropping the particular element.

If this is something that can already be done please let me know!

Thank you!!

Most helpful comment

FYI; I was able to accomplish this by doing a few things.
1: Added the library: png-crop to my project.
2: Hacked some code together that looked something like:

require png = require('png-crop');

module.exports = {
  'Screenshot Test': function(browser) {
    browser.element('css selector', '#myElement', function(element) {
      browser.elementIdLocationInView(element.value.ELEMENT, function(location) {
        browser.elementIdSize(element.value.ELEMENT, function(size) {
          browser.saveScreenshot('screenshots/test.png', function() {
             var config = {
                              width: size.value.width*2, //needed 2x due to monitor resolution
                              height: size.value.height*2, //needed 2x due to monitor resolution
                              top: location.value.y*2, //needed 2x due to monitor resolution
                              left: location.value.x*2 //needed 2x due to monitor resolution
             };

             png.crop(
                                'screenshots/test.png',
                                'screenshots/test_cropped.png',
                                config,
                                function(err) {
                                  console.log(err);
                                }
             );
          });
        });
      });
    }
}

Working on making it a bit cleaner now; but thought i'd at least share incase someone else was working through something similar.

All 6 comments

FYI; I was able to accomplish this by doing a few things.
1: Added the library: png-crop to my project.
2: Hacked some code together that looked something like:

require png = require('png-crop');

module.exports = {
  'Screenshot Test': function(browser) {
    browser.element('css selector', '#myElement', function(element) {
      browser.elementIdLocationInView(element.value.ELEMENT, function(location) {
        browser.elementIdSize(element.value.ELEMENT, function(size) {
          browser.saveScreenshot('screenshots/test.png', function() {
             var config = {
                              width: size.value.width*2, //needed 2x due to monitor resolution
                              height: size.value.height*2, //needed 2x due to monitor resolution
                              top: location.value.y*2, //needed 2x due to monitor resolution
                              left: location.value.x*2 //needed 2x due to monitor resolution
             };

             png.crop(
                                'screenshots/test.png',
                                'screenshots/test_cropped.png',
                                config,
                                function(err) {
                                  console.log(err);
                                }
             );
          });
        });
      });
    }
}

Working on making it a bit cleaner now; but thought i'd at least share incase someone else was working through something similar.

Thanks for sharing but this is not likely to be incorporated into nightwatch soon.

Hi @beatfactor any plan on adding this feature?

@petrogad have you try to make it a extended nightwatch command ?

Hi,
Am I right in saying that this feature is now part of webdriver spec: https://www.w3.org/TR/webdriver/#take-element-screenshot ?
Therefore should be being rolled out into browser driver implementations.

If so could we reopen this issue to incorporate it into nightwatch? Or rather make use of the new endpoint

Here Our version of partial screenshot, who throw error when selector fail or crop fail
this code make the path for files if it's don't exist.
feel free to comment and propose inprovement
We didn't double the pixel size because that not nessesary in circleci machine

const png = require('png-crop');
const fs = require('fs');
const util = require('util');
const events = require('events');
const mkdirp = require('mkdirp');

function partialScreenshot() {
  events.EventEmitter.call(this);
}

function makeDirForPath(baselinePath) {
  const baseDir = baselinePath.substring(0, baselinePath.lastIndexOf('/'));
  mkdirp.sync(baseDir);
}

util.inherits(partialScreenshot, events.EventEmitter);

partialScreenshot.prototype.command = function (selector, filename, callback) {
  this.abortOnFailure = typeof this.client.api.globals.abortOnAssertionFailure === 'undefined' || this.client.api.globals.abortOnAssertionFailure;
  const self = this;
  const pathToSave = filename;
  const pathTmp = `temp/${filename}`;
  // #TODO ignore hidden part of element
  self.locateStrategy = self.client.locateStrategy || 'css selector';
  self.api.element(self.locateStrategy, selector, (element) => {
    if (element && !element.error) {
      self.api.elementIdLocationInView(element.value.ELEMENT, (location) => {
        self.api.elementIdSize(element.value.ELEMENT, (size) => {
          self.api.saveScreenshot(pathTmp, () => {
            makeDirForPath(pathToSave);
            const config = {
              width: size.value.width,
              height: size.value.height,
              top: location.value.y,
              left: location.value.x,
            };
            png.crop(
              pathTmp,
              pathToSave,
              config,
              (err) => {
                if (err) {
                  self.client.assertion(false, 'not found', 'found', `SaveElementScreenshotAction: could not crop: ${pathToSave} ${err}`, self.abortOnFailure, self._stackTrace);
                  return self.emit('complete');
                }
                fs.unlink(pathTmp, (res) => {
                  const message = `Saved screenshot for <${selector}> to ${pathToSave}`;
                  self.client.assertion(true, 'expression false', 'expression true', message, true);
                  self.emit('complete');
                  if (typeof callback === 'function') {
                    callback.call(self.client.api);
                  }
                });
              });
          });
        });
      });
    } else {
      self.client.assertion(false, 'not found', 'found', `SaveElementScreenshotAction: could not select <${selector}> because ${element.error}`, self.abortOnFailure, self._stackTrace);
      return self.emit('complete');
    }
  });

  return this;
};

module.exports = partialScreenshot;
Was this page helpful?
0 / 5 - 0 ratings