mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #510 from subtleGradient/subtlegradient/run-the-browser-tests-on-saucelabs
Make it easy to run the browser tests on saucelabs.
This commit is contained in:
@@ -23,3 +23,4 @@ docs/js/examples
|
||||
docs/downloads
|
||||
examples/shared/*.js
|
||||
test/the-files-to-test.generated.js
|
||||
sauce_connect.log*
|
||||
|
||||
+3
-1
@@ -6,6 +6,7 @@ var browserifyTask = require('./grunt/tasks/browserify');
|
||||
var populistTask = require('./grunt/tasks/populist');
|
||||
var webdriverPhantomJSTask = require('./grunt/tasks/webdriver-phantomjs');
|
||||
var webdriverJasmineTasks = require('./grunt/tasks/webdriver-jasmine');
|
||||
var sauceTunnelTask = require('./grunt/tasks/sauce-tunnel');
|
||||
var npmTask = require('./grunt/tasks/npm');
|
||||
var releaseTasks = require('./grunt/tasks/release');
|
||||
|
||||
@@ -46,6 +47,8 @@ module.exports = function(grunt) {
|
||||
|
||||
grunt.registerMultiTask('populist', populistTask);
|
||||
|
||||
grunt.registerTask('sauce-tunnel', sauceTunnelTask);
|
||||
|
||||
grunt.registerMultiTask('webdriver-jasmine', webdriverJasmineTasks);
|
||||
|
||||
grunt.registerMultiTask('npm', npmTask);
|
||||
@@ -71,7 +74,6 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('build:min', ['jsx:release', 'version-check', 'browserify:min']);
|
||||
grunt.registerTask('build:addons-min', ['jsx:debug', 'browserify:addonsMin']);
|
||||
grunt.registerTask('build:test', [
|
||||
'jsx:jasmine',
|
||||
'jsx:test',
|
||||
'version-check',
|
||||
'populist:test'
|
||||
|
||||
@@ -24,15 +24,6 @@ var debug = {
|
||||
outputDir: "build/modules"
|
||||
};
|
||||
|
||||
var jasmine = {
|
||||
rootIDs: [
|
||||
"all"
|
||||
],
|
||||
getConfig: getDebugConfig,
|
||||
sourceDir: "vendor/jasmine",
|
||||
outputDir: "build/jasmine"
|
||||
};
|
||||
|
||||
var test = {
|
||||
rootIDs: rootIDs.concat([
|
||||
"test/all.js",
|
||||
@@ -71,7 +62,6 @@ var release = {
|
||||
|
||||
module.exports = {
|
||||
debug: debug,
|
||||
jasmine: jasmine,
|
||||
test: test,
|
||||
release: release
|
||||
};
|
||||
|
||||
+18
-22
@@ -1,24 +1,22 @@
|
||||
var pxlgif = Buffer('R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==', 'base64');
|
||||
|
||||
module.exports = function(grunt){
|
||||
|
||||
function printMiddleware(req, res, next) {
|
||||
if (req._parsedUrl.pathname != '/print') return next();
|
||||
if (req.query.message.indexOf('ok') === 0){
|
||||
grunt.log.ok(req.query.message);
|
||||
} else if (req.query.message.indexOf('not ok') === 0){
|
||||
grunt.log.error(req.query.message);
|
||||
} else {
|
||||
grunt[req.query.type || 'log'].writeln('[%s][%s]', req.headers['user-agent'], Date.now(), req.query.message);
|
||||
}
|
||||
res.end(pxlgif);
|
||||
}
|
||||
|
||||
function testResultLoggerMiddleware(req, res, next) {
|
||||
if (!(req.body && req.body.data)) return next();
|
||||
grunt.log.writeln('[%s][%s]', req.headers['user-agent'], Date.now(), req.body.data);
|
||||
if (!(req.method == 'POST' && req._parsedUrl.pathname.indexOf('/reportTestResults') === 0)) return next();
|
||||
var logType = 'writeln';
|
||||
var message = req.body;
|
||||
|
||||
if (req.body.type && req.body.message){
|
||||
if (req.body.type == 'error') logType = 'error';
|
||||
else if (req.body.message.indexOf('ok') === 0) logType = 'ok';
|
||||
else if (req.body.message.indexOf('not ok') === 0) logType = 'error';
|
||||
message = req.body.message;
|
||||
}
|
||||
if (typeof message != 'string') message = JSON.stringify(message, null, 2);
|
||||
grunt.log[logType]('[%s][%s]', req.headers['user-agent'], Date.now(), message);
|
||||
res.write('<!doctype html><meta charset=utf-8>');
|
||||
res.end('Got it, thanks!');
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
server: {
|
||||
options: {
|
||||
@@ -26,17 +24,15 @@ module.exports = function(grunt){
|
||||
hostname: '*',
|
||||
port: 9999,
|
||||
middleware: function(connect, options) {
|
||||
|
||||
connect.logger.token('user-agent', function(req, res){ return req.headers['user-agent']; });
|
||||
connect.logger.token('timestamp', function(req, res){ return Date.now(); });
|
||||
|
||||
return [
|
||||
connect.query(),
|
||||
printMiddleware,
|
||||
|
||||
connect.logger({format:'[:user-agent][:timestamp] :method :url', stream:grunt.verbose}),
|
||||
connect.bodyParser(),
|
||||
connect.json(),
|
||||
testResultLoggerMiddleware,
|
||||
|
||||
connect.logger({format:'[:user-agent][:timestamp] :method :url', stream:grunt.verbose}),
|
||||
connect.static(options.base),
|
||||
connect.directory(options.base)
|
||||
];
|
||||
|
||||
@@ -6,9 +6,8 @@ exports.local = {
|
||||
remote: { protocol: 'http:', hostname: '127.0.0.1', port: 9515, path: '/' }
|
||||
},
|
||||
url: "http://127.0.0.1:9999/test/index.html",
|
||||
onComplete: function(report){
|
||||
var browser = this;
|
||||
if (!report.passed){
|
||||
onComplete: function(passed){
|
||||
if (!passed){
|
||||
grunt.fatal("tests failed");
|
||||
}
|
||||
},
|
||||
@@ -16,3 +15,74 @@ exports.local = {
|
||||
grunt.fatal(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (grunt.option('debug')) exports.local.url += '?debug=' + grunt.option('debug');
|
||||
|
||||
|
||||
exports.saucelabs = {
|
||||
webdriver: {
|
||||
remote: {
|
||||
/* https://github.com/admc/wd/blob/master/README.md#named-parameters */
|
||||
user: process.env.SAUCE_USERNAME,
|
||||
pwd: process.env.SAUCE_ACCESS_KEY,
|
||||
|
||||
protocol: 'http:',
|
||||
hostname: 'ondemand.saucelabs.com',
|
||||
port: '80',
|
||||
path: '/wd/hub'
|
||||
}
|
||||
},
|
||||
desiredCapabilities: {
|
||||
"build": process.env.TRAVIS_BUILD_NUMBER || 'dev' + Date.now(),
|
||||
"tunnel-identifier": process.env.TRAVIS_JOB_NUMBER || 'my awesome tunnel',
|
||||
"browserName": "chrome"
|
||||
},
|
||||
url: exports.local.url,
|
||||
onStart: function(browser){
|
||||
grunt.log.writeln("Starting WebDriver Test. Watch results here: http://saucelabs.com/tests/" + browser.sessionID);
|
||||
},
|
||||
onComplete: exports.local.onComplete,
|
||||
onError: exports.local.onError
|
||||
}
|
||||
|
||||
/* https://saucelabs.com/docs/platforms */
|
||||
exports.saucelabs_ios =
|
||||
exports.saucelabs_ios6_1 = sauceItUp({ browserName: 'iphone', version: '6.1', platform:'OS X 10.8' });
|
||||
exports.saucelabs_ios6 = sauceItUp({ browserName: 'iphone', version: '6', platform:'OS X 10.8' });
|
||||
exports.saucelabs_ios5_1 = sauceItUp({ browserName: 'iphone', version: '5.1', platform:'OS X 10.8' });
|
||||
exports.saucelabs_ios5 = sauceItUp({ browserName: 'iphone', version: '5', platform:'OS X 10.6' });
|
||||
exports.saucelabs_ios4 = sauceItUp({ browserName: 'iphone', version: '4', platform:'OS X 10.6' });
|
||||
|
||||
exports.saucelabs_ipad =
|
||||
exports.saucelabs_ipad6_1 = sauceItUp({ browserName: 'ipad', version: '6.1', platform:'OS X 10.8' });
|
||||
exports.saucelabs_ipad6 = sauceItUp({ browserName: 'ipad', version: '6', platform:'OS X 10.8' });
|
||||
exports.saucelabs_ipad5_1 = sauceItUp({ browserName: 'ipad', version: '5.1', platform:'OS X 10.8' });
|
||||
exports.saucelabs_ipad5 = sauceItUp({ browserName: 'ipad', version: '5', platform:'OS X 10.6' });
|
||||
exports.saucelabs_ipad4 = sauceItUp({ browserName: 'ipad', version: '4', platform:'OS X 10.6' });
|
||||
|
||||
exports.saucelabs_android = sauceItUp({ browserName: 'android', version: '4.0', platform:'Linux' });
|
||||
exports.saucelabs_android_tablet = sauceItUp({ browserName: 'android', version: '4.0', platform:'Linux', 'device-type':'tablet' });
|
||||
|
||||
exports.saucelabs_safari = sauceItUp({ browserName: 'safari' });
|
||||
exports.saucelabs_chrome = sauceItUp({ browserName: 'chrome' });
|
||||
exports.saucelabs_firefox = sauceItUp({ browserName: 'firefox' });
|
||||
|
||||
exports.saucelabs_ie =
|
||||
exports.saucelabs_ie8 = sauceItUp({ browserName: 'internet explorer', version: 8 });
|
||||
exports.saucelabs_ie9 = sauceItUp({ browserName: 'internet explorer', version: 9 });
|
||||
exports.saucelabs_ie10 = sauceItUp({ browserName: 'internet explorer', version: 10 });
|
||||
exports.saucelabs_ie11 = sauceItUp({ browserName: 'internet explorer', version: 11, platform:'Windows 8.1' });
|
||||
|
||||
|
||||
function sauceItUp(desiredCapabilities){
|
||||
desiredCapabilities["build"] = exports.saucelabs.desiredCapabilities["build"];
|
||||
desiredCapabilities["tunnel-identifier"] = exports.saucelabs.desiredCapabilities["tunnel-identifier"];
|
||||
return {
|
||||
webdriver: exports.saucelabs.webdriver,
|
||||
url: exports.saucelabs.url,
|
||||
onStart: exports.saucelabs.onStart,
|
||||
onComplete: exports.saucelabs.onComplete,
|
||||
onError: exports.saucelabs.onError,
|
||||
desiredCapabilities: desiredCapabilities,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
var grunt = require('grunt');
|
||||
var SauceTunnel = require('sauce-tunnel');
|
||||
|
||||
module.exports = function(){
|
||||
var task = this;
|
||||
var config = task.data;
|
||||
var shouldStayAliveForever = task.flags.keepalive;
|
||||
|
||||
var SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY;
|
||||
if (!SAUCE_ACCESS_KEY) grunt.fatal('Requires the environment variable SAUCE_ACCESS_KEY to be set');
|
||||
|
||||
var SAUCE_USERNAME = process.env.SAUCE_USERNAME;
|
||||
if (!SAUCE_USERNAME) grunt.fatal('Requires the environment variable SAUCE_USERNAME to be set');
|
||||
|
||||
var IDENTIFIER = process.env.TRAVIS_JOB_NUMBER || 'my awesome tunnel';
|
||||
|
||||
var taskCompletedSuccessfully = task.async();
|
||||
|
||||
var stunnel = new SauceTunnel(SAUCE_USERNAME, SAUCE_ACCESS_KEY, IDENTIFIER, /*tunneled*/true, /*tunnelTimeout*/5);
|
||||
process.on('exit', stunnel.stop.bind(stunnel, function(){}));
|
||||
|
||||
stunnel.on('log:error', grunt.log.error.bind(grunt.log));
|
||||
stunnel.on('log:writeln', grunt.log.writeln.bind(grunt.log));
|
||||
|
||||
stunnel.on('verbose:ok', grunt.verbose.ok.bind(grunt.verbose));
|
||||
stunnel.on('verbose:error', grunt.verbose.error.bind(grunt.verbose));
|
||||
stunnel.on('verbose:debug', grunt.verbose.debug.bind(grunt.verbose));
|
||||
stunnel.on('verbose:writeln', grunt.verbose.writeln.bind(grunt.verbose));
|
||||
|
||||
stunnel.openTunnel(function(isOpen){
|
||||
if (shouldStayAliveForever && isOpen){
|
||||
grunt.verbose.writeln('Keeping the sauce-tunnel open forever because you used the keepalive flag `' + task.nameArgs + '`');
|
||||
return;
|
||||
}
|
||||
grunt.verbose.writeln('To keep the sauce-tunnel open forever, use the grunt task `' + task.nameArgs + ':keepalive`');
|
||||
taskCompletedSuccessfully(isOpen);
|
||||
});
|
||||
};
|
||||
@@ -4,7 +4,14 @@ var wd = require('wd');
|
||||
module.exports = function(){
|
||||
var config = this.data;
|
||||
var taskSucceeded = this.async();
|
||||
grunt.verbose.write('webdriver remote', JSON.stringify(config.webdriver.remote));
|
||||
|
||||
var desiredCapabilities = {};
|
||||
if (config.desiredCapabilities) Object.keys(config.desiredCapabilities).forEach(function(key){
|
||||
if (config.desiredCapabilities[key] === undefined) return;
|
||||
desiredCapabilities[key] = config.desiredCapabilities[key];
|
||||
});
|
||||
grunt.verbose.writeln("desiredCapabilities", JSON.stringify(desiredCapabilities));
|
||||
|
||||
var browser = wd.promiseChainRemote(config.webdriver.remote);
|
||||
|
||||
browser.on('status', function(info) {
|
||||
@@ -15,30 +22,50 @@ module.exports = function(){
|
||||
grunt.verbose.writeln(' > ' + meth, path, data || '');
|
||||
});
|
||||
|
||||
var results = null;
|
||||
|
||||
// browser._debugPromise();
|
||||
browser
|
||||
.init(config.browser || {})
|
||||
.init(desiredCapabilities)
|
||||
.then(config.onStart && config.onStart.bind(config, browser))
|
||||
.get(config.url)
|
||||
.then(function(){return browser;})
|
||||
.then(getJSReport)
|
||||
.then(config.onComplete && config.onComplete.bind(browser), config.onError && config.onError.bind(browser))
|
||||
.fail(grunt.verbose.writeln.bind(grunt.verbose))
|
||||
.fin(function(){
|
||||
.then(function(data){ results = data; })
|
||||
.fail(function(error){
|
||||
grunt.log.error(error);
|
||||
return browser
|
||||
.eval('document.documentElement.innerText || document.documentElement.textContent')
|
||||
.then(grunt.verbose.writeln.bind(grunt.verbose))
|
||||
.then(function(){throw error})
|
||||
;
|
||||
})
|
||||
.finally(function(){
|
||||
if (grunt.option('webdriver-keep-open')) return;
|
||||
grunt.verbose.writeln('Closing the browser window. To keep it open, pass the --webdriver-keep-open flag to grunt.');
|
||||
return browser.quit();
|
||||
})
|
||||
.done(
|
||||
taskSucceeded.bind(null,true),
|
||||
taskSucceeded.bind(null,false)
|
||||
function(){
|
||||
if (config.onComplete) config.onComplete(results);
|
||||
taskSucceeded(true);
|
||||
},
|
||||
function(error){
|
||||
if (config.onError) config.onError(error);
|
||||
taskSucceeded(false);
|
||||
}
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
function getJSReport(browser){
|
||||
return browser
|
||||
.waitForCondition("typeof window.jasmine != 'undefined'", 500)
|
||||
.waitForCondition("typeof window.jasmine != 'undefined'", 5e3)
|
||||
.fail(function(error){
|
||||
throw Error("The test page didn't load properly. " + error);
|
||||
})
|
||||
.waitForCondition("typeof window.jasmine.getJSReport != 'undefined'", 10e3)
|
||||
.waitForCondition("window.testImageURL.running <= 0", 5e3)
|
||||
.eval("jasmine.getJSReport()")
|
||||
.waitForCondition("window.postDataToURL.running <= 0", 30e3)
|
||||
.eval("jasmine.getJSReport().passed")
|
||||
;
|
||||
}
|
||||
|
||||
+2
-1
@@ -60,7 +60,8 @@
|
||||
"jasmine-tapreporter": "~0.2.2",
|
||||
"grunt-contrib-connect": "~0.5.0",
|
||||
"es5-shim": "~2.1.0",
|
||||
"wd": "~0.2.2"
|
||||
"wd": "~0.2.2",
|
||||
"sauce-tunnel": "~1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
console._error = console.error;
|
||||
console._warn = console.warn;
|
||||
console._log = console.log;
|
||||
|
||||
console.log = window.print = function(message){
|
||||
console._log(message);
|
||||
testImageURL('/print?type=log&message=' + encodeURIComponent(message) + '&_=' + Date.now().toString(36));
|
||||
if (typeof console == 'undefined') console = {
|
||||
log: function(){},
|
||||
warn: function(){},
|
||||
error: function(){}
|
||||
};
|
||||
|
||||
console._log = console.log;
|
||||
console.log = function(message){
|
||||
console._log(message);
|
||||
postDataToURL({type:'log', message:message}, '/reportTestResults');
|
||||
}
|
||||
console._error = console.error;
|
||||
console.error = function(message){
|
||||
console._error(message);
|
||||
testImageURL('/print?type=error&message=' + encodeURIComponent(message) + '&_=' + Date.now().toString(36));
|
||||
};
|
||||
|
||||
console.warn = function(message){
|
||||
console._warn(message);
|
||||
testImageURL('/print?type=warn&message=' + encodeURIComponent(message) + '&_=' + Date.now().toString(36));
|
||||
};
|
||||
postDataToURL({type:'error', message:message}, '/reportTestResults');
|
||||
}
|
||||
|
||||
;(function(env){
|
||||
|
||||
env.addReporter(new jasmine.JSReporter());
|
||||
env.addReporter(new TAPReporter(window.print));
|
||||
if (location.search.substring(1).indexOf('debug') != -1){
|
||||
env.addReporter(new TAPReporter(console.log.bind(console)));
|
||||
}
|
||||
|
||||
function report(){
|
||||
if (typeof jasmine.getJSReport != 'function') return setTimeout(report, 100);
|
||||
postDataToURL(JSON.stringify(jasmine.getJSReport()), '/reportTestResults', function(error, event){
|
||||
if (typeof jasmine.getJSReport != 'function') {
|
||||
console.log("typeof jasmine.getJSReport != 'function'");
|
||||
return setTimeout(report, 100);
|
||||
}
|
||||
postDataToURL(jasmine.getJSReport(), '/reportTestResults', function(error, results){
|
||||
if (error) return console.error(error);
|
||||
});
|
||||
}
|
||||
@@ -35,42 +37,31 @@ console.warn = function(message){
|
||||
report();
|
||||
};
|
||||
|
||||
function postDataToURL(data, url, callback){
|
||||
var id = '$' + (+new Date()).toString(36);
|
||||
|
||||
var postReportingTarget = document.createElement('iframe');
|
||||
postReportingTarget.id = postReportingTarget.name = 'postReportingTarget' + id;
|
||||
|
||||
var postReportingForm = document.createElement('form');
|
||||
postReportingForm.method = 'POST';
|
||||
postReportingForm.action = url;
|
||||
postReportingForm.target = postReportingTarget.name;
|
||||
|
||||
var postReportingData = document.createElement('input');
|
||||
postReportingData.type = 'hidden';
|
||||
postReportingData.name = 'data';
|
||||
postReportingData.value = data || '{"error":"unknown error in postReportingData"}';
|
||||
|
||||
postReportingForm.appendChild(postReportingData);
|
||||
postReportingForm.appendChild(postReportingTarget);
|
||||
postReportingForm.style.cssText = "visibility:hidden; position:absolute; bottom:100%; right:100%";
|
||||
|
||||
function done(error, event){
|
||||
postReportingForm.parentNode.removeChild(postReportingForm);
|
||||
callback(error, event);
|
||||
}
|
||||
|
||||
postReportingTarget.onerror = function(error){
|
||||
done(error);
|
||||
}
|
||||
postReportingTarget.onload = function(event){
|
||||
done(null, event);
|
||||
}
|
||||
document.body.appendChild(postReportingForm);
|
||||
setTimeout(function(){
|
||||
postReportingForm.submit();
|
||||
},0);
|
||||
}
|
||||
|
||||
}(window.jasmine.getEnv()));
|
||||
|
||||
function createXMLHttpRequest(){
|
||||
try{return new XMLHttpRequest();}
|
||||
catch(e){}
|
||||
try {return new ActiveXObject("Msxml2.XMLHTTP");}
|
||||
catch (e) {}
|
||||
try {return new ActiveXObject("Microsoft.XMLHTTP");}
|
||||
catch (e) {}
|
||||
}
|
||||
function postDataToURL(data, url, callback) {
|
||||
if (!callback) callback = postDataToURL.defaultCallback;
|
||||
var request = createXMLHttpRequest();
|
||||
if (!request) return callback(Error('XMLHttpRequest is unsupported'));
|
||||
postDataToURL.running = (postDataToURL.running||0) + 1;
|
||||
request.onreadystatechange = function(){
|
||||
if (request.readyState != 4) return;
|
||||
request.onreadystatechange = null;
|
||||
postDataToURL.running = (postDataToURL.running||0) - 1;
|
||||
callback(request.status == 200 ? null : request.status, request.responseText);
|
||||
};
|
||||
request.open('POST', url);
|
||||
request.setRequestHeader('Content-Type', 'application/json');
|
||||
request.send(JSON.stringify(data));
|
||||
}
|
||||
postDataToURL.defaultCallback = function(error){
|
||||
// console.log('postDataToURL.defaultCallback', arguments)
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
testImageURL._recycle = function(img){
|
||||
console.log('_recycle', img);
|
||||
try {
|
||||
img.src = '';
|
||||
img.onload = img.onerror = null;
|
||||
} catch(e){}
|
||||
testImageURL._recycleBin.push(img);
|
||||
}
|
||||
testImageURL.getImage = function(callback){
|
||||
// if (!testImageURL._recycleBin) testImageURL._recycleBin = [new Image(),new Image(),new Image(),new Image()];
|
||||
// function get(){
|
||||
// if (testImageURL._recycleBin.length === 0) return setTimeout(get, 100);
|
||||
// callback(testImageURL._recycleBin.shift(), testImageURL._recycle);
|
||||
// }
|
||||
// get();
|
||||
callback(new Image(), function recycle(){});
|
||||
}
|
||||
|
||||
testImageURL.defaultCallback = function(error, event){}
|
||||
|
||||
function testImageURL(url, timeout, callback){
|
||||
if (typeof timeout == 'function'){
|
||||
callback = timeout;
|
||||
timeout = testImageURL.timeout;
|
||||
}
|
||||
if (typeof callback != 'function') callback = testImageURL.defaultCallback;
|
||||
|
||||
testImageURL.getImage(function(img, done){
|
||||
function callbackWrapper(error, event){
|
||||
callbackWrapper = testImageURL.noop;
|
||||
testImageURL.running = (testImageURL.running || 0) - 1;
|
||||
clearTimeout(timer);
|
||||
done(img);
|
||||
img = url = timeout = null;
|
||||
callback(error, event);
|
||||
error = event = callback = null;
|
||||
}
|
||||
|
||||
var timer = setTimeout(function(){callbackWrapper(Error('timeout'));}, timeout);
|
||||
|
||||
try {
|
||||
img.onload = function(event){ callbackWrapper(null, event || window.event); };
|
||||
img.onerror = function(error){ callbackWrapper(error); };
|
||||
img.src = url;
|
||||
testImageURL.running = (testImageURL.running || 0) + 1;
|
||||
|
||||
if (img.complete === true
|
||||
|| img.readyState == 4
|
||||
|| img.width > 0
|
||||
|| img.height > 0
|
||||
|| img.readyState == 'complete'
|
||||
) callbackWrapper(null, null);
|
||||
}
|
||||
catch(error){
|
||||
callbackWrapper(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testImageURL.noop = function(){};
|
||||
|
||||
testImageURL.timeout = 5000;
|
||||
Reference in New Issue
Block a user