UNPKG

grunt-browsersnapsy

Version:

A grunt plugin to take screenshots via BrowserStack.

252 lines (213 loc) 6.81 kB
/* * grunt-browsersnapsy * https://github.com/tdeekens/grunt-browsersnapsy * * Copyright (c) 2014 tdeekens * Licensed under the MIT license. */ 'use strict'; var curl = require('curlrequest'), wget = require('wgetjs'), path = require('path'), mkdirp = require('mkdirp'), BrowserStackTunnel = require('browserstacktunnel-wrapper'); module.exports = function(grunt) { grunt.registerMultiTask('browsersnapsy', 'Take screenshots via BrowserStack.', function() { var options = this.options({ downloadTo: '', tunnel: false, browserstack: {}, waitTime: 0, statusDelay: 10, abort: 50, user: '', token: '' }), apiRoot = 'https://www.browserstack.com/screenshots', initializeTunnel, closeTunnel, tunnel, requestScreenshots, requestStatus, downloadScreenshot, taskStatus = { ready: {}, quantity: 0, processed: 0, done: 0, tries: 0 }, pingStatus, endTask = this.async(); var request = curl.request({ url: apiRoot, headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, user: options.user + ':' + options.token, verbose: true, stderr: true }); initializeTunnel = function(finished) { var isTunnelRequested = ( typeof options.tunnel === 'object' && options.tunnel.key && options.tunnel.hosts.length > 0 ); if (!isTunnelRequested) { finished(); return false; } tunnel = new BrowserStackTunnel(options.tunnel); tunnel.start(function(error) { if (error) { grunt.log.errorlns('Could not create tunnel(s) due to: ' + error + '.'); closeTunnel(); endTask(); } else { grunt.log.ok('Successfully created tunnel(s)!'); finished(); } }); }; closeTunnel = function() { if (tunnel !== undefined) { tunnel.stop(function(error) { if (error) { grunt.log.errorlns('Could not close tunnel(s) due to: ' + error + '.'); } else { grunt.log.ok('Successfully closed tunnel(s)!'); } }); } }; requestScreenshots = function(success) { if (options.browserstack.dry_run === true) { success(); } request({ data: JSON.stringify(options.browserstack) }, function(err, data) { if (err) { grunt.log.error('Screenshots requested failed.'); closeTunnel(); endTask(); } grunt.log.subhead('Requesting screenshots finished.'); success(data); }); }; requestStatus = function(screenshots, success, delay, log) { setTimeout(function() { var jobId = screenshots.job_id || screenshots.id; request({ url: apiRoot + '/' + jobId + ".json" }, function(err, data) { if (err) { grunt.log.error('Can not fetch screenshots\' taskStatus.'); closeTunnel(); endTask(); } if (log !== false) { var response = JSON.parse(data), devices = response.screenshots.map(function(screenshot) { var device = screenshot.device || screenshot.os + ' - ' + screenshot.browser + screenshot.browser_version; var orientation = screenshot.orientation || 'portrait'; return device + ' (' + orientation + ')'; }); grunt.log.ok( 'Requests successfully made for: ' + devices + '.' ); } success(data); }); }, delay || options.waitTime * 1000); }; pingStatus = function(request, log) { if (taskStatus.tries >= options.abort) { grunt.log.errorlns('Aborting, tried ' + options.abort + ' times to get screenshots.'); closeTunnel(); endTask(); } if (log !== false) { grunt.log.ok( 'Pinging status of screenshot requests ' + '(every ' + options.statusDelay + ' secs).' ); } else { grunt.log.write('...'); } request.screenshots.forEach(function(screenshot) { if (taskStatus.ready[screenshot.id] === undefined && screenshot.state === 'done') { taskStatus.processed++; downloadScreenshot(screenshot); } }); if (taskStatus.processed !== taskStatus.quantity) { setTimeout(function() { requestStatus(request, function(data) { taskStatus.tries++; pingStatus(JSON.parse(data), false); }, 0, false); }, options.statusDelay * 1000); } }; downloadScreenshot = function(screenshot) { if (taskStatus.ready[screenshot.id] !== undefined) { return false; } taskStatus.ready[screenshot.id] = screenshot; var device = screenshot.device || screenshot.os + ' - ' + screenshot.browser + screenshot.browser_version; grunt.log.subhead( 'Status of screenshots changed: ' + taskStatus.processed + ' of ' + taskStatus.quantity + ' ready (' + device + ').' ); var generateScreenshotPath = function(screenshot, downloadTo) { var imageUrlArray = screenshot.image_url.split("/"); return path.join(downloadTo, imageUrlArray[5]); }; // Ensure downloadTo exists mkdirp(options.downloadTo, function(err) { wget({ url: screenshot.image_url, dest: generateScreenshotPath(screenshot, options.downloadTo) }, function() { taskStatus.done++; if (taskStatus.done === taskStatus.quantity) { grunt.log.ok('All screenshots downloaded!'); closeTunnel(); endTask(); } }); }); }; initializeTunnel(function() { requestScreenshots(function(data) { try { var screenshotRequest = JSON.parse(data); } catch (exception) { grunt.log.errorlns(data); closeTunnel(); endTask(); return false; } if (screenshotRequest.errors || screenshotRequest.message) { grunt.log.errorlns('BrowserStack request failed due to: ' + screenshotRequest.message || screenshotRequest.errors); closeTunnel(); endTask(); return false; } taskStatus.quantity = screenshotRequest.screenshots.length; requestStatus(screenshotRequest, function(data) { var request = JSON.parse(data); pingStatus(request); }); }); }); }); };