UNPKG

intern

Version:

Intern. A next-generation code testing stack for JavaScript.

261 lines 11.5 kB
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "body-parser", "express", "ws", "@dojo/core/aspect", "@dojo/core/lang", "./common/util", "./node/util", "./middleware/instrument", "./middleware/unhandled", "./middleware/finalError", "./middleware/resolveSuites", "./middleware/post"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var body_parser_1 = require("body-parser"); var express = require("express"); var WebSocket = require("ws"); var aspect_1 = require("@dojo/core/aspect"); var lang_1 = require("@dojo/core/lang"); var util_1 = require("./common/util"); var util_2 = require("./node/util"); var instrument_1 = require("./middleware/instrument"); var unhandled_1 = require("./middleware/unhandled"); var finalError_1 = require("./middleware/finalError"); var resolveSuites_1 = require("./middleware/resolveSuites"); var post_1 = require("./middleware/post"); var Server = (function () { function Server(options) { lang_1.mixin(this, { basePath: '.', runInSync: false }, options); } Object.defineProperty(Server.prototype, "stopped", { get: function () { return !this._httpServer; }, enumerable: true, configurable: true }); Server.prototype.start = function () { var _this = this; var startupError; var wsServer; var httpServer; return new Promise(function (resolve, reject) { var app = (_this._app = express()); _this._sessions = {}; _this.executor.log('Listening for WebSocket connections on port', _this.socketPort); wsServer = new WebSocket.Server({ port: _this.socketPort }); wsServer.on('connection', function (client) { _this.executor.log('WebSocket connection opened:', client); _this._handleWebSocket(client); }); wsServer.on('error', function (error) { if (util_2.isErrnoException(error) && error.code === 'EADDRINUSE') { var err = new Error("Something is already listening on the websocket server port (" + _this.socketPort + ")"); err.code = error.code; err.errno = error.errno; reject(err); } else if (!_this._wsServer) { reject(error); } else { _this.executor.emit('error', error); } }); var context = Object.create(null, { stopped: { enumerable: true, get: function () { return _this.stopped; } }, basePath: { enumerable: true, get: function () { return _this.basePath; } }, executor: { enumerable: true, get: function () { return _this.executor; } }, handleMessage: { enumerable: false, writable: false, configurable: false, value: function (message) { return _this._handleMessage(message); } } }); Object.defineProperty(app.request, 'intern', { enumerable: true, get: function () { return context; } }); Object.defineProperty(app.response, 'intern', { enumerable: true, get: function () { return context; } }); app.use(body_parser_1.json({ limit: '1mb' }), body_parser_1.urlencoded({ extended: true })); app.use(function (request, _response, next) { _this.executor.log(request.method + " request for " + request.url); return next(); }); var internPath = _this.executor.config.internPath; app.use([ "/" + internPath + "__resolveSuites__", '/__intern/__resolveSuites__' ], resolveSuites_1.default(context)); app.use('/__intern', express.static(internPath, { fallthrough: false })); app.use(instrument_1.default(context), express.static(_this.basePath), post_1.default(context), unhandled_1.default(), finalError_1.default()); httpServer = app.listen(_this.port, resolve); httpServer.on('error', function (error) { if (util_2.isErrnoException(error) && error.code === 'EADDRINUSE') { var err = new Error("Something is already listening on the server port (" + _this.port + ")"); err.code = error.code; err.errno = error.errno; reject(err); } else if (!_this._httpServer) { reject(error); } else { _this.executor.emit('error', error); } }); var sockets = []; aspect_1.after(httpServer, 'close', function () { var socket; while ((socket = sockets.pop())) { socket.destroy(); } }); httpServer.on('connection', function (socket) { sockets.push(socket); _this.executor.log('HTTP connection opened,', sockets.length, 'open connections'); socket.on('close', function () { var index = sockets.indexOf(socket); index !== -1 && sockets.splice(index, 1); _this.executor.log('HTTP connection closed,', sockets.length, 'open connections'); }); }); }) .then(function () { _this._wsServer = wsServer; _this._httpServer = httpServer; }) .catch(function (error) { startupError = error; try { wsServer.close(); } catch (_error) { } try { httpServer.close(); } catch (_error) { } }) .then(function () { if (startupError) { throw startupError; } }); }; Server.prototype.stop = function () { var _this = this; this.executor.log('Stopping server...'); var promises = []; if (this._app && this._httpServer) { promises.push(new Promise(function (resolve) { _this._httpServer.close(resolve); }).then(function () { _this.executor.log('Stopped http server'); _this._app = _this._httpServer = undefined; })); } if (this._wsServer) { promises.push(new Promise(function (resolve) { _this._wsServer.close(resolve); }).then(function () { _this.executor.log('Stopped ws server'); _this._wsServer = undefined; })); } return Promise.all(promises); }; Server.prototype.subscribe = function (sessionId, listener) { var listeners = this._getSession(sessionId).listeners; listeners.push(listener); return { destroy: function () { this.destroy = function () { }; util_1.pullFromArray(listeners, listener); } }; }; Server.prototype._getSession = function (sessionId) { var session = this._sessions[sessionId]; if (!session) { session = this._sessions[sessionId] = { listeners: [] }; } return session; }; Server.prototype._handleMessage = function (message) { var _this = this; this.executor.log('Processing message [', message.id, '] for ', message.sessionId, ': ', message.name); var promise = this._publish(message); if (getShouldWait(this.runInSync, message)) { return promise; } promise.catch(function (error) { _this.executor.emit('error', error); }); return resolvedPromise; }; Server.prototype._handleWebSocket = function (client) { var _this = this; client.on('message', function (data) { _this.executor.log('Received WebSocket message'); var message = JSON.parse(data.toString()); _this._handleMessage(message) .catch(function (error) { return _this.executor.emit('error', error); }) .then(function () { _this.executor.log('Sending ack for [', message.id, ']'); client.send(JSON.stringify({ id: message.id }), function (error) { if (error) { _this.executor.emit('error', new Error("Error sending ack for [ " + message.id + " ]: " + error.message)); } }); }); }); client.on('error', function (error) { _this.executor.log('WebSocket client error:', error); _this.executor.emit('error', error); }); }; Server.prototype._publish = function (message) { var listeners = this._getSession(message.sessionId).listeners; return Promise.all(listeners.map(function (listener) { return listener(message.name, message.data); })); }; return Server; }()); exports.default = Server; var resolvedPromise = Promise.resolve(); function getShouldWait(waitMode, message) { var eventName = message.name; if (eventName === 'runEnd') { return false; } var shouldWait = false; if (waitMode === 'fail') { if ((eventName === 'testEnd' && message.data.error) || (eventName === 'suiteEnd' && message.data.error) || eventName === 'error') { shouldWait = true; } } else if (waitMode === true) { shouldWait = true; } else if (Array.isArray(waitMode) && waitMode.indexOf(eventName) !== -1) { shouldWait = true; } return shouldWait; } }); //# sourceMappingURL=Server.js.map