import fs from 'fs';
import path from 'path';
import callsite from 'callsite';
import test from 'tape';
import Nightmare from 'nightmare';
import Promise from 'bluebird';
import resemble from 'node-resemble';

function dataUrl (raw) {
  return `data:image/png;base64,${raw.toString('base64')}`;
}

function rawData (dataUrl) {
  return dataUrl.split(',')[1];
}

function callerDirname () {
  const stack = callsite();
  const frame = stack[2].getFileName();
  return path.dirname(frame);
}

function doSaveImage (name) {
  return process.env.CANDELA_SAVE_IMAGE && process.env.CANDELA_SAVE_IMAGE.split(',').indexOf(name) > -1;
}

Promise.onPossiblyUnhandledRejection(err => {
  console.log(err);
  throw err;
});

export default function imageTest ({name, url, selector, delay = 0, threshold}) {
  const dirname = callerDirname();

  test(`${name} image test`, t => {
    // TODO: allow options to appear in args.
    let n = Nightmare({
      show: false
    });

    Promise.resolve()
    .then(() => {
      return n.goto(url)
        .wait('body')
        .wait(delay)
        // TODO: allow for a custom evaluate function?
        .evaluate((_selector) => {
          const box = document.querySelector(_selector).getBoundingClientRect();
          return {
            x: box.left,
            y: box.top,
            width: box.width,
            height: box.height
          };
        }, selector);
    })
    .then(rect => n.screenshot(doSaveImage(name) ? path.join(dirname, `${name}.png`) : undefined, rect))
    .then(imageBuf => {
      const refImage = dataUrl(fs.readFileSync(path.join(dirname, `${name}.png`)));
      const image = imageBuf ? dataUrl(imageBuf) : refImage;

      resemble(image)
        .compareTo(refImage)
        .onComplete(analysis => {
          const passed = Number(analysis.misMatchPercentage) < threshold;
          if (!passed) {
            fs.writeFileSync(path.join(dirname, `${name}-test.png`), imageBuf.toString('base64'), 'base64');
            fs.writeFileSync(path.join(dirname, `${name}-diff.png`), rawData(analysis.getImageDataUrl()), 'base64');
          }

          t.ok(passed, `${name} image matches reference image to within ${threshold * 100}%`);

          t.end();
          return n.end().then();
        });
    });
  });
}

@@ -516,22 +516,305 @@
 me) %7B%0A  
-return
+// This function returns true if (1) there is an environment variable set%0A  // called %22CANDELA_SAVE_IMAGE%22, and either (2a) the name of the test appears%0A  // in the value of the variable when treated as a comma separated list of%0A  // strings, or (2b) the variable reads %22all%22.%0A  const go =
  process
@@ -836,16 +836,43 @@
 VE_IMAGE
+;%0A  const mentionsName = go
  && proc
@@ -929,16 +929,119 @@
 ) %3E -1;%0A
+  const doAll = go && process.env.CANDELA_SAVE_IMAGE === 'all';%0A%0A  return go && mentionsName %7C%7C doAll;%0A
 %7D%0A%0APromi

Allow CANDELA_SAVE_IMAGE to be set to "all" to save images for all image tests