diff --git a/tasks/baseline.sh b/tasks/baseline.sh index 7b757d058bb..d363645abc8 100755 --- a/tasks/baseline.sh +++ b/tasks/baseline.sh @@ -14,7 +14,7 @@ CMD=( "cp -f test/image/index.html ../server_app/index.html &&" "supervisorctl restart nw1 &&" "wget --server-response --spider --tries=10 --retry-connrefused http://localhost:9010/ping &&" - "node test/image/make_baseline.js $1" + "node test/image/make_baseline.js $@" ) docker exec -i $CONTAINER_NAME /bin/bash -c "${CMD[*]}" diff --git a/tasks/pretest.js b/tasks/pretest.js index b15d6598b97..89c0221820f 100644 --- a/tasks/pretest.js +++ b/tasks/pretest.js @@ -36,3 +36,11 @@ var setPlotConfig = [ fs.writeFile(constants.pathToSetPlotConfig, setPlotConfig, function(err) { if(err) throw err; }); + +// make artifact folders for image tests +if(!fs.existsSync(constants.pathToTestImagesDiff)) { + fs.mkdirSync(constants.pathToTestImagesDiff); +} +if(!fs.existsSync(constants.pathToTestImages)) { + fs.mkdirSync(constants.pathToTestImages); +} diff --git a/tasks/test_export.sh b/tasks/test_export.sh index 2936c0126d3..5ab443fb0ac 100755 --- a/tasks/test_export.sh +++ b/tasks/test_export.sh @@ -14,7 +14,7 @@ CMD=( "cp -f test/image/index.html ../server_app/index.html &&" "supervisorctl restart nw1 && " "wget --server-response --spider --tries=10 --retry-connrefused http://localhost:9010/ping &&" - "node test/image/export_test.js $1" + "node test/image/export_test.js $@" ) docker exec -i $CONTAINER_NAME /bin/bash -c "${CMD[*]}" diff --git a/tasks/test_image.sh b/tasks/test_image.sh index 4cbb0aa2d78..951c5c680a9 100755 --- a/tasks/test_image.sh +++ b/tasks/test_image.sh @@ -14,7 +14,7 @@ CMD=( "cp -f test/image/index.html ../server_app/index.html &&" "supervisorctl restart nw1 && " "wget --server-response --spider --tries=10 --retry-connrefused http://localhost:9010/ping &&" - "node test/image/compare_pixels_test.js $1" + "node test/image/compare_pixels_test.js $@" ) docker exec -i $CONTAINER_NAME /bin/bash -c "${CMD[*]}" diff --git a/tasks/util/get_image_request_options.js b/tasks/util/get_image_request_options.js deleted file mode 100644 index 00e1f891a38..00000000000 --- a/tasks/util/get_image_request_options.js +++ /dev/null @@ -1,16 +0,0 @@ -/* - * For image testing - * - * Give it a json object for the body, - * it'll return an options object ready for request(). - */ -module.exports = function getOptions(body, url) { - var opts = { - url: url || 'http://localhost:9010/', - method: 'POST' - }; - - if(body) opts.body = JSON.stringify(body); - - return opts; -}; diff --git a/test/image/README.md b/test/image/README.md index 59c2278cc09..7fa5b7881f3 100644 --- a/test/image/README.md +++ b/test/image/README.md @@ -26,7 +26,7 @@ the above evaluates the output of `docker-machine env default`. ### Step 1: Run the testing container -Plotly.js uses `docker-compose` to ease the creation/stopping/deletion of the testing docker container. +We use `docker-compose` to ease the creation/stopping/deletion of the testing docker container. Inside your `plotly.js` directory, run @@ -40,25 +40,86 @@ as listed on [hub.docker.com](https://hub.docker.com/r/plotly/testbed/tags/) and ### Step 2: Run the image tests -Inside your `plotly.js` directory, run +The image testing docker container allows plotly.js developers to ([A](#a-run-image-comparison-tests) run image +comparison tests, ([B](#b-run-image-export-tests) run image export tests and ([C](#c-generate-or-update-existing-baseline-image)) generate baseline +images. + +**IMPORTANT:** the image tests scripts do **not** bundle the source files before +running the image tests. We recommend running `npm run watch` or `npm start` in +a separate tab to ensure that the most up-to-date code is used. + +##### A: Run image comparison tests + +Image comparison tests take in plotly.js mock json files (found in +[`test/image/mocks`][mocks]), generate test png images (saved in +`build/test_images/` - which is git-ignored) and compare them pixel-by-pixel to +their corresponding baseline images (found in +[`test/image/baselines`][baselines]) using +[`GraphicsMagick`](https://github.com/aheckmann/gm). + +To run the image comparison tests, in your `plotly.js` directory: ```bash npm run test-image ``` -if some tests fail, compare their outputs using `npm run start-image_viewer`. +which runs all image comparison tests in batch. If some tests fail, compare their outputs +by booting up the test image viewer using `npm run start-image_viewer`. -**IMPORTANT:** `npm run test-image` does **not** bundle the source files before running the image tests. We recommend runnnig `npm run watch` or `npm run start-test_dashboard` in a separate tab to ensure that the most up-to-date code is tested. +As an alternative to running all image comparison tests at once, you can provide +a [glob](https://github.com/isaacs/node-glob) as argument to target one or multiple test mocks found in +[`test/image/mocks`][mocks]. +For example, -### Step 2b: Make a new or update an existing baseline image +```bash +# Run one test (e.g. the 'contour_nolines' test): +$ npm run test-image -- contour_nolines -Inside your `plotly.js` directory, run +# Run all gl3d image test in batch: +$ npm run test-image -- gl3d_* +``` + +Developers on weak hardware might encounter batch timeout issue. These are most +common when generated WebGL-based graphs. In this case, running the image +comparison tests in queue (i.e. with no concurrency) is recommended: ```bash -npm run baseline -- mock.json +# Run all gl3d image test in queue: +$ npm run test-image -- gl3d_* --queue +``` + +##### B: Run image export tests + +Image export tests check that image export works for formats other than png. + +To run the image export tests, in your `plotly.js` directory: + +```bash +npm run test-export + +# or +npm run test-export -- +``` + +##### C: Generate or update existing baseline image + +To generate a new baseline image, add a new mock file in +[`test/image/mocks`][mocks]. Note that mock file needs to be a valid JSON and +have both a "data" and a `"layout"` field. Then, in your plotly.js directory, +run: + +```bash +npm run baseline -- +``` + +which generates a baseline png image in [`test/image/baselines`][baselines]. + +To update existing baseline image(s), run + +```bash +npm run basline -- ``` -where `mock.json` is the name of a `{"data": [], "layout": {}}` json file found in [`test/image/mocks/`](https://github.com/plotly/plotly.js/tree/master/test/image/mocks). The `"data"` and `"layout"` field are passed to `Plotly.plot` to produce an image saved in [`test/image/baslines`](https://github.com/plotly/plotly.js/tree/master/test/image/baselines). ### Step 3: Stop your testing container @@ -74,7 +135,7 @@ Mac and Windows user should also kill their docker-machine (named `default`) onc docker-machine kill default ``` -### Docker tricks +### Docker tricks ##### SSH into docker container @@ -145,3 +206,6 @@ docker-machine kill default ``` For more comprehensive information about docker, please refer to the [docker docs](http://docs.docker.com/). + +[mocks]: https://github.com/plotly/plotly.js/tree/master/test/image/mocks +[baselines]: https://github.com/plotly/plotly.js/tree/master/test/image/baselines diff --git a/test/image/assets/get_image_paths.js b/test/image/assets/get_image_paths.js new file mode 100644 index 00000000000..6883d261c83 --- /dev/null +++ b/test/image/assets/get_image_paths.js @@ -0,0 +1,29 @@ +var path = require('path'); +var constants = require('../../../tasks/util/constants'); + +var DEFAULT_FORMAT = 'png'; + + +/** + * Return paths to baseline, test-image and diff images for a given mock name. + * + * @param {string} mockName + * @param {string} format + * @return {object} + * baseline + * test + * diff + */ +module.exports = function getImagePaths(mockName, format) { + format = format || DEFAULT_FORMAT; + + return { + baseline: join(constants.pathToTestImageBaselines, mockName, format), + test: join(constants.pathToTestImages, mockName, format), + diff: join(constants.pathToTestImagesDiff, mockName, format) + }; +}; + +function join(basePath, mockName, format) { + return path.join(basePath, mockName) + '.' + format; +} diff --git a/test/image/assets/get_image_request_options.js b/test/image/assets/get_image_request_options.js new file mode 100644 index 00000000000..a7d2ad5bda8 --- /dev/null +++ b/test/image/assets/get_image_request_options.js @@ -0,0 +1,32 @@ +var path = require('path'); +var constants = require('../../../tasks/util/constants'); + +var DEFAULT_URL = 'http://localhost:9010/'; +var DEFAULT_FORMAT = 'png'; +var DEFAULT_SCALE = 1; + +/** + * Return the image server request options for a given mock (and specs) + * + * @param {object} specs + * mockName : name of json mock to plot + * format (optional): format of generated image + * scale (optional): scale of generated image + * url (optional): URL of image server + */ +module.exports = function getRequestOpts(specs) { + var pathToMock = path.join(constants.pathToTestImageMocks, specs.mockName) + '.json'; + var figure = require(pathToMock); + + var body = { + figure: figure, + format: specs.format || DEFAULT_FORMAT, + scale: specs.scale || DEFAULT_SCALE + }; + + return { + method: 'POST', + url: specs.url || DEFAULT_URL, + body: JSON.stringify(body) + }; +}; diff --git a/test/image/assets/get_mock_list.js b/test/image/assets/get_mock_list.js new file mode 100644 index 00000000000..e0f4b39a147 --- /dev/null +++ b/test/image/assets/get_mock_list.js @@ -0,0 +1,29 @@ +var path = require('path'); +var glob = require('glob'); + +var constants = require('../../../tasks/util/constants'); + + +/** + * Return array of mock name corresponding to input glob pattern + * + * @param {string} pattern + * @return {array} + */ +module.exports = function getMocks(pattern) { + // defaults to 'all' + pattern = pattern || '*'; + + // defaults to '.json' ext is none is provided + if(path.extname(pattern) === '') pattern += '.json'; + + var patternFull = constants.pathToTestImageMocks + '/' + pattern; + var matches = glob.sync(patternFull); + + // return only the mock name (not a full path, no ext) + var mockNames = matches.map(function(match) { + return path.basename(match).split('.')[0]; + }); + + return mockNames; +}; diff --git a/test/image/compare_pixels_test.js b/test/image/compare_pixels_test.js index 9388a659dd6..1335843011a 100644 --- a/test/image/compare_pixels_test.js +++ b/test/image/compare_pixels_test.js @@ -1,109 +1,154 @@ var fs = require('fs'); -var path = require('path'); -var constants = require('../../tasks/util/constants'); -var getOptions = require('../../tasks/util/get_image_request_options'); +var getMockList = require('./assets/get_mock_list'); +var getRequestOpts = require('./assets/get_image_request_options'); +var getImagePaths = require('./assets/get_image_paths'); // packages inside the image server docker -var request = require('request'); var test = require('tape'); +var request = require('request'); var gm = require('gm'); -var TOLERANCE = 1e-6; // pixel comparison tolerance -var BASE_TIMEOUT = 500; // base timeout time -var BATCH_SIZE = 5; // size of each test 'batch' -var running = 0; // number of tests currently running +// pixel comparison tolerance +var TOLERANCE = 1e-6; + +// wait time between each test batch +var BATCH_WAIT = 500; + +// number of tests in each test batch +var BATCH_SIZE = 5; + +// wait time between each test in test queue +var QUEUE_WAIT = 10; + +/** + * Image pixel comparison test script. + * + * Called by `tasks/test_image.sh in `npm run test-image`. + * + * CLI arguments: + * + * 1. 'pattern' : glob determining which mock(s) are to be tested + * 2. --queue : if sent, the image will be run in queue instead of in batch. + * Makes the test run significantly longer, but is recommended on weak hardware. + * + * Examples: + * + * Run all tests in batch: + * + * npm run test-image + * + * Run the 'contour_nolines' test: + * + * npm run test-image -- contour_nolines + * + * Run all gl3d image test in queue: + * + * npm run test-image -- gl3d_* --queue + */ + +var pattern = process.argv[2]; +var mockList = getMockList(pattern); +var isInQueue = (process.argv[3] === '--queue'); + +if(mockList.length === 0) { + throw new Error('No mocks found with pattern ' + pattern); +} -var touch = function(fileName) { - fs.closeSync(fs.openSync(fileName, 'w')); -}; +mockList = mockList.filter(untestableFilter); +if(mockList.length === 0) { + throw new Error('All mocks found with pattern ' + pattern + ' are currently untestable'); +} -// make artifact folders -if(!fs.existsSync(constants.pathToTestImagesDiff)) { - fs.mkdirSync(constants.pathToTestImagesDiff); +// main +if(isInQueue) { + runInQueue(mockList); } -if(!fs.existsSync(constants.pathToTestImages)) { - fs.mkdirSync(constants.pathToTestImages); +else { + runInBatch(mockList); } -var userFileName = process.argv[2]; +/* Test cases: + * + * - font-wishlist + * - all gl2d + * - all mapbox + * + * don't behave consistently from run-to-run and/or + * machine-to-machine; skip over them for now. + * + */ +function untestableFilter(mockName) { + return !( + mockName === 'font-wishlist' || + mockName.indexOf('gl2d_') !== -1 || + mockName.indexOf('mapbox_') !== -1 + ); +} -// run the test(s) -if(!userFileName) runAll(); -else runSingle(userFileName); +function runInBatch(mockList) { + var running = 0; -function runAll() { - test('testing mocks', function(t) { + // remove mapbox mocks if circle ci - var fileNames = fs.readdirSync(constants.pathToTestImageMocks); + test('testing mocks in batch', function(t) { + t.plan(mockList.length); - // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var allMocks = fileNames.filter(function(name) {return name.slice(-5) === '.json';}); + for(var i = 0; i < mockList.length; i++) { + run(mockList[i], t); + } + }); - /* Test cases: - * - * - font-wishlist - * - all gl2d - * - * don't behave consistently from run-to-run and/or - * machine-to-machine; skip over them. - * - */ - var mocks = allMocks.filter(function(mock) { - return !( - mock === 'font-wishlist.json' || - mock.indexOf('gl2d') !== -1 - ); - }); + function run(mockName, t) { + if(running >= BATCH_SIZE) { + setTimeout(function() { + run(mockName, t); + }, BATCH_WAIT); + return; + } + running++; - // skip mapbox mocks for now - mocks = mocks.filter(function(mock) { - return mock.indexOf('mapbox_') === -1; + // throttle the number of tests running concurrently + + comparePixels(mockName, function(isEqual, mockName) { + running--; + t.ok(isEqual, mockName + ' should be pixel perfect'); }); + } +} - t.plan(mocks.length); +function runInQueue(mockList) { + var index = 0; - for(var i = 0; i < mocks.length; i++) { - testMock(mocks[i], t); - } + test('testing mocks in queue', function(t) { + t.plan(mockList.length); + run(mockList[index], t); }); -} -function runSingle(userFileName) { - test('testing single mock: ' + userFileName, function(t) { - t.plan(1); - testMock(userFileName, t); - }); -} + function run(mockName, t) { + comparePixels(mockName, function(isEqual, mockName) { + t.ok(isEqual, mockName + ' should be pixel perfect'); -function testMock(fileName, t) { - // throttle the number of tests running concurrently - if(running >= BATCH_SIZE) { - setTimeout(function() { testMock(fileName, t); }, BASE_TIMEOUT); - return; + index++; + if(index < mockList.length) { + setTimeout(function() { + run(mockList[index], t); + }, QUEUE_WAIT); + } + }); } - running++; - - var figure = require(path.join(constants.pathToTestImageMocks, fileName)); - var bodyMock = { - figure: figure, - format: 'png', - scale: 1 - }; +} - var imageFileName = fileName.split('.')[0] + '.png'; - var savedImagePath = path.join(constants.pathToTestImages, imageFileName); - var diffPath = path.join(constants.pathToTestImagesDiff, 'diff-' + imageFileName); - var savedImageStream = fs.createWriteStream(savedImagePath); - var options = getOptions(bodyMock, 'http://localhost:9010/'); +function comparePixels(mockName, cb) { + var requestOpts = getRequestOpts({ mockName: mockName }), + imagePaths = getImagePaths(mockName), + saveImageStream = fs.createWriteStream(imagePaths.test); function checkImage() { - running--; - - var options = { - file: diffPath, + var gmOpts = { + file: imagePaths.diff, highlightColor: 'purple', tolerance: TOLERANCE }; @@ -125,26 +170,30 @@ function testMock(fileName, t) { */ gm.compare( - savedImagePath, - path.join(constants.pathToTestImageBaselines, imageFileName), - options, + imagePaths.test, + imagePaths.baseline, + gmOpts, onEqualityCheck ); } function onEqualityCheck(err, isEqual) { if(err) { - touch(diffPath); - return console.error(err, imageFileName); + touch(imagePaths.diff); + return console.error(err, mockName); } if(isEqual) { - fs.unlinkSync(diffPath); + fs.unlinkSync(imagePaths.diff); } - t.ok(isEqual, imageFileName + ' should be pixel perfect'); + cb(isEqual, mockName); } - request(options) - .pipe(savedImageStream) + request(requestOpts) + .pipe(saveImageStream) .on('close', checkImage); } + +function touch(filePath) { + fs.closeSync(fs.openSync(filePath, 'w')); +} diff --git a/test/image/export_test.js b/test/image/export_test.js index de3d4726a7e..71bd767fe4c 100644 --- a/test/image/export_test.js +++ b/test/image/export_test.js @@ -1,106 +1,89 @@ var fs = require('fs'); -var path = require('path'); +var getMockList = require('./assets/get_mock_list'); +var getRequestOpts = require('./assets/get_image_request_options'); +var getImagePaths = require('./assets/get_image_paths'); + +// packages inside the image server docker var request = require('request'); var test = require('tape'); -var constants = require('../../tasks/util/constants'); -var getOptions = require('../../tasks/util/get_image_request_options'); +// image formats to test +// N.B. 'png' is tested in `npm run test-image, no need to duplicate here +// TODO figure why 'jpeg' and 'webp' lead to errors +var FORMATS = ['svg', 'pdf', 'eps']; + +// non-exhaustive list of mocks to test +var DEFAULT_LIST = ['0', 'geo_first', 'gl3d_z-range', 'text_export']; -var userFileName = process.argv[2]; +// minimum satisfactory file size +var MIN_SIZE = 100; /** - * Image formats to test + * Image export test script. * - * N.B. 'png' is tested in `compare_pixels_test.js` + * Called by `tasks/test_export.sh in `npm run test-export`. * - * TODO figure why 'jpeg' and 'webp' lead to errors + * CLI arguments: * - */ -var FORMATS = ['svg', 'pdf', 'eps']; - -/** - * The tests below determine whether the images are properly - * exported by (only) checking the file size of the generated images. + * 1. 'pattern' : glob determining which mock(s) are to be tested * - * MIN_SIZE is the minimum satisfactory file size. + * Examples: + * + * Run the export test on the default mock list (in batch): + * + * npm run test-image + * + * Run the export on the 'contour_nolines' mock: + * + * npm run test-image -- contour_nolines + * + * Run the export test on all gl3d mocks (in batch): + * + * npm run test-image -- gl3d_* */ -var MIN_SIZE = 100; +var pattern = process.argv[2]; +var mockList = pattern ? getMockList(pattern) : DEFAULT_LIST; -// make artifact folder -if(!fs.existsSync(constants.pathToTestImages)) { - fs.mkdirSync(constants.pathToTestImages); +if(mockList.length === 0) { + throw new Error('No mocks found with pattern ' + pattern); } -if(!userFileName) runAll(); -else { +// main +runInBatch(mockList); - if(path.extname(userFileName) !== '.json') { - throw new Error('user-specified mock must end with \'.json\''); - } - - runSingle(userFileName); -} - -function runAll() { - test('testing export formats', function(t) { +function runInBatch(mockList) { + test('testing image export formats', function(t) { + t.plan(mockList.length * FORMATS.length); - // non-exhaustive list of mocks to test - var fileNames = [ - '0.json', - 'geo_first.json', - 'gl3d_z-range.json', - 'text_export.json' - ]; - - t.plan(fileNames.length * FORMATS.length); - - fileNames.forEach(function(fileName) { - testExports(fileName, t); + // send all requests out at once + mockList.forEach(function(mockName) { + FORMATS.forEach(function(format) { + testExport(mockName, format, t); + }); }); }); } -function runSingle(userFileName) { - test('testing export for: ' + userFileName, function(t) { - t.plan(FORMATS.length); - - testExports(userFileName, t); - }); -} - -function testExports(fileName, t) { - FORMATS.forEach(function(format) { - testExport(fileName, format, t); - }); -} - -function testExport(fileName, format, t) { - var figure = require(path.join(constants.pathToTestImageMocks, fileName)); - var bodyMock = { - figure: figure, - format: format, - scale: 1 - }; - - var imageFileName = fileName.split('.')[0] + '.' + format; - var savedImagePath = path.join(constants.pathToTestImages, imageFileName); - var savedImageStream = fs.createWriteStream(savedImagePath); - - var options = getOptions(bodyMock, 'http://localhost:9010/'); +// The tests below determine whether the images are properly +// exported by (only) checking the file size of the generated images. +function testExport(mockName, format, t) { + var requestOpts = getRequestOpts({ mockName: mockName, format: format }), + imagePaths = getImagePaths(mockName, format), + saveImageStream = fs.createWriteStream(imagePaths.test); function checkExport(err) { if(err) throw err; - fs.stat(savedImagePath, function(err, stats) { + fs.stat(imagePaths.test, function(err, stats) { var didExport = stats.size > MIN_SIZE; - t.ok(didExport, imageFileName + ' should be properly exported'); + t.ok(didExport, mockName + ' should be properly exported as a ' + format); }); } - request(options) - .pipe(savedImageStream) + request(requestOpts) + .pipe(saveImageStream) .on('close', checkExport); } diff --git a/test/image/make_baseline.js b/test/image/make_baseline.js index 0eb4ae0e9c1..fea40dfc082 100644 --- a/test/image/make_baseline.js +++ b/test/image/make_baseline.js @@ -1,56 +1,81 @@ var fs = require('fs'); -var path = require('path'); -var constants = require('../../tasks/util/constants'); -var getOptions = require('../../tasks/util/get_image_request_options'); +var getMockList = require('./assets/get_mock_list'); +var getRequestOpts = require('./assets/get_image_request_options'); +var getImagePaths = require('./assets/get_image_paths'); // packages inside the image server docker -var ProgressBar = require('progress'); var request = require('request'); -var userFileName = process.argv[2]; -var bar; +// wait time between each baseline generation +var QUEUE_WAIT = 10; +/** + * Baseline image generation script. + * + * Called by `tasks/baseline.sh in `npm run baseline`. + * + * CLI arguments: + * + * 1. 'pattern' : glob determining the baseline(s) to be generated + * + * Examples: + * + * Generate or (re-generate) all baselines (in queue): + * + * npm run baseline + * + * Generate or (re-generate) the 'contour_nolines' baseline: + * + * npm run baseline -- contour_nolines + * + * Generate or (re-generate) all gl3d baseline (in queue): + * + * npm run baseline -- gl3d_* + * + */ +var pattern = process.argv[2]; +var mockList = getMockList(pattern); -if(!userFileName) { - fs.readdir(constants.pathToTestImageMocks, function(err, files) { - console.log('####### ' + files.length + ' total baseline images to build #######'); - bar = new ProgressBar('processing [:bar] [:current / :total]', { total: files.length, width: 30 }); - if(err) return console.log(err); - files.forEach(createBaselineImage); - }); -} -else { - createBaselineImage(userFileName); +if(mockList.length === 0) { + throw new Error('No mocks found with pattern ' + pattern); } +// main +runInQueue(mockList); -function createBaselineImage(fileName) { - if(path.extname(fileName) !== '.json') return; +function runInQueue(mockList) { + var index = 0; - var figure = require(path.join(constants.pathToTestImageMocks, fileName)); - var bodyMock = { - figure: figure, - format: 'png', - scale: 1 - }; + run(mockList[index]); - var imageFileName = fileName.split('.')[0] + '.png'; - var savedImagePath = path.join(constants.pathToTestImageBaselines, imageFileName); - var savedImageStream = fs.createWriteStream(savedImagePath); - var options = getOptions(bodyMock, 'http://localhost:9010/'); + function run(mockName) { + makeBaseline(mockName, function() { + console.log('generated ' + mockName + ' successfully'); - function checkFormat(err, res) { - if(err) console.log(err); - if(res.headers['content-type'] !== 'image/png') console.log(res.statusCode); + index++; + if(index < mockList.length) { + setTimeout(function() { + run(mockList[index]); + }, QUEUE_WAIT); + } + }); } +} - function onClose() { - if(bar) bar.tick(); - if(userFileName) console.log('generated : ' + imageFileName + ' successfully'); +function makeBaseline(mockName, cb) { + var requestOpts = getRequestOpts({ mockName: mockName }), + imagePaths = getImagePaths(mockName), + saveImageStream = fs.createWriteStream(imagePaths.baseline); + + function checkFormat(err, res) { + if(err) throw err; + if(res.headers['content-type'] !== 'image/png') { + throw new Error('Generated image is not a valid png'); + } } - request(options, checkFormat) - .pipe(savedImageStream) - .on('close', onClose); + request(requestOpts, checkFormat) + .pipe(saveImageStream) + .on('close', cb); }