diff --git a/commands/protractor/src/config.js b/commands/protractor/src/config.js index abda0494..efadeb20 100644 --- a/commands/protractor/src/config.js +++ b/commands/protractor/src/config.js @@ -403,6 +403,10 @@ if (argv.seleniumServerJar) { argv.seleniumServerJar = jar; } +if (argv.glob.length) { + argv.specs = argv.glob.map(p => path.resolve(p)); +} + module.exports = { config: argv, }; diff --git a/commands/protractor/src/options.js b/commands/protractor/src/options.js index 360cec33..655cf11f 100644 --- a/commands/protractor/src/options.js +++ b/commands/protractor/src/options.js @@ -17,7 +17,7 @@ module.exports = { description: 'Glob pattern', type: 'array', default: TEST_GLOB, - alias: ['glob', 'specs'], + alias: ['glob'], }, coverage: { description: 'Generate coverage', diff --git a/packages/server/package.json b/packages/server/package.json index f64752fa..0a060238 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -22,6 +22,7 @@ "dependencies": { "@after-work.js/transform-middleware": "5.1.1", "@after-work.js/utils": "5.1.1", + "http-proxy-middleware": "0.19.1", "import-cwd": "2.1.0", "express": "4.16.4", "serve-favicon": "2.5.0", diff --git a/packages/server/src/index.js b/packages/server/src/index.js index ce04032e..4ecc58c2 100644 --- a/packages/server/src/index.js +++ b/packages/server/src/index.js @@ -2,19 +2,23 @@ const path = require('path'); const express = require('express'); const favicon = require('serve-favicon'); const transformFiles = require('@after-work.js/transform-middleware'); +const applyProxies = require('./proxies'); module.exports = function createServer(options) { const { middleware = () => {}, ...argv } = options; const app = express(); + const websocketProxies = applyProxies(app, options.proxy); app.use(favicon(path.resolve(__dirname, '../aw.png'))); app.use(transformFiles(argv)); app.use('/', express.static(process.cwd())); middleware(app, express); - return app.listen(argv.http.port, '0.0.0.0', (err) => { + const server = app.listen(argv.http.port, '0.0.0.0', (err) => { if (err) { throw err; } // eslint-disable-next-line no-console console.error(`Listening on http://0.0.0.0:${argv.http.port}`); }); + websocketProxies.forEach(wsProxy => server.on('upgrade', wsProxy.upgrade)); + return server; }; diff --git a/packages/server/src/proxies.js b/packages/server/src/proxies.js new file mode 100644 index 00000000..254d48ce --- /dev/null +++ b/packages/server/src/proxies.js @@ -0,0 +1,81 @@ +const httpProxyMiddleware = require('http-proxy-middleware'); + +const getProxyMiddleware = (proxyConfig) => { + if (typeof proxyConfig.logLevel === 'undefined') { + proxyConfig.logLevel = 'error'; + } + const context = proxyConfig.context || proxyConfig.path; + // It is possible to use the `bypass` method without a `target`. + // However, the proxy middleware has no use in this case, and will fail to instantiate. + if (proxyConfig.target) { + return httpProxyMiddleware(context, proxyConfig); + } + return null; +}; + +const normalize = options => Object.keys(options).map((context) => { + let proxyOptions; + const correctedContext = context + .replace(/^\*$/, '**') + .replace(/\/\*$/, ''); + if (typeof options.proxy[context] === 'string') { + proxyOptions = { + context: correctedContext, + target: options.proxy[context], + }; + } else { + proxyOptions = Object.assign({}, options.proxy[context]); + proxyOptions.context = correctedContext; + } + proxyOptions.logLevel = proxyOptions.logLevel || 'warn'; + return proxyOptions; +}); + +const applyProxies = (app, options = []) => { + const websocketProxies = []; + const proxy = !Array.isArray(options) ? normalize(options) : options; + proxy.forEach((proxyConfigOrCallback) => { + let proxyConfig; + let proxyMiddleware; + + if (typeof proxyConfigOrCallback === 'function') { + proxyConfig = proxyConfigOrCallback(); + } else { + proxyConfig = proxyConfigOrCallback; + } + + proxyMiddleware = getProxyMiddleware(proxyConfig); + + if (proxyConfig.ws) { + websocketProxies.push(proxyMiddleware); + } + + app.use((req, res, next) => { // eslint-disable-line + if (typeof proxyConfigOrCallback === 'function') { + const newProxyConfig = proxyConfigOrCallback(); + + if (newProxyConfig !== proxyConfig) { + proxyConfig = newProxyConfig; + proxyMiddleware = getProxyMiddleware(proxyConfig); + } + } + + const bypass = typeof proxyConfig.bypass === 'function'; + + const bypassUrl = (bypass && proxyConfig.bypass(req, res, proxyConfig)) || false; + + if (bypassUrl) { + req.url = bypassUrl; + + next(); + } else if (proxyMiddleware) { + return proxyMiddleware(req, res, next); + } else { + next(); + } + }); + }); + return websocketProxies; +}; + +module.exports = applyProxies;