wct.emitHook('prepare:webserver', app, function(error) { if (error) return done(error); // Serve up all the static assets. app.use(serveWaterfall(wsOptions.pathMappings, { root: options.root, headers: DEFAULT_HEADERS, log: wct.emit.bind(wct, 'log:debug'), })); app.get('/favicon.ico', function(request, response) { response.end(); }); app.use(function(request, response, next) { wct.emit('log:warn', '404', chalk.magenta(request.method), request.url); next(); }); server.listen(port); server.port = port; cleankill.onInterrupt(function(done) { server.close(done); }); wct.emit('log:info', 'Web server running on port', chalk.yellow(port), 'and serving from', chalk.magenta(options.root) ); done(); });
temp.mkdir('wct', function(error, logDir) { if (error) return done(error); var logPath = path.join(logDir, 'sc.log'); var connectOptions = { username: config.username, accessKey: config.accessKey, tunnelIdentifier: uuid.v4(), logger: emitter.emit.bind(emitter, 'log:debug'), logfile: logPath, }; _.assign(connectOptions, config.tunnelOptions); var tunnelId = connectOptions.tunnelIdentifier; emitter.emit('log:info', 'Creating Sauce Connect tunnel'); emitter.emit('log:info', 'Sauce Connect log:', chalk.magenta(logPath)); emitter.emit('log:debug', 'sauce-connect-launcher options', connectOptions); sauceConnect(connectOptions, function(error, tunnel) { if (error) { emitter.emit('log:error', 'Sauce tunnel failed:'); } else { emitter.emit('log:info', 'Sauce tunnel active:', chalk.yellow(tunnelId)); emitter.emit('sauce:tunnel-active', tunnelId); } done(error, tunnelId); }); // SauceConnectLauncher only supports one tunnel at a time; this allows us to // kill it before we've gotten our callback. cleankill.onInterrupt(sauceConnect.kill.bind(sauceConnect)); });
// Browser abstraction, responsible for spinning up a browser instance via wd.js and // executing runner.html test files passed in options.files function BrowserRunner(emitter, capabilities, options, doneCallback) { this.timeout = options.testTimeout; this.emitter = emitter; this.options = options; this.def = capabilities; this.doneCallback = doneCallback; this.stats = {status: 'initializing'}; this.browser = wd.remote(this.def.url); // never retry selenium commands this.browser.configureHttp({ retries: -1 }); cleankill.onInterrupt(function(done) { if (!this.browser) return done(); var origDoneCallback = this.doneCallback; this.doneCallback = function(error, runner) { done(); origDoneCallback(error, runner); }; this.done('Interrupting'); }.bind(this)); this.browser.on('command', function(method, context) { emitter.emit('log:debug', this.def, chalk.cyan(method), context); }.bind(this)); this.browser.on('http', function(method, path, data) { if (data) { emitter.emit('log:debug', this.def, chalk.magenta(method), chalk.cyan(path), data); } else { emitter.emit('log:debug', this.def, chalk.magenta(method), chalk.cyan(path)); } }.bind(this)); this.browser.on('connection', function(code, message, error) { emitter.emit('log:warn', this.def, 'Error code ' + code + ':', message, error); }.bind(this)); this.emitter.emit('browser-init', this.def, this.stats); // Make sure that we are passing a pristine capabilities object to webdriver. // None of our screwy custom properties! var webdriverCapabilities = _.clone(this.def); delete webdriverCapabilities.id; delete webdriverCapabilities.url; delete webdriverCapabilities.sessionId; // Reusing a session? if (this.def.sessionId) { this.browser.attach(this.def.sessionId, function(error) { this._init(error, this.def.sessionId); }.bind(this)); } else { this.browser.init(webdriverCapabilities, this._init.bind(this)); } }
spawnCb: function(server) { // Make sure that we interrupt the selenium server ASAP. cleankill.onInterrupt(function(done) { server.kill(); done(); }); server.stdout.on('data', onOutput); server.stderr.on('data', onOutput); },
return __awaiter(this, void 0, void 0, function* () { const app = express(); const server = http.createServer(app); app.use('/httpbin', exports.httpbin); const port = yield port_scanner_1.findPort([7777, 7000, 8000, 8080, 8888]); server.listen(port); server.port = port; serverDestroy(server); cleankill.onInterrupt(() => { return new Promise((resolve) => { server.destroy(); server.on('close', resolve); }); }); console.log('Server running at http://localhost:' + port + '/httpbin/'); });
wct.emitHook('prepare:webserver', app, function(error) { if (error) return done(error); // The static root is the lowest priority middleware. app.use(serveStatic(options.root, {'index': ['index.html', 'index.htm']})); server.listen(port); server.port = port; cleankill.onInterrupt(function(done) { server.close(); done(); }); wct.emit('log:info', 'Web server running on port', chalk.yellow(port), 'and serving from', chalk.magenta(options.root) ); done(); });
wct.emitHook('prepare:webserver', app, function(error) { if (error) return done(error); // Serve up all the static assets. app.use(serveWaterfall(wsOptions.pathMappings, { root: options.root, headers: DEFAULT_HEADERS, log: wct.emit.bind(wct, 'log:debug'), })); app.use('/httpbin', httpbin.httpbin); app.get('/favicon.ico', function(request, response) { response.end(); }); app.use(function(request, response, next) { wct.emit('log:warn', '404', chalk.magenta(request.method), request.url); next(); }); server.listen(port); server.port = port; serverDestroy(server); cleankill.onInterrupt(function(done) { // close the socket IO server directly if it is spun up var io = wct._socketIOServer; if (io) { // we will close the underlying server ourselves io.httpServer = null; io.close(); } server.destroy(); server.on('close', done); }); wct.emit('log:info', 'Web server running on port', chalk.yellow(port), 'and serving from', chalk.magenta(options.root) ); done(); });
return __awaiter(this, void 0, void 0, function* () { const wsOptions = options.webserver; const additionalRoutes = new Map(); const packageName = config_1.getPackageName(options); let componentDir; // Check for client-side compatibility. // Non-npm case. if (!options.npm) { componentDir = bowerConfig.read(options.root).directory; const pathToLocalWct = path.join(options.root, componentDir, 'web-component-tester'); let version = undefined; const mdFilenames = ['package.json', 'bower.json', '.bower.json']; for (const mdFilename of mdFilenames) { const pathToMetadata = path.join(pathToLocalWct, mdFilename); try { if (!version) { version = require(pathToMetadata).version; } } catch (e) { // Handled below, where we check if we found a version. } } if (!version) { throw new Error(` The web-component-tester Bower package is not installed as a dependency of this project (${packageName}). Please run this command to install: bower install --save-dev web-component-tester Web Component Tester >=6.0 requires that support files needed in the browser are installed as part of the project's dependencies or dev-dependencies. This is to give projects greater control over the versions that are served, while also making Web Component Tester's behavior easier to understand. Expected to find a ${mdFilenames.join(' or ')} at: ${pathToLocalWct}/ `); } const allowedRange = require(path.join(__dirname, '..', 'package.json'))['--private-wct--']['client-side-version-range']; if (!semver.satisfies(version, allowedRange)) { throw new Error(` The web-component-tester Bower package installed is incompatible with the wct node package you're using. The test runner expects a version that satisfies ${allowedRange} but the bower package you have installed is ${version}. `); } let hasWarnedBrowserJs = false; additionalRoutes.set('/browser.js', function (request, response) { if (!hasWarnedBrowserJs) { console.warn(` WARNING: Loading WCT's browser.js from /browser.js is deprecated. Instead load it from ../web-component-tester/browser.js (or with the absolute url /components/web-component-tester/browser.js) `); hasWarnedBrowserJs = true; } const browserJsPath = path.join(pathToLocalWct, 'browser.js'); send(request, browserJsPath).pipe(response); }); } const pathToGeneratedIndex = `/components/${packageName}/generated-index.html`; additionalRoutes.set(pathToGeneratedIndex, (_request, response) => { response.set(DEFAULT_HEADERS); response.send(options.webserver._generatedIndexContent); }); const appMapper = (app, options) => __awaiter(this, void 0, void 0, function* () { // Using the define:webserver hook to provide a mapper function that // allows user to substitute their own app for the generated polyserve // app. yield wct.emitHook('define:webserver', app, (substitution) => { app = substitution; }, options); return app; }); // Serve up project & dependencies via polyserve const polyserveResult = yield polyserve_1.startServers({ root: options.root, componentDir, compile: options.compile, hostname: options.webserver.hostname, port: options.webserver.port, headers: DEFAULT_HEADERS, packageName, additionalRoutes, npm: !!options.npm, moduleResolution: options.moduleResolution, proxy: options.proxy, }, appMapper); let servers; const onDestroyHandlers = []; const registerServerTeardown = (serverInfo) => { const destroyableServer = serverInfo.server; serverDestroy(destroyableServer); onDestroyHandlers.push(() => { destroyableServer.destroy(); return new Promise((resolve) => serverInfo.server.on('close', () => resolve())); }); }; if (polyserveResult.kind === 'mainline') { servers = [polyserveResult]; registerServerTeardown(polyserveResult); const address = polyserveResult.server.address(); if (typeof address !== 'string') { wsOptions.port = address.port; } } else if (polyserveResult.kind === 'MultipleServers') { servers = [polyserveResult.mainline]; servers = servers.concat(polyserveResult.variants); const address = polyserveResult.mainline.server.address(); if (typeof address !== 'string') { wsOptions.port = address.port; } for (const server of polyserveResult.servers) { registerServerTeardown(server); } } else { const never = polyserveResult; throw new Error('Internal error: Got unknown response from polyserve.startServers: ' + `${never}`); } wct._httpServers = servers.map((s) => s.server); // At this point, we allow other plugins to hook and configure the // webservers as they please. for (const server of servers) { yield wct.emitHook('prepare:webserver', server.app); } options.webserver._servers = servers.map((s) => { const address = s.server.address(); const port = typeof address === 'string' ? '' : `:${address.port}`; const hostname = s.options.hostname; const url = `http://${hostname}${port}${pathToGeneratedIndex}`; return { url, variant: s.kind === 'mainline' ? '' : s.variantName }; }); // TODO(rictic): re-enable this stuff. need to either move this code // into polyserve or let the polyserve API expose this stuff. // app.use('/httpbin', httpbin.httpbin); // app.get('/favicon.ico', function(request, response) { // response.end(); // }); // app.use(function(request, response, next) { // wct.emit('log:warn', '404', chalk.magenta(request.method), // request.url); // next(); // }); function interruptHandler() { return __awaiter(this, void 0, void 0, function* () { // close the socket IO server directly if it is spun up for (const io of (wct._socketIOServers || [])) { // we will close the underlying server ourselves io.httpServer = null; io.close(); } yield Promise.all(onDestroyHandlers.map((f) => f())); }); } cleankill.onInterrupt(() => { return new Promise((resolve) => { interruptHandler().then(() => resolve(), resolve); }); }); });