mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
204 lines
5.2 KiB
JavaScript
204 lines
5.2 KiB
JavaScript
var _ = require('underscore');
|
|
var Fiber = require('fibers');
|
|
var Future = require('fibers/future');
|
|
var files = require('./files.js');
|
|
var runLog = require('./run-log.js');
|
|
var utils = require('./utils.js');
|
|
|
|
// options: runner url browserId xunitOutputFile
|
|
var Selenium = function (options) {
|
|
var self = this;
|
|
options = options || {};
|
|
|
|
self.driver = null;
|
|
self.server = null;
|
|
|
|
self.browserId = options.browserId || 'xunit';
|
|
self.url = options.url || 'http://localhost:3000/' + self.browserId;
|
|
self.xunitOutputFile = options.xunitOutputFile || 'test-results.xml';
|
|
|
|
self.runner = options.runner;
|
|
self.browser = options.browser || 'chrome';
|
|
|
|
self.xunitLines = null;
|
|
};
|
|
|
|
var _promiseToFuture = function (promise) {
|
|
var fut = new Future;
|
|
promise.then(function (result) {
|
|
fut.isResolved() || fut['return'](result);
|
|
}, function (err) {
|
|
fut.isResolved() || fut['throw'](err);
|
|
});
|
|
return fut;
|
|
};
|
|
|
|
|
|
// The magic prefix for special log output
|
|
// Must match packages/test-in-console/driver.js
|
|
var MAGIC_PREFIX = '##_meteor_magic##';
|
|
|
|
// For some reason, we can't see the console.log output
|
|
// unless we 'flush' it by sending another console.log via execute()
|
|
// Note that this is actually a magic message, so we get it echoed back to us;
|
|
// that's not necessary for this to work, but it keeps the output clean for users.
|
|
var DUMMY_FLUSH = MAGIC_PREFIX + "flush: flush";
|
|
|
|
_.extend(Selenium.prototype, {
|
|
// Start the selenium server, block (yield) until it is ready to go
|
|
// (actively listening on outer and proxying to inner), and then
|
|
// return.
|
|
start: function () {
|
|
var self = this;
|
|
|
|
if (self.server)
|
|
throw new Error("already running?");
|
|
|
|
self.xunitLines = [];
|
|
|
|
var webdriver = require('selenium-webdriver');
|
|
|
|
var capabilities;
|
|
var loggingPrefs;
|
|
if (self.browser === 'chrome') {
|
|
capabilities = webdriver.Capabilities.chrome();
|
|
loggingPrefs = {'browser': 'ALL'};
|
|
} else if (self.browser === 'firefox') {
|
|
capabilities = webdriver.Capabilities.firefox();
|
|
loggingPrefs = {'browser': 'ALL'};
|
|
} else {
|
|
throw new Error("Unhandled browser: " + self.browser);
|
|
}
|
|
|
|
if (loggingPrefs) {
|
|
capabilities = capabilities.set('loggingPrefs', loggingPrefs);
|
|
}
|
|
|
|
var builder = new webdriver.Builder().withCapabilities(capabilities);
|
|
self.driver = builder.build();
|
|
|
|
var fut = _promiseToFuture(self.driver.getSession());
|
|
fut.wait();
|
|
|
|
_promiseToFuture(self.driver.get(self.url)).wait();
|
|
|
|
Fiber(function () {
|
|
try {
|
|
self._pollLogs();
|
|
} catch (err) {
|
|
runLog.log("Log polling exited unexpectedly: " + err);
|
|
}
|
|
}).run();
|
|
},
|
|
|
|
stop: function () {
|
|
var self = this;
|
|
|
|
if (! self.driver)
|
|
return;
|
|
|
|
_promiseToFuture(self.driver.close()).wait();
|
|
_promiseToFuture(self.driver.quit()).wait();
|
|
self.driver = null;
|
|
},
|
|
|
|
_flushLogs: function () {
|
|
var self = this;
|
|
|
|
var promise = self.driver.executeScript("console.log('" + DUMMY_FLUSH + "');", []);
|
|
_promiseToFuture(promise).wait();
|
|
},
|
|
|
|
_getLogs: function () {
|
|
var self = this;
|
|
|
|
var promise = self.driver.manage().logs().get('browser');
|
|
return _promiseToFuture(promise).wait();
|
|
},
|
|
|
|
_gotStateDone: function () {
|
|
var self = this;
|
|
|
|
if (self.xunitOutputFile) {
|
|
runLog.log("Writing xunit output to: " + self.xunitOutputFile);
|
|
files.writeFile(self.xunitOutputFile, self.xunitLines.join('\n'));
|
|
}
|
|
|
|
if (self.runner) {
|
|
runLog.log("Shutting down in response to 'done' state");
|
|
self.runner.stop();
|
|
process.exit(0);
|
|
}
|
|
},
|
|
|
|
_gotState: function (state) {
|
|
var self = this;
|
|
|
|
runLog.log("State -> " + state);
|
|
|
|
if (state === "done") {
|
|
self._gotStateDone();
|
|
}
|
|
},
|
|
|
|
_gotMagicLog: function (facility, msg) {
|
|
var self = this;
|
|
|
|
if (facility == 'xunit') {
|
|
self.xunitLines.push(msg);
|
|
} else if (facility == 'state') {
|
|
self._gotState(msg);
|
|
} else if (facility == 'flush') {
|
|
// Ignore
|
|
} else {
|
|
runLog.log("Unknown magic: " + facility + ": " + msg);
|
|
}
|
|
},
|
|
|
|
_pollLogsOnce: function () {
|
|
var self = this;
|
|
|
|
self._flushLogs();
|
|
var logs = self._getLogs();
|
|
_.each(logs, function (log) {
|
|
var msg = log.message;
|
|
var regex = /([^\s]*)\s*([^\s]*)\s*(.*)/i;
|
|
var match = regex.exec(msg);
|
|
if (!match) {
|
|
runLog.log("Unknown console.log message format: " + JSON.stringify(log));
|
|
return;
|
|
}
|
|
msg = match[3];
|
|
if (msg === DUMMY_FLUSH) return;
|
|
if (msg.indexOf(MAGIC_PREFIX) == 0) {
|
|
msg = msg.substring(MAGIC_PREFIX.length);
|
|
var colonIndex = msg.indexOf(': ');
|
|
if (colonIndex == -1) {
|
|
self._gotMagicLog('', msg);
|
|
} else {
|
|
var facility = msg.substring(0, colonIndex);
|
|
msg = msg.substring(colonIndex + 2);
|
|
self._gotMagicLog(facility, msg);
|
|
}
|
|
} else {
|
|
runLog.log(msg);
|
|
}
|
|
});
|
|
},
|
|
|
|
_pollLogs: function () {
|
|
var self = this;
|
|
|
|
while (self.driver) {
|
|
try {
|
|
self._pollLogsOnce();
|
|
} catch (err) {
|
|
runLog.log("Error reading console log: " + err);
|
|
}
|
|
utils.sleepMs(1000);
|
|
}
|
|
},
|
|
});
|
|
|
|
exports.Selenium = Selenium;
|