UNPKG

intern

Version:

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

284 lines 12.8 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", "tslib", "body-parser", "express", "ws", "./common/util", "./node/util", "./middleware/instrument", "./middleware/unhandled", "./middleware/finalError", "./middleware/resolveSuites", "./middleware/post", "./middleware/filterUrl"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var body_parser_1 = require("body-parser"); var express_1 = tslib_1.__importDefault(require("express")); var ws_1 = tslib_1.__importDefault(require("ws")); var util_1 = require("./common/util"); var util_2 = require("./node/util"); var instrument_1 = tslib_1.__importDefault(require("./middleware/instrument")); var unhandled_1 = tslib_1.__importDefault(require("./middleware/unhandled")); var finalError_1 = tslib_1.__importDefault(require("./middleware/finalError")); var resolveSuites_1 = tslib_1.__importDefault(require("./middleware/resolveSuites")); var post_1 = tslib_1.__importDefault(require("./middleware/post")); var filterUrl_1 = tslib_1.__importDefault(require("./middleware/filterUrl")); var Server = (function () { function Server(options) { Object.assign(this, { basePath: '.', runInSync: false, }, options); this._wsPingTimers = []; } Object.defineProperty(Server.prototype, "stopped", { get: function () { return !this._httpServer; }, enumerable: false, 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_1.default()); _this._sessions = {}; _this.executor.log('Listening for WebSocket connections on port', _this.socketPort); var clientCount = 0; wsServer = new ws_1.default.Server({ port: _this.socketPort }); wsServer.on('connection', function (client) { clientCount++; _this.executor.log("WebSocket client " + clientCount + " connected"); _this._handleWebSocket(client, clientCount); }); 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); } }); wsServer.on('close', function () { for (var _i = 0, _a = _this._wsPingTimers; _i < _a.length; _i++) { var timer = _a[_i]; clearInterval(timer); } }); 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(filterUrl_1.default()); 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_1.default.static(internPath, { fallthrough: false })); app.use(instrument_1.default(context), express_1.default.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 = []; httpServer.on('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, id) { var _this = this; var isAlive = true; var timer = setInterval(function () { if (!isAlive) { client.terminate(); clearInterval(timer); } isAlive = false; _this.executor.log('Sending ping to remote', id); client.ping(); }, 30000); this._wsPingTimers.push(timer); client.on('pong', function () { _this.executor.log('Received pong from remote', id); isAlive = true; }); client.on('message', function (data) { _this.executor.log('Received WebSocket message from', id); 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, '] to', id); client.send(JSON.stringify({ id: message.id }), function (error) { if (error) { _this.executor.emit('error', new Error("Error sending ack for [ " + message.id + " ] to " + id + ": " + error.message)); } }); }); }); client.on('error', function (error) { _this.executor.log("WebSocket client error for " + id + ":", error); _this.executor.emit('error', error); clearInterval(timer); }); }; 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