UNPKG

wct-mocha

Version:

Client-side library for testing web-components with Mocha.

1,439 lines (1,391 loc) 90.8 kB
var WctMocha = (function () { 'use strict'; function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var helpers = createCommonjsModule(function (module, exports) { /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); // Make sure that we use native timers, in case they're being stubbed out. var nativeSetInterval = window.setInterval; var nativeSetTimeout = window.setTimeout; var nativeRequestAnimationFrame = window.requestAnimationFrame; /** * Runs `stepFn`, catching any error and passing it to `callback` (Node-style). * Otherwise, calls `callback` with no arguments on success. * * @param {function()} callback * @param {function()} stepFn */ function safeStep(callback, stepFn) { var err; try { stepFn(); } catch (error) { err = error; } callback(err); } exports.safeStep = safeStep; /** * Runs your test at declaration time (before Mocha has begun tests). Handy for * when you need to test document initialization. * * Be aware that any errors thrown asynchronously cannot be tied to your test. * You may want to catch them and pass them to the done event, instead. See * `safeStep`. * * @param {string} name The name of the test. * @param {function(?function())} testFn The test function. If an argument is * accepted, the test will be treated as async, just like Mocha tests. */ function testImmediate(name, testFn) { if (testFn.length > 0) { return testImmediateAsync(name, testFn); } var err; try { testFn(); } catch (error) { err = error; } test(name, function (done) { done(err); }); } exports.testImmediate = testImmediate; /** * An async-only variant of `testImmediate`. * * @param {string} name * @param {function(?function())} testFn */ function testImmediateAsync(name, testFn) { var testComplete = false; var err; test(name, function (done) { var intervalId = nativeSetInterval(function () { if (!testComplete) { return; } clearInterval(intervalId); done(err); }, 10); }); try { testFn(function (error) { if (error) { err = error; testComplete = true; } }); } catch (error) { err = error; testComplete = true; } } exports.testImmediateAsync = testImmediateAsync; /** * Triggers a flush of any pending events, observations, etc and calls you * back after they have been processed. * * @param {function()} callback */ function flush(callback) { // Ideally, this function would be a call to Polymer.dom.flush, but that // doesn't support a callback yet // (https://github.com/Polymer/polymer-dev/issues/851), // ...and there's cross-browser flakiness to deal with. // Make sure that we're invoking the callback with no arguments so that the // caller can pass Mocha callbacks, etc. var done = function done() { callback(); }; // Because endOfMicrotask is flaky for IE, we perform microtask checkpoints // ourselves (https://github.com/Polymer/polymer-dev/issues/114): var isIE = navigator.appName === 'Microsoft Internet Explorer'; if (isIE && window.Platform && window.Platform.performMicrotaskCheckpoint) { var reallyDone_1 = done; done = function doneIE() { Platform.performMicrotaskCheckpoint(); nativeSetTimeout(reallyDone_1, 0); }; } // Everyone else gets a regular flush. var scope; if (window.Polymer && window.Polymer.dom && window.Polymer.dom.flush) { scope = window.Polymer.dom; } else if (window.Polymer && window.Polymer.flush) { scope = window.Polymer; } else if (window.WebComponents && window.WebComponents.flush) { scope = window.WebComponents; } if (scope && scope.flush) { scope.flush(); } // Ensure that we are creating a new _task_ to allow all active microtasks // to finish (the code you're testing may be using endOfMicrotask, too). nativeSetTimeout(done, 0); } exports.flush = flush; /** * Advances a single animation frame. * * Calls `flush`, `requestAnimationFrame`, `flush`, and `callback` * sequentially * @param {function()} callback */ function animationFrameFlush(callback) { flush(function () { nativeRequestAnimationFrame(function () { flush(callback); }); }); } exports.animationFrameFlush = animationFrameFlush; /** * DEPRECATED: Use `flush`. * @param {function} callback */ function asyncPlatformFlush(callback) { console.warn('asyncPlatformFlush is deprecated in favor of the more terse flush()'); return window.flush(callback); } exports.asyncPlatformFlush = asyncPlatformFlush; /** * */ function waitFor(fn, next, intervalOrMutationEl, timeout, timeoutTime) { timeoutTime = timeoutTime || Date.now() + (timeout || 1000); intervalOrMutationEl = intervalOrMutationEl || 32; try { fn(); } catch (e) { if (Date.now() > timeoutTime) { throw e; } else { if (typeof intervalOrMutationEl !== 'number') { intervalOrMutationEl.onMutation(intervalOrMutationEl, function () { waitFor(fn, next, intervalOrMutationEl, timeout, timeoutTime); }); } else { nativeSetTimeout(function () { waitFor(fn, next, intervalOrMutationEl, timeout, timeoutTime); }, intervalOrMutationEl); } return; } } next(); } exports.waitFor = waitFor; window.safeStep = safeStep; window.testImmediate = testImmediate; window.testImmediateAsync = testImmediateAsync; window.flush = flush; window.animationFrameFlush = animationFrameFlush; window.asyncPlatformFlush = asyncPlatformFlush; window.waitFor = waitFor; }); unwrapExports(helpers); var helpers_1 = helpers.safeStep; var helpers_2 = helpers.testImmediate; var helpers_3 = helpers.testImmediateAsync; var helpers_4 = helpers.flush; var helpers_5 = helpers.animationFrameFlush; var helpers_6 = helpers.asyncPlatformFlush; var helpers_7 = helpers.waitFor; var config = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ /** * The global configuration state for WCT's browser client. */ exports._config = { environmentScripts: [], environmentImports: [], root: null, waitForFrameworks: true, waitFor: null, numConcurrentSuites: 1, trackConsoleError: true, mochaOptions: { timeout: 10 * 1000 }, verbose: false, }; /** * Merges initial `options` into WCT's global configuration. * * @param {Object} options The options to merge. See `browser/config.ts` for a * reference. */ function setup(options) { var childRunner = childrunner.default.current(); if (childRunner) { deepMerge(exports._config, childRunner.parentScope.WCT._config); // But do not force the mocha UI delete exports._config.mochaOptions.ui; } if (options && typeof options === 'object') { deepMerge(exports._config, options); } if (!exports._config.root) { // Sibling dependencies. var wctMochaJsRoot = util.scriptPrefix('wct-mocha.js'); var browserJsRoot = util.scriptPrefix('browser.js'); var scriptName = wctMochaJsRoot ? 'wct-mocha.js' : 'browser.js'; var root = (wctMochaJsRoot || browserJsRoot); exports._config.root = util.basePath(root.substr(0, root.length - 1)); if (!exports._config.root) { throw new Error("Unable to detect root URL for WCT sources. " + ("Please set WCT.root before loading " + scriptName + " first.")); } } } exports.setup = setup; /** * Retrieves a configuration value. */ function get(key) { return exports._config[key]; } exports.get = get; function deepMerge(target, source) { Object.keys(source).forEach(function (untypedKey) { var key = untypedKey; var targetValue = target[key]; if (targetValue != null && typeof targetValue === 'object' && !Array.isArray(targetValue)) { deepMerge(targetValue, source[key]); } else { target[key] = source[key]; } }); } exports.deepMerge = deepMerge; }); unwrapExports(config); var config_1 = config._config; var config_2 = config.setup; var config_3 = config.get; var config_4 = config.deepMerge; var util = createCommonjsModule(function (module, exports) { /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); /** * @param {function()} callback A function to call when the active web component * frameworks have loaded. */ function whenFrameworksReady(callback) { debug('whenFrameworksReady'); function done() { debug('whenFrameworksReady done'); callback(); } // If webcomponents script is in the document, wait for WebComponentsReady. if (window.WebComponents && !window.WebComponents.ready) { debug('WebComponentsReady?'); window.addEventListener('WebComponentsReady', function wcReady() { window.removeEventListener('WebComponentsReady', wcReady); debug('WebComponentsReady'); done(); }); } else { done(); } } exports.whenFrameworksReady = whenFrameworksReady; /** * @return {string} '<count> <kind> tests' or '<count> <kind> test'. */ function pluralizedStat(count, kind) { if (count === 1) { return count + ' ' + kind + ' test'; } else { return count + ' ' + kind + ' tests'; } } exports.pluralizedStat = pluralizedStat; /** * @param {string} path The URI of the script to load. * @param {function} done */ function loadScript(path, done) { var script = document.createElement('script'); script.src = path; if (done) { script.onload = done.bind(null, null); script.onerror = done.bind(null, 'Failed to load script ' + script.src); } document.head.appendChild(script); } exports.loadScript = loadScript; /** * @param {string} path The URI of the stylesheet to load. * @param {function} done */ function loadStyle(path, done) { var link = document.createElement('link'); link.rel = 'stylesheet'; link.href = path; if (done) { link.onload = done.bind(null, null); link.onerror = done.bind(null, 'Failed to load stylesheet ' + link.href); } document.head.appendChild(link); } exports.loadStyle = loadStyle; /** * @param {...*} var_args Logs values to the console when the `debug` * configuration option is true. */ function debug() { var var_args = []; for (var _i = 0; _i < arguments.length; _i++) { var_args[_i] = arguments[_i]; } if (!config.get('verbose')) { return; } var args = [window.location.pathname].concat(var_args); (console.debug || console.log).apply(console, args); } exports.debug = debug; // URL Processing /** * @param {string} url * @return {{base: string, params: string}} */ function parseUrl(url) { var parts = url.match(/^(.*?)(?:\?(.*))?$/); return { base: parts[1], params: getParams(parts[2] || ''), }; } exports.parseUrl = parseUrl; /** * Expands a URL that may or may not be relative to `base`. * * @param {string} url * @param {string} base * @return {string} */ function expandUrl(url, base) { if (!base) { return url; } if (url.match(/^(\/|https?:\/\/)/)) { return url; } if (base.substr(base.length - 1) !== '/') { base = base + '/'; } return base + url; } exports.expandUrl = expandUrl; /** * @param {string=} opt_query A query string to parse. * @return {!Object<string, !Array<string>>} All params on the URL's query. */ function getParams(query) { query = typeof query === 'string' ? query : window.location.search; if (query.substring(0, 1) === '?') { query = query.substring(1); } // python's SimpleHTTPServer tacks a `/` on the end of query strings :( if (query.slice(-1) === '/') { query = query.substring(0, query.length - 1); } if (query === '') { return {}; } var result = {}; query.split('&').forEach(function (part) { var pair = part.split('='); if (pair.length !== 2) { console.warn('Invalid URL query part:', part); return; } var key = decodeURIComponent(pair[0]); var value = decodeURIComponent(pair[1]); if (!result[key]) { result[key] = []; } result[key].push(value); }); return result; } exports.getParams = getParams; /** * Merges params from `source` into `target` (mutating `target`). * * @param {!Object<string, !Array<string>>} target * @param {!Object<string, !Array<string>>} source */ function mergeParams(target, source) { Object.keys(source).forEach(function (key) { if (!(key in target)) { target[key] = []; } target[key] = target[key].concat(source[key]); }); } exports.mergeParams = mergeParams; /** * @param {string} param The param to return a value for. * @return {?string} The first value for `param`, if found. */ function getParam(param) { var params = getParams(); return params[param] ? params[param][0] : null; } exports.getParam = getParam; /** * @param {!Object<string, !Array<string>>} params * @return {string} `params` encoded as a URI query. */ function paramsToQuery(params) { var pairs = []; Object.keys(params).forEach(function (key) { params[key].forEach(function (value) { pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); }); }); return (pairs.length > 0) ? ('?' + pairs.join('&')) : ''; } exports.paramsToQuery = paramsToQuery; function getPathName(location) { return typeof location === 'string' ? location : location.pathname; } function basePath(location) { return getPathName(location).match(/^.*\//)[0]; } exports.basePath = basePath; function relativeLocation(location, basePath) { var path = getPathName(location); if (path.indexOf(basePath) === 0) { path = path.substring(basePath.length); } return path; } exports.relativeLocation = relativeLocation; function cleanLocation(location) { var path = getPathName(location); if (path.slice(-11) === '/index.html') { path = path.slice(0, path.length - 10); } return path; } exports.cleanLocation = cleanLocation; function parallel(runners, maybeLimit, done) { var limit; if (typeof maybeLimit !== 'number') { done = maybeLimit; limit = 0; } else { limit = maybeLimit; } if (!runners.length) { return done && done(); } var called = false; var total = runners.length; var numActive = 0; var numDone = 0; function runnerDone(error) { if (called) { return; } numDone = numDone + 1; numActive = numActive - 1; if (error || numDone >= total) { called = true; done && done(error); } else { runOne(); } } function runOne() { if (limit && numActive >= limit) { return; } if (!runners.length) { return; } numActive = numActive + 1; runners.shift()(runnerDone); } runners.forEach(runOne); } exports.parallel = parallel; /** * Finds the directory that a loaded script is hosted on. * * @param {string} filename * @return {string?} */ function scriptPrefix(filename) { var scripts = document.querySelectorAll('script[src*="/' + filename + '"]'); if (scripts.length !== 1) { return null; } var script = scripts[0].src; return script.substring(0, script.indexOf(filename)); } exports.scriptPrefix = scriptPrefix; }); unwrapExports(util); var util_1 = util.whenFrameworksReady; var util_2 = util.pluralizedStat; var util_3 = util.loadScript; var util_4 = util.loadStyle; var util_5 = util.debug; var util_6 = util.parseUrl; var util_7 = util.expandUrl; var util_8 = util.getParams; var util_9 = util.mergeParams; var util_10 = util.getParam; var util_11 = util.paramsToQuery; var util_12 = util.basePath; var util_13 = util.relativeLocation; var util_14 = util.cleanLocation; var util_15 = util.parallel; var util_16 = util.scriptPrefix; var childrunner = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ /** * A Mocha suite (or suites) run within a child iframe, but reported as if they * are part of the current context. */ var ChildRunner = /** @class */ (function () { function ChildRunner(url, parentScope) { this.eventListenersToRemoveOnClean = []; this.onRunComplete = null; this.share = null; this.parentScope = parentScope; var urlBits = util.parseUrl(url); util.mergeParams(urlBits.params, util.getParams(parentScope.location.search)); delete urlBits.params.cli_browser_id; this.url = "" + urlBits.base + util.paramsToQuery(urlBits.params); this.state = 'initializing'; } /** * Listeners added using this method will be removed on done() * * @param type event type * @param listener object which receives a notification * @param target event target */ ChildRunner.prototype.addEventListener = function (type, listener, target) { target.addEventListener(type, listener); var descriptor = { target: target, type: type, listener: listener }; this.eventListenersToRemoveOnClean.push(descriptor); }; /** * Removes all event listeners added by a method addEventListener defined * on an instance of ChildRunner. */ ChildRunner.prototype.removeAllEventListeners = function () { this.eventListenersToRemoveOnClean.forEach(function (_a) { var target = _a.target, type = _a.type, listener = _a.listener; return target.removeEventListener(type, listener); }); }; /** * @return {ChildRunner} The `ChildRunner` that was registered for this * window. */ ChildRunner.current = function () { return ChildRunner.get(window); }; /** * @param {!Window} target A window to find the ChildRunner of. * @param {boolean} traversal Whether this is a traversal from a child window. * @return {ChildRunner} The `ChildRunner` that was registered for `target`. */ ChildRunner.get = function (target, traversal) { var childRunner = ChildRunner.byUrl[target.location.href]; if (childRunner) { return childRunner; } if (window.parent === window) { // Top window. if (traversal) { console.warn('Subsuite loaded but was never registered. This most likely is due to wonky history behavior. Reloading...'); window.location.reload(); } return null; } // Otherwise, traverse. return window.parent.WCT._ChildRunner.get(target, true); }; /** * Loads and runs the subsuite. * * @param {function} done Node-style callback. */ ChildRunner.prototype.run = function (done) { var _this = this; util.debug('ChildRunner#run', this.url); this.state = 'loading'; this.onRunComplete = done; this.container = document.getElementById('subsuites'); if (!this.container) { var container_1 = (this.container = document.createElement('div')); container_1.id = 'subsuites'; document.body.appendChild(container_1); } var container = this.container; var iframe = (this.iframe = document.createElement('iframe')); iframe.classList.add('subsuite'); iframe.src = this.url; // Let the iframe expand the URL for us. var url = (this.url = iframe.src); container.appendChild(iframe); ChildRunner.byUrl[url] = this; this.timeoutId = window.setTimeout(function () { return _this.loaded(new Error('Timed out loading ' + url)); }, ChildRunner.loadTimeout); this.addEventListener('error', function () { return _this.loaded(new Error('Failed to load document ' + _this.url)); }, iframe); this.addEventListener('DOMContentLoaded', function () { return _this.loaded(); }, iframe.contentWindow); }; /** * Called when the sub suite's iframe has loaded (or errored during load). * * @param {*} error The error that occured, if any. */ ChildRunner.prototype.loaded = function (error) { util.debug('ChildRunner#loaded', this.url, error); if (!this.iframe || this.iframe.contentWindow == null && error) { this.signalRunComplete(error); this.done(); return; } // Not all targets have WCT loaded (compatiblity mode) if (this.iframe.contentWindow.WCT) { this.share = this.iframe.contentWindow.WCT.share; } if (error) { this.signalRunComplete(error); this.done(); } }; /** * Called in mocha/run.js when all dependencies have loaded, and the child is * ready to start running tests * * @param {*} error The error that occured, if any. */ ChildRunner.prototype.ready = function (error) { util.debug('ChildRunner#ready', this.url, error); if (this.timeoutId) { clearTimeout(this.timeoutId); } if (error) { this.signalRunComplete(error); this.done(); } }; /** * Called when the sub suite's tests are complete, so that it can clean up. */ ChildRunner.prototype.done = function () { var _this = this; util.debug('ChildRunner#done', this.url, arguments); // Make sure to clear that timeout. this.ready(); this.signalRunComplete(); if (this.iframe) { // Be safe and avoid potential browser crashes when logic attempts to // interact with the removed iframe. setTimeout(function () { _this.removeAllEventListeners(); _this.container.removeChild(_this.iframe); _this.iframe = undefined; _this.share = null; }, 0); } }; ChildRunner.prototype.signalRunComplete = function (error) { if (this.onRunComplete) { this.state = 'complete'; this.onRunComplete(error); this.onRunComplete = null; } }; // ChildRunners get a pretty generous load timeout by default. ChildRunner.loadTimeout = 60000; // We can't maintain properties on iframe elements in Firefox/Safari/???, so // we track childRunners by URL. ChildRunner.byUrl = {}; return ChildRunner; }()); exports.default = ChildRunner; }); unwrapExports(childrunner); var clisocket = createCommonjsModule(function (module, exports) { /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); var SOCKETIO_ENDPOINT = window.location.protocol + '//' + window.location.host; var SOCKETIO_LIBRARY = SOCKETIO_ENDPOINT + '/socket.io/socket.io.js'; /** * A socket for communication between the CLI and browser runners. * * @param {string} browserId An ID generated by the CLI runner. * @param {!io.Socket} socket The socket.io `Socket` to communicate over. */ var CLISocket = /** @class */ (function () { function CLISocket(browserId, socket) { this.browserId = browserId; this.socket = socket; } /** * @param {!Mocha.Runner} runner The Mocha `Runner` to observe, reporting * interesting events back to the CLI runner. */ CLISocket.prototype.observe = function (runner) { var _this = this; this.emitEvent('browser-start', { url: window.location.toString(), }); // We only emit a subset of events that we care about, and follow a more // general event format that is hopefully applicable to test runners beyond // mocha. // // For all possible mocha events, see: // https://github.com/visionmedia/mocha/blob/master/lib/runner.js#L36 runner.on('test', function (test) { _this.emitEvent('test-start', { test: getTitles(test) }); }); runner.on('test end', function (test) { _this.emitEvent('test-end', { state: getState(test), test: getTitles(test), duration: test.duration, error: test.err, }); }); runner.on('fail', function (test, err) { // fail the test run if we catch errors outside of a test function if (test.type !== 'test') { _this.emitEvent('browser-fail', 'Error thrown outside of test function: ' + err.stack); } }); runner.on('childRunner start', function (childRunner) { _this.emitEvent('sub-suite-start', childRunner.share); }); runner.on('childRunner end', function (childRunner) { _this.emitEvent('sub-suite-end', childRunner.share); }); runner.on('end', function () { _this.emitEvent('browser-end'); }); }; /** * @param {string} event The name of the event to fire. * @param {*} data Additional data to pass with the event. */ CLISocket.prototype.emitEvent = function (event, data) { this.socket.emit('client-event', { browserId: this.browserId, event: event, data: data, }); }; /** * Builds a `CLISocket` if we are within a CLI-run environment; short-circuits * otherwise. * * @param {function(*, CLISocket)} done Node-style callback. */ CLISocket.init = function (done) { var browserId = util.getParam('cli_browser_id'); if (!browserId) { return done(); } // Only fire up the socket for root runners. if (childrunner.default.current()) { return done(); } util.loadScript(SOCKETIO_LIBRARY, function (error) { if (error) { return done(error); } var server = io(SOCKETIO_ENDPOINT); // WTF(usergenic): The typings are super wrong or something. The object // returned by io() doesn't seem to map to the SocketIO.Server type at // all. var sockets = server; // server.sockets; var errorListener = function (error) { sockets.off('error', errorListener); done(error); }; sockets.on('error', errorListener); var connectListener = function () { sockets.off('connect', connectListener); done(null, new CLISocket(browserId, sockets)); }; sockets.on('connect', connectListener); }); }; return CLISocket; }()); exports.default = CLISocket; // Misc Utility /** * @param {!Mocha.Runnable} runnable The test or suite to extract titles from. * @return {!Array.<string>} The titles of the runnable and its parents. */ function getTitles(runnable) { var titles = []; while (runnable && !runnable.root && runnable.title) { titles.unshift(runnable.title); runnable = runnable.parent; } return titles; } /** * @param {!Mocha.Runnable} runnable * @return {string} */ function getState(runnable) { if (runnable.state === 'passed') { return 'passing'; } else if (runnable.state === 'failed') { return 'failing'; } else if (runnable.pending) { return 'pending'; } else { return 'unknown'; } } }); unwrapExports(clisocket); var statsCollector = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** (The MIT License) Copyright (c) 2011-2018 JS Foundation and contributors, https://js.foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * The following was extracted from * https://github.com/mochajs/mocha/blob/master/lib/stats-collector.js */ /** * Test statistics collector. * * @typedef {Object} StatsCollector * @property {number} suites - integer count of suites run. * @property {number} tests - integer count of tests run. * @property {number} passes - integer count of passing tests. * @property {number} pending - integer count of pending tests. * @property {number} failures - integer count of failed tests. * @property {Date} start - time when testing began. * @property {Date} end - time when testing concluded. * @property {number} duration - number of msecs that testing took. */ /** * Provides stats such as test duration, * number of tests passed / failed etc. * * @public * @memberof Mocha * @param {Runner} runner */ exports.createStatsCollector = function (runner) { var stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; if (!runner) { throw new TypeError('Missing runner argument'); } runner.stats = stats; runner.once('start', function () { stats.start = new Date(); }); runner.on('suite', function (suite) { suite.root || stats.suites++; }); runner.on('pass', function () { stats.passes++; }); runner.on('fail', function () { stats.failures++; }); runner.on('pending', function () { stats.pending++; }); runner.on('test end', function () { stats.tests++; }); runner.once('end', function () { stats.end = new Date(); // To coerce to numbers and make TS compiler happy, we use unary `+` prefix // for date arithmetic. stats.duration = +stats.end - +stats.start; }); }; }); unwrapExports(statsCollector); var statsCollector_1 = statsCollector.createStatsCollector; var console_1 = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ // We capture console events when running tests; so make sure we have a // reference to the original one. var console = window.console; var FONT = ';font: normal 13px "Roboto", "Helvetica Neue", "Helvetica", sans-serif;'; var STYLES = { plain: FONT, suite: 'color: #5c6bc0' + FONT, test: FONT, passing: 'color: #259b24' + FONT, pending: 'color: #e65100' + FONT, failing: 'color: #c41411' + FONT, stack: 'color: #c41411', results: FONT + 'font-size: 16px', }; // I don't think we can feature detect this one... var userAgent = navigator.userAgent.toLowerCase(); var CAN_STYLE_LOG = userAgent.match('firefox') || userAgent.match('webkit'); var CAN_STYLE_GROUP = userAgent.match('webkit'); // Track the indent for faked `console.group` var logIndent = ''; function getStyle(style) { if (style === undefined) { return STYLES.plain; } return STYLES[style] || STYLES.plain; } function log(text, style) { text = text.split('\n').map(function (l) { return logIndent + l; }).join('\n'); if (CAN_STYLE_LOG) { console.log('%c' + text, getStyle(style)); } else { console.log(text); } } function logGroup(text, style) { if (CAN_STYLE_GROUP) { console.group('%c' + text, getStyle(style)); } else if (console.group) { console.group(text); } else { logIndent = logIndent + ' '; log(text, style); } } function logGroupEnd() { if (console.groupEnd) { console.groupEnd(); } else { logIndent = logIndent.substr(0, logIndent.length - 2); } } function logException(error) { log(error.stack || error.message || (error + ''), 'stack'); } /** * A Mocha reporter that logs results out to the web `console`. */ var Console = /** @class */ (function () { /** * @param runner The runner that is being reported on. */ function Console(runner) { // Mocha 6 runner doesn't have stats at this point so we need to use // the stats-collector from Mocha to add them before calling the base // reporter. if (!runner.stats) { statsCollector.createStatsCollector(runner); } Mocha.reporters.Base.call(this, runner); runner.on('suite', function (suite) { return suite.root && logGroup(suite.title, 'suite'); }); runner.on('suite end', function (suite) { return suite.root && logGroupEnd(); }); runner.on('test', function (test) { return logGroup(test.title, 'test'); }); runner.on('pending', function (test) { return logGroup(test.title, 'pending'); }); runner.on('fail', function (_test, error) { return logException(error); }); runner.on('test end', function (_test) { return logGroupEnd(); }); runner.on('end', this.logSummary.bind(this)); } /** Prints out a final summary of test results. */ Console.prototype.logSummary = function () { logGroup('Test Results', 'results'); if (this.stats.failures > 0) { log(util.pluralizedStat(this.stats.failures, 'failing'), 'failing'); } if (this.stats.pending > 0) { log(util.pluralizedStat(this.stats.pending, 'pending'), 'pending'); } log(util.pluralizedStat(this.stats.passes, 'passing')); if (!this.stats.failures) { log('test suite passed', 'passing'); } log('Evaluated ' + this.stats.tests + ' tests in ' + this.stats.duration + 'ms.'); logGroupEnd(); }; return Console; }()); exports.default = Console; }); unwrapExports(console_1); var html = createCommonjsModule(function (module, exports) { /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); /** * WCT-specific behavior on top of Mocha's default HTML reporter. * * @param {!Mocha.Runner} runner The runner that is being reported on. */ function HTML(runner) { var output = document.createElement('div'); output.id = 'mocha'; document.body.appendChild(output); runner.on('suite', function (_test) { this.total = runner.total; }.bind(this)); Mocha.reporters.HTML.call(this, runner); } exports.default = HTML; // Woo! What a hack. This just saves us from adding a bunch of complexity around // style loading. var style = document.createElement('style'); style.textContent = "\n html, body {\n position: relative;\n height: 100%;\n width: 100%;\n min-width: 900px;\n }\n #mocha, #subsuites {\n height: 100%;\n position: absolute;\n top: 0;\n }\n #mocha {\n box-sizing: border-box;\n margin: 0 !important;\n padding: 60px 20px;\n right: 0;\n left: 500px;\n }\n #subsuites {\n -ms-flex-direction: column;\n -webkit-flex-direction: column;\n display: -ms-flexbox;\n display: -webkit-flex;\n display: flex;\n flex-direction: column;\n left: 0;\n width: 500px;\n }\n #subsuites .subsuite {\n border: 0;\n width: 100%;\n height: 100%;\n }\n #mocha .test.pass .duration {\n color: #555 !important;\n }\n"; document.head.appendChild(style); }); unwrapExports(html); var parsing = createCommonjsModule(function (module, exports) { /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * * This code may only be used under the BSD style license found at * polymer.github.io/LICENSE.txt The complete set of authors may be found at * polymer.github.io/AUTHORS.txt The complete set of contributors may be found * at polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of * the polymer project is also subject to an additional IP rights grant found at * polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); function parse(stack) { var rawLines = stack.split('\n'); var stackyLines = compact(rawLines.map(parseStackyLine)); if (stackyLines.length === rawLines.length) { return stackyLines; } var v8Lines = compact(rawLines.map(parseV8Line)); if (v8Lines.length > 0) { return v8Lines; } var geckoLines = compact(rawLines.map(parseGeckoLine)); if (geckoLines.length > 0) { return geckoLines; } throw new Error('Unknown stack format: ' + stack); } exports.parse = parse; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack var GECKO_LINE = /^(?:([^@]*)@)?(.*?):(\d+)(?::(\d+))?$/; function parseGeckoLine(line) { var match = line.match(GECKO_LINE); if (!match) { return null; } return { method: match[1] || '', location: match[2] || '', line: parseInt(match[3]) || 0, column: parseInt(match[4]) || 0, }; } exports.parseGeckoLine = parseGeckoLine; // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi var V8_OUTER1 = /^\s*(eval )?at (.*) \((.*)\)$/; var V8_OUTER2 = /^\s*at()() (\S+)$/; var V8_INNER = /^\(?([^\(]+):(\d+):(\d+)\)?$/; function parseV8Line(line) { var outer = line.match(V8_OUTER1) || line.match(V8_OUTER2); if (!outer) { return null; } var inner = outer[3].match(V8_INNER); if (!inner) { return null; } var method = outer[2] || ''; if (outer[1]) { method = 'eval at ' + method; } return { method: method, location: inner[1] || '', line: parseInt(inner[2]) || 0, column: parseInt(inner[3]) || 0, }; } exports.parseV8Line = parseV8Line; var STACKY_LINE = /^\s*(.+) at (.+):(\d+):(\d+)$/; function parseStackyLine(line) { var match = line.match(STACKY_LINE); if (!match) { return null; } return { method: match[1] || '', location: match[2] || '', line: parseInt(match[3]) || 0, column: parseInt(match[4]) || 0, }; } exports.parseStackyLine = parseStackyLine; // Helpers function compact(array) { var result = []; array.forEach(function (value) { return value && result.push(value); }); return result; } }); unwrapExports(parsing); var parsing_1 = parsing.parse; var parsing_2 = parsing.parseGeckoLine; var parsing_3 = parsing.parseV8Line; var parsing_4 = parsing.parseStackyLine; var formatting = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * * This code may only be used under the BSD style license found at * polymer.github.io/LICENSE.txt The complete set of authors may be found at * polymer.github.io/AUTHORS.txt The complete set of contributors may be found * at polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of * the polymer project is also subject to an additional IP rights grant found at * polymer.github.io/PATENTS.txt */ exports.defaults = { maxMethodPadding: 40, indent: '', methodPlaceholder: '<unknown>', locationStrip: [], unimportantLocation: [], filter: function () { return false; }, styles: { method: passthrough, location: passthrough, line: passthrough, column: passthrough, unimportant: passthrough, }, }; function pretty(stackOrParsed, maybeOptions) { var options = mergeDefaults(maybeOptions || {}, exports.defaults); var linesAndNulls = Array.isArray(stackOrParsed) ? stackOrParsed : parsing.parse(stackOrParsed); var lines = clean(linesAndNulls, options); var padSize = methodPadding(lines, options); var parts = lines.map(function (line) { var method = line.method || options.methodPlaceholder; var pad = options.indent + padding(padSize - method.length); var locationBits = [ options.styles.location(line.location), options.styles.line(line.line.toString()), ]; if ('column' in line) { locationBits.push(options.styles.column(line.column.toString())); } var location = locationBits.join(':'); var text = pad + options.styles.method(method) + ' at ' + location; if (!line.important) { text = options.styles.unimportant(text); } return text; }); return parts.join('\n'); } exports.pretty = pretty; function clean(lines, options) { var result = []; for (var i = 0, line = void 0; line = lines[i]; i++) { if (options.filter && options.filter(line)) { continue; } line.location = cleanLocation(line.location, options); line.important = isImportant(line, options); result.push(line); } return result; } // Utility function passthrough(text) { return text; } function mergeDefaults(options, defaults) { var result = Object.create(defaults); Object.keys(options).forEach(function (untypedKey) { var key = untypedKey; var value = options[key]; if (typeof value === 'object' && !Array.isArray(value)) { value = mergeDefaults(value, defaults[key]); } result[key] = value; }); return result; } function methodPadding(lines, options) { var size = (options.methodPlaceholder || '').length; for (var i = 0, line = void 0; line = lines[i]; i++) { size = Math.min(options.maxMethodPadding || Infinity, Math.max(size, line.method.length)); } return size; } function padding(length) { var result = ''; for (var i = 0; i < length; i++) { result = result + ' '; } return result; } function cleanLocation(location, options) { if (options.locationStrip) { for (var i = 0, matcher = void 0; matcher = options.locationStrip[i]; i++) { location = location.replace(matcher, ''); } } return location; } function isImportant(line, options) { if (options.unimportantLocation) { for (var i = 0, matcher = void 0; matcher = options.unimportantLocation[i]; i++) { if (line.location.match(matcher)) { return false; } } } return true; } }); unwrapExports(formatting); var formatting_1 = formatting.defaults; var formatting_2 = formatting.pretty; var normalization = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @license * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. * * This code may only be used under the BSD style license found at * polymer.github.io/LICENSE.txt The complete set of authors may be found at * polymer.github.io/AUTHORS.txt The complete set of contributors may be found * at polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of * the polymer project is also subject to an additional IP rights grant found at * polymer.github.io/PATENTS.txt */ function normalize(error, prettyOptions) { if (error.parsedStack) { return error; } var message = error.message || error.description || error || '<unknown error>'; var parsedStack = []; try { parsedStack = parsing.parse(error.stack || error.to