UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

191 lines 29.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("lodash"); const pinkie_1 = __importDefault(require("pinkie")); const compiler_1 = __importDefault(require("../compiler")); const connection_1 = __importDefault(require("../browser/connection")); const runtime_1 = require("../errors/runtime"); const pool_1 = __importDefault(require("../browser/provider/pool")); const types_1 = require("../errors/types"); const browser_set_1 = __importDefault(require("./browser-set")); const tested_app_1 = __importDefault(require("./tested-app")); const parse_file_list_1 = __importDefault(require("../utils/parse-file-list")); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const make_dir_1 = __importDefault(require("make-dir")); const resolve_path_relatively_cwd_1 = __importDefault(require("../utils/resolve-path-relatively-cwd")); class Bootstrapper { constructor(browserConnectionGateway) { this.browserConnectionGateway = browserConnectionGateway; this.concurrency = null; this.sources = []; this.browsers = []; this.reporters = []; this.filter = null; this.appCommand = null; this.appInitDelay = null; this.tsConfigPath = null; } static _splitBrowserInfo(browserInfo) { const remotes = []; const automated = []; browserInfo.forEach(browser => { if (browser instanceof connection_1.default) remotes.push(browser); else automated.push(browser); }); return { remotes, automated }; } async _getBrowserInfo() { if (!this.browsers.length) throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserNotSet); const browserInfo = await pinkie_1.default.all(this.browsers.map(browser => pool_1.default.getBrowserInfo(browser))); return lodash_1.flatten(browserInfo); } _createAutomatedConnections(browserInfo) { if (!browserInfo) return []; return browserInfo .map(browser => lodash_1.times(this.concurrency, () => new connection_1.default(this.browserConnectionGateway, browser))); } async _getBrowserConnections(browserInfo) { const { automated, remotes } = Bootstrapper._splitBrowserInfo(browserInfo); if (remotes && remotes.length % this.concurrency) throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotDivideRemotesCountByConcurrency); let browserConnections = this._createAutomatedConnections(automated); browserConnections = browserConnections.concat(lodash_1.chunk(remotes, this.concurrency)); return await browser_set_1.default.from(browserConnections); } async _getTests() { if (!this.sources.length) throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testSourcesNotSet); const { parsedFileList, compilerOptions } = await this._getCompilerArguments(); const compiler = new compiler_1.default(parsedFileList, compilerOptions); let tests = await compiler.getTests(); const testsWithOnlyFlag = tests.filter(test => test.only); if (testsWithOnlyFlag.length) tests = testsWithOnlyFlag; if (this.filter) tests = tests.filter(test => this.filter(test.name, test.fixture.name, test.fixture.path, test.meta, test.fixture.meta)); if (!tests.length) throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRun); return tests; } async _getCompilerArguments() { const parsedFileList = await parse_file_list_1.default(this.sources, process.cwd()); const compilerOptions = { typeScriptOptions: { tsConfigPath: this.tsConfigPath } }; return { parsedFileList, compilerOptions }; } async _ensureOutStream(outStream) { if (typeof outStream !== 'string') return outStream; const fullReporterOutputPath = resolve_path_relatively_cwd_1.default(outStream); await make_dir_1.default(path_1.default.dirname(fullReporterOutputPath)); return fs_1.default.createWriteStream(fullReporterOutputPath); } static _addDefaultReporter(reporters) { reporters.push({ name: 'spec', file: process.stdout }); } async _getReporterPlugins() { const stdoutReporters = lodash_1.filter(this.reporters, r => lodash_1.isUndefined(r.output) || r.output === process.stdout); if (stdoutReporters.length > 1) throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleStdoutReporters, stdoutReporters.map(r => r.name).join(', ')); if (!this.reporters.length) Bootstrapper._addDefaultReporter(this.reporters); return pinkie_1.default.all(this.reporters.map(async ({ name, output }) => { let pluginFactory = name; let pluginName = null; const outStream = await this._ensureOutStream(output); if (typeof pluginFactory !== 'function') { try { pluginFactory = require('testcafe-reporter-' + name); pluginName = name; } catch (err) { throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotFindReporterForAlias, name); } } const plugin = pluginFactory(); plugin.name = pluginName; return { plugin, outStream }; })); } async _startTestedApp() { if (this.appCommand) { const testedApp = new tested_app_1.default(); await testedApp.start(this.appCommand, this.appInitDelay); return testedApp; } return null; } async _canUseParallelBootstrapping(browserInfo) { const isLocalPromises = browserInfo.map(browser => browser.provider.isLocalBrowser(null, browserInfo.browserName)); const isLocalBrowsers = await pinkie_1.default.all(isLocalPromises); return isLocalBrowsers.every(result => result); } async _bootstrapSequence(browserInfo) { const tests = await this._getTests(); const testedApp = await this._startTestedApp(); const browserSet = await this._getBrowserConnections(browserInfo); return { tests, testedApp, browserSet }; } _wrapBootstrappingPromise(promise) { return promise .then(result => ({ error: null, result })) .catch(error => ({ result: null, error })); } async _handleBootstrappingError([browserSetStatus, testsStatus, testedAppStatus]) { if (!browserSetStatus.error) await browserSetStatus.result.dispose(); if (!testedAppStatus.error && testedAppStatus.result) await testedAppStatus.result.kill(); if (testsStatus.error) throw testsStatus.error; else if (testedAppStatus.error) throw testedAppStatus.error; else throw browserSetStatus.error; } async _bootstrapParallel(browserInfo) { let bootstrappingPromises = [ this._getBrowserConnections(browserInfo), this._getTests(), this._startTestedApp() ]; bootstrappingPromises = bootstrappingPromises.map(promise => this._wrapBootstrappingPromise(promise)); const bootstrappingStatuses = await pinkie_1.default.all(bootstrappingPromises); if (bootstrappingStatuses.some(status => status.error)) await this._handleBootstrappingError(bootstrappingStatuses); const [browserSet, tests, testedApp] = bootstrappingStatuses.map(status => status.result); return { browserSet, tests, testedApp }; } // API async createRunnableConfiguration() { const reporterPlugins = await this._getReporterPlugins(); // NOTE: If a user forgot to specify a browser, but has specified a path to tests, the specified path will be // considered as the browser argument, and the tests path argument will have the predefined default value. // It's very ambiguous for the user, who might be confused by compilation errors from an unexpected test. // So, we need to retrieve the browser aliases and paths before tests compilation. const browserInfo = await this._getBrowserInfo(); if (await this._canUseParallelBootstrapping(browserInfo)) return Object.assign({ reporterPlugins }, await this._bootstrapParallel(browserInfo)); return Object.assign({ reporterPlugins }, await this._bootstrapSequence(browserInfo)); } } exports.default = Bootstrapper; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bm5lci9ib290c3RyYXBwZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxtQ0FBb0U7QUFDcEUsb0RBQTZCO0FBQzdCLDJEQUFtQztBQUNuQyx1RUFBc0Q7QUFDdEQsK0NBQWlEO0FBQ2pELG9FQUEyRDtBQUMzRCwyQ0FBaUQ7QUFDakQsZ0VBQXVDO0FBQ3ZDLDhEQUFxQztBQUNyQywrRUFBcUQ7QUFDckQsZ0RBQXdCO0FBQ3hCLDRDQUFvQjtBQUNwQix3REFBK0I7QUFDL0IsdUdBQTRFO0FBRTVFLE1BQXFCLFlBQVk7SUFDN0IsWUFBYSx3QkFBd0I7UUFDakMsSUFBSSxDQUFDLHdCQUF3QixHQUFHLHdCQUF3QixDQUFDO1FBRXpELElBQUksQ0FBQyxXQUFXLEdBQUksSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQVEsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxRQUFRLEdBQU8sRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLEdBQU0sRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLEdBQVMsSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxVQUFVLEdBQUssSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO0lBQzdCLENBQUM7SUFFRCxNQUFNLENBQUMsaUJBQWlCLENBQUUsV0FBVztRQUNqQyxNQUFNLE9BQU8sR0FBSyxFQUFFLENBQUM7UUFDckIsTUFBTSxTQUFTLEdBQUcsRUFBRSxDQUFDO1FBRXJCLFdBQVcsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7WUFDMUIsSUFBSSxPQUFPLFlBQVksb0JBQWlCO2dCQUNwQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDOztnQkFFdEIsU0FB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TSxJQUFJLENBQUMseUJBQXlCLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUVoRSxNQUFNLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxTQUFTLENBQUMsR0FBRyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFMUYsT0FBTyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUM7SUFDNUMsQ0FBQztJQUVELE1BQU07SUFDTixLQUFLLENBQUMsMkJBQTJCO1FBQzdCLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFFekQsNkdBQTZHO1FBQzdHLDBHQUEwRztRQUMxRyx5R0FBeUc7UUFDekcsa0ZBQWtGO1FBQ2xGLE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBRWpELElBQUksTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQUMsV0FBVyxDQUFDO1lBQ3BELHVCQUFTLGVBQWUsSUFBSyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsRUFBRztRQUU5RSx1QkFBUyxlQUFlLElBQUssTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxDQUFDLEVBQUc7SUFDOUUsQ0FBQztDQUNKO0FBck9ELCtCQXFPQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzVW5kZWZpbmVkLCBmaWx0ZXIsIGZsYXR0ZW4sIGNodW5rLCB0aW1lcyB9IGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgUHJvbWlzZSBmcm9tICdwaW5raWUnO1xuaW1wb3J0IENvbXBpbGVyIGZyb20gJy4uL2NvbXBpbGVyJztcbmltcG9ydCBCcm93c2VyQ29ubmVjdGlvbiBmcm9tICcuLi9icm93c2VyL2Nvbm5lY3Rpb24nO1xuaW1wb3J0IHsgR2VuZXJhbEVycm9yIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUnO1xuaW1wb3J0IGJyb3dzZXJQcm92aWRlclBvb2wgZnJvbSAnLi4vYnJvd3Nlci9wcm92aWRlci9wb29sJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcbmltcG9ydCBCcm93c2VyU2V0IGZyb20gJy4vYnJvd3Nlci1zZXQnO1xuaW1wb3J0IFRlc3RlZEFwcCBmcm9tICcuL3Rlc3RlZC1hcHAnO1xuaW1wb3J0IHBhcnNlRmlsZUxpc3QgZnJvbSAnLi4vdXRpbHMvcGFyc2UtZmlsZS1saXN0JztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCBtYWtlRGlyIGZyb20gJ21ha2UtZGlyJztcbmltcG9ydCByZXNvbHZlUGF0aFJlbGF0aXZlbHlDd2QgZnJvbSAnLi4vdXRpbHMvcmVzb2x2ZS1wYXRoLXJlbGF0aXZlbHktY3dkJztcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQm9vdHN0cmFwcGVyIHtcbiAgICBjb25zdHJ1Y3RvciAoYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5KSB7XG4gICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5ID0gYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5O1xuXG4gICAgICAgIHRoaXMuY29uY3VycmVuY3kgID0gbnVsbDtcbiAgICAgICAgdGhpcy5zb3VyY2VzICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5icm93c2VycyAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5yZXBvcnRlcnMgICAgPSBbXTtcbiAgICAgICAgdGhpcy5maWx0ZXIgICAgICAgPSBudWxsO1xuICAgICAgICB0aGlzLmFwcENvbW1hbmQgICA9IG51bGw7XG4gICAgICAgIHRoaXMuYXBwSW5pdERlbGF5ID0gbnVsbDtcbiAgICAgICAgdGhpcy50c0NvbmZpZ1BhdGggPSBudWxsO1xuICAgIH1cblxuICAgIHN0YXRpYyBfc3BsaXRCcm93c2VySW5mbyAoYnJvd3NlckluZm8pIHtcbiAgICAgICAgY29uc3QgcmVtb3RlcyAgID0gW107XG4gICAgICAgIGNvbnN0IGF1dG9tYXRlZCA9IFtdO1xuXG4gICAgICAgIGJyb3dzZXJJbmZvLmZvckVhY2goYnJvd3NlciA9PiB7XG4gICAgICAgICAgICBpZiAoYnJvd3NlciBpbnN0YW5jZW9mIEJyb3dzZXJDb25uZWN0aW9uKVxuICAgICAgICAgICAgICAgIHJlbW90ZXMucHVzaChicm93c2VyKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBhdXRvbWF0ZWQucHVzaChicm93c2VyKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHsgcmVtb3RlcywgYXV0b21hdGVkIH07XG4gICAgfVxuXG4gICAgYXN5bmMgX2dldEJyb3dzZXJJbmZvICgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmJyb3dzZXJzLmxlbmd0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuYnJvd3Nlck5vdFNldCk7XG5cbiAgICAgICAgY29uc3QgYnJvd3NlckluZm8gPSBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmJyb3dzZXJzLm1hcChicm93c2VyID0+IGJyb3dzZXJQcm92aWRlclBvb2wuZ2V0QnJvd3NlckluZm8oYnJvd3NlcikpKTtcblxuICAgICAgICByZXR1cm4gZmxhdHRlbihicm93c2VySW5mbyk7XG4gICAgfVxuXG4gICAgX2NyZWF0ZUF1dG9tYXRlZENvbm5lY3Rpb25zIChicm93c2VySW5mbykge1xuICAgICAgICBpZiAoIWJyb3dzZXJJbmZvKVxuICAgICAgICAgICAgcmV0dXJuIFtdO1xuXG4gICAgICAgIHJldHVybiBicm93c2VySW5mb1xuICAgICAgICAgICAgLm1hcChicm93c2VyID0+IHRpbWVzKHRoaXMuY29uY3VycmVuY3ksICgpID0+IG5ldyBCcm93c2VyQ29ubmVjdGlvbih0aGlzLmJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSwgYnJvd3NlcikpKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZ2V0QnJvd3NlckNvbm5lY3Rpb25zIChicm93c2VySW5mbykge1xuICAgICAgICBjb25zdCB7IGF1dG9tYXRlZCwgcmVtb3RlcyB9ID0gQm9vdHN0cmFwcGVyLl9zcGxpdEJyb3dzZXJJbmZvKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICBpZiAocmVtb3RlcyAmJiByZW1vdGVzLmxlbmd0aCAlIHRoaXMuY29uY3VycmVuY3kpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdERpdmlkZVJlbW90ZXNDb3VudEJ5Q29uY3VycmVuY3kpO1xuXG4gICAgICAgIGxldCBicm93c2VyQ29ubmVjdGlvbnMgPSB0aGlzLl9jcmVhdGVBdXRvbWF0ZWRDb25uZWN0aW9ucyhhdXRvbWF0ZWQpO1xuXG4gICAgICAgIGJyb3dzZXJDb25uZWN0aW9ucyA9IGJyb3dzZXJDb25uZWN0aW9ucy5jb25jYXQoY2h1bmsocmVtb3RlcywgdGhpcy5jb25jdXJyZW5jeSkpO1xuXG4gICAgICAgIHJldHVybiBhd2FpdCBCcm93c2VyU2V0LmZyb20oYnJvd3NlckNvbm5lY3Rpb25zKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZ2V0VGVzdHMgKCkge1xuICAgICAgICBpZiAoIXRoaXMuc291cmNlcy5sZW5ndGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLnRlc3RTb3VyY2VzTm90U2V0KTtcblxuICAgICAgICBjb25zdCB7IHBhcnNlZEZpbGVMaXN0LCBjb21waWxlck9wdGlvbnMgfSA9IGF3YWl0IHRoaXMuX2dldENvbXBpbGVyQXJndW1lbnRzKCk7XG5cbiAgICAgICAgY29uc3QgY29tcGlsZXIgPSBuZXcgQ29tcGlsZXIocGFyc2VkRmlsZUxpc3QsIGNvbXBpbGVyT3B0aW9ucyk7XG4gICAgICAgIGxldCB0ZXN0cyAgICAgID0gYXdhaXQgY29tcGlsZXIuZ2V0VGVzdHMoKTtcblxuICAgICAgICBjb25zdCB0ZXN0c1dpdGhPbmx5RmxhZyA9IHRlc3RzLmZpbHRlcih0ZXN0ID0+IHRlc3Qub25seSk7XG5cbiAgICAgICAgaWYgKHRlc3RzV2l0aE9ubHlGbGFnLmxlbmd0aClcbiAgICAgICAgICAgIHRlc3RzID0gdGVzdHNXaXRoT25seUZsYWc7XG5cbiAgICAgICAgaWYgKHRoaXMuZmlsdGVyKVxuICAgICAgICAgICAgdGVzdHMgPSB0ZXN0cy5maWx0ZXIodGVzdCA9PiB0aGlzLmZpbHRlcih0ZXN0Lm5hbWUsIHRlc3QuZml4dHVyZS5uYW1lLCB0ZXN0LmZpeHR1cmUucGF0aCwgdGVzdC5tZXRhLCB0ZXN0LmZpeHR1cmUubWV0YSkpO1xuXG4gICAgICAgIGlmICghdGVzdHMubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5ub1Rlc3RzVG9SdW4pO1xuXG4gICAgICAgIHJldHVybiB0ZXN0cztcbiAgICB9XG5cbiAgICBhc3luYyBfZ2V0Q29tcGlsZXJBcmd1bWVudHMgKCkge1xuICAgICAgICBjb25zdCBwYXJzZWRGaWxlTGlzdCA9IGF3YWl0IHBhcnNlRmlsZUxpc3QodGhpcy5zb3VyY2VzLCBwcm9jZXNzLmN3ZCgpKTtcblxuICAgICAgICBjb25zdCBjb21waWxlck9wdGlvbnMgPSB7XG4gICAgICAgICAgICB0eXBlU2NyaXB0T3B0aW9uczoge1xuICAgICAgICAgICAgICAgIHRzQ29uZmlnUGF0aDogdGhpcy50c0NvbmZpZ1BhdGhcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4geyBwYXJzZWRGaWxlTGlzdCwgY29tcGlsZXJPcHRpb25zIH07XG4gICAgfVxuXG4gICAgYXN5bmMgX2Vuc3VyZU91dFN0cmVhbSAob3V0U3RyZWFtKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb3V0U3RyZWFtICE9PSAnc3RyaW5nJylcbiAgICAgICAgICAgIHJldHVybiBvdXRTdHJlYW07XG5cbiAgICAgICAgY29uc3QgZnVsbFJlcG9ydGVyT3V0cHV0UGF0aCA9IHJlc29sdmVQYXRoUmVsYXRpdmVseUN3ZChvdXRTdHJlYW0pO1xuXG4gICAgICAgIGF3YWl0IG1ha2VEaXIocGF0aC5kaXJuYW1lKGZ1bGxSZXBvcnRlck91dHB1dFBhdGgpKTtcblxuICAgICAgICByZXR1cm4gZnMuY3JlYXRlV3JpdGVTdHJlYW0oZnVsbFJlcG9ydGVyT3V0cHV0UGF0aCk7XG4gICAgfVxuXG4gICAgc3RhdGljIF9hZGREZWZhdWx0UmVwb3J0ZXIgKHJlcG9ydGVycykge1xuICAgICAgICByZXBvcnRlcnMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiAnc3BlYycsXG4gICAgICAgICAgICBmaWxlOiBwcm9jZXNzLnN0ZG91dFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBhc3luYyBfZ2V0UmVwb3J0ZXJQbHVnaW5zICgpIHtcbiAgICAgICAgY29uc3Qgc3Rkb3V0UmVwb3J0ZXJzID0gZmlsdGVyKHRoaXMucmVwb3J0ZXJzLCByID0+IGlzVW5kZWZpbmVkKHIub3V0cHV0KSB8fCByLm91dHB1dCA9PT0gcHJvY2Vzcy5zdGRvdXQpO1xuXG4gICAgICAgIGlmIChzdGRvdXRSZXBvcnRlcnMubGVuZ3RoID4gMSlcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMubXVsdGlwbGVTdGRvdXRSZXBvcnRlcnMsIHN0ZG91dFJlcG9ydGVycy5tYXAociA9PiByLm5hbWUpLmpvaW4oJywgJykpO1xuXG4gICAgICAgIGlmICghdGhpcy5yZXBvcnRlcnMubGVuZ3RoKVxuICAgICAgICAgICAgQm9vdHN0cmFwcGVyLl9hZGREZWZhdWx0UmVwb3J0ZXIodGhpcy5yZXBvcnRlcnMpO1xuXG4gICAgICAgIHJldHVybiBQcm9taXNlLmFsbCh0aGlzLnJlcG9ydGVycy5tYXAoYXN5bmMgKHsgbmFtZSwgb3V0cHV0IH0pID0+IHtcbiAgICAgICAgICAgIGxldCBwbHVnaW5GYWN0b3J5ID0gbmFtZTtcbiAgICAgICAgICAgIGxldCBwbHVnaW5OYW1lICAgID0gbnVsbDtcblxuICAgICAgICAgICAgY29uc3Qgb3V0U3RyZWFtID0gYXdhaXQgdGhpcy5fZW5zdXJlT3V0U3RyZWFtKG91dHB1dCk7XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGx1Z2luRmFjdG9yeSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIHBsdWdpbkZhY3RvcnkgPSByZXF1aXJlKCd0ZXN0Y2FmZS1yZXBvcnRlci0nICsgbmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIHBsdWdpbk5hbWUgICAgPSBuYW1lO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RmluZFJlcG9ydGVyRm9yQWxpYXMsIG5hbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcGx1Z2luID0gcGx1Z2luRmFjdG9yeSgpO1xuXG4gICAgICAgICAgICBwbHVnaW4ubmFtZSA9IHBsdWdpbk5hbWU7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcGx1Z2luLFxuICAgICAgICAgICAgICAgIG91dFN0cmVhbVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSkpO1xuICAgIH1cblxuICAgIGFzeW5jIF9zdGFydFRlc3RlZEFwcCAoKSB7XG4gICAgICAgIGlmICh0aGlzLmFwcENvbW1hbmQpIHtcbiAgICAgICAgICAgIGNvbnN0IHRlc3RlZEFwcCA9IG5ldyBUZXN0ZWRBcHAoKTtcblxuICAgICAgICAgICAgYXdhaXQgdGVzdGVkQXBwLnN0YXJ0KHRoaXMuYXBwQ29tbWFuZCwgdGhpcy5hcHBJbml0RGVsYXkpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGVzdGVkQXBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgYXN5bmMgX2NhblVzZVBhcmFsbGVsQm9vdHN0cmFwcGluZyAoYnJvd3NlckluZm8pIHtcbiAgICAgICAgY29uc3QgaXNMb2NhbFByb21pc2VzID0gYnJvd3NlckluZm8ubWFwKGJyb3dzZXIgPT4gYnJvd3Nlci5wcm92aWRlci5pc0xvY2FsQnJvd3NlcihudWxsLCBicm93c2VySW5mby5icm93c2VyTmFtZSkpO1xuICAgICAgICBjb25zdCBpc0xvY2FsQnJvd3NlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChpc0xvY2FsUHJvbWlzZXMpO1xuXG4gICAgICAgIHJldHVybiBpc0xvY2FsQnJvd3NlcnMuZXZlcnkocmVzdWx0ID0+IHJlc3VsdCk7XG4gICAgfVxuXG4gICAgYXN5bmMgX2Jvb3RzdHJhcFNlcXVlbmNlIChicm93c2VySW5mbykge1xuICAgICAgICBjb25zdCB0ZXN0cyAgICAgICA9IGF3YWl0IHRoaXMuX2dldFRlc3RzKCk7XG4gICAgICAgIGNvbnN0IHRlc3RlZEFwcCAgID0gYXdhaXQgdGhpcy5fc3RhcnRUZXN0ZWRBcHAoKTtcbiAgICAgICAgY29uc3QgYnJvd3NlclNldCAgPSBhd2FpdCB0aGlzLl9nZXRCcm93c2VyQ29ubmVjdGlvbnMoYnJvd3NlckluZm8pO1xuXG4gICAgICAgIHJldHVybiB7IHRlc3RzLCB0ZXN0ZWRBcHAsIGJyb3dzZXJTZXQgfTtcbiAgICB9XG5cbiAgICBfd3JhcEJvb3RzdHJhcHBpbmdQcm9taXNlIChwcm9taXNlKSB7XG4gICAgICAgIHJldHVybiBwcm9taXNlXG4gICAgICAgICAgICAudGhlbihyZXN1bHQgPT4gKHsgZXJyb3I6IG51bGwsIHJlc3VsdCB9KSlcbiAgICAgICAgICAgIC5jYXRjaChlcnJvciA9PiAoeyByZXN1bHQ6IG51bGwsIGVycm9yIH0pKTtcbiAgICB9XG5cbiAgICBhc3luYyBfaGFuZGxlQm9vdHN0cmFwcGluZ0Vycm9yIChbYnJvd3NlclNldFN0YXR1cywgdGVzdHNTdGF0dXMsIHRlc3RlZEFwcFN0YXR1c10pIHtcbiAgICAgICAgaWYgKCFicm93c2VyU2V0U3RhdHVzLmVycm9yKVxuICAgICAgICAgICAgYXdhaXQgYnJvd3NlclNldFN0YXR1cy5yZXN1bHQuZGlzcG9zZSgpO1xuXG4gICAgICAgIGlmICghdGVzdGVkQXBwU3RhdHVzLmVycm9yICYmIHRlc3RlZEFwcFN0YXR1cy5yZXN1bHQpXG4gICAgICAgICAgICBhd2FpdCB0ZXN0ZWRBcHBTdGF0dXMucmVzdWx0LmtpbGwoKTtcblxuICAgICAgICBpZiAodGVzdHNTdGF0dXMuZXJyb3IpXG4gICAgICAgICAgICB0aHJvdyB0ZXN0c1N0YXR1cy5lcnJvcjtcbiAgICAgICAgZWxzZSBpZiAodGVzdGVkQXBwU3RhdHVzLmVycm9yKVxuICAgICAgICAgICAgdGhyb3cgdGVzdGVkQXBwU3RhdHVzLmVycm9yO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICB0aHJvdyBicm93c2VyU2V0U3RhdHVzLmVycm9yO1xuICAgIH1cblxuICAgIGFzeW5jIF9ib290c3RyYXBQYXJhbGxlbCAoYnJvd3NlckluZm8pIHtcbiAgICAgICAgbGV0IGJvb3RzdHJhcHBpbmdQcm9taXNlcyA9IFtcbiAgICAgICAgICAgIHRoaXMuX2dldEJyb3dzZXJDb25uZWN0aW9ucyhicm93c2VySW5mbyksXG4gICAgICAgICAgICB0aGlzLl9nZXRUZXN0cygpLFxuICAgICAgICAgICAgdGhpcy5fc3RhcnRUZXN0ZWRBcHAoKVxuICAgICAgICBdO1xuXG4gICAgICAgIGJvb3RzdHJhcHBpbmdQcm9taXNlcyA9IGJvb3RzdHJhcHBpbmdQcm9taXNlcy5tYXAocHJvbWlzZSA9PiB0aGlzLl93cmFwQm9vdHN0cmFwcGluZ1Byb21pc2UocHJvbWlzZSkpO1xuXG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdTdGF0dXNlcyA9IGF3YWl0IFByb21pc2UuYWxsKGJvb3RzdHJhcHBpbmdQcm9taXNlcyk7XG5cbiAgICAgICAgaWYgKGJvb3RzdHJhcHBpbmdTdGF0dXNlcy5zb21lKHN0YXR1cyA9PiBzdGF0dXMuZXJyb3IpKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5faGFuZGxlQm9vdHN0cmFwcGluZ0Vycm9yKGJvb3RzdHJhcHBpbmdTdGF0dXNlcyk7XG5cbiAgICAgICAgY29uc3QgW2Jyb3dzZXJTZXQsIHRlc3RzLCB0ZXN0ZWRBcHBdID0gYm9vdHN0cmFwcGluZ1N0YXR1c2VzLm1hcChzdGF0dXMgPT4gc3RhdHVzLnJlc3VsdCk7XG5cbiAgICAgICAgcmV0dXJuIHsgYnJvd3NlclNldCwgdGVzdHMsIHRlc3RlZEFwcCB9O1xuICAgIH1cblxuICAgIC8vIEFQSVxuICAgIGFzeW5jIGNyZWF0ZVJ1bm5hYmxlQ29uZmlndXJhdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHJlcG9ydGVyUGx1Z2lucyA9IGF3YWl0IHRoaXMuX2dldFJlcG9ydGVyUGx1Z2lucygpO1xuXG4gICAgICAgIC8vIE5PVEU6IElmIGEgdXNlciBmb3Jnb3QgdG8gc3BlY2lmeSBhIGJyb3dzZXIsIGJ1dCBoYXMgc3BlY2lmaWVkIGEgcGF0aCB0byB0ZXN0cywgdGhlIHNwZWNpZmllZCBwYXRoIHdpbGwgYmVcbiAgICAgICAgLy8gY29uc2lkZXJlZCBhcyB0aGUgYnJvd3NlciBhcmd1bWVudCwgYW5kIHRoZSB0ZXN0cyBwYXRoIGFyZ3VtZW50IHdpbGwgaGF2ZSB0aGUgcHJlZGVmaW5lZCBkZWZhdWx0IHZhbHVlLlxuICAgICAgICAvLyBJdCdzIHZlcnkgYW1iaWd1b3VzIGZvciB0aGUgdXNlciwgd2hvIG1pZ2h0IGJlIGNvbmZ1c2VkIGJ5IGNvbXBpbGF0aW9uIGVycm9ycyBmcm9tIGFuIHVuZXhwZWN0ZWQgdGVzdC5cbiAgICAgICAgLy8gU28sIHdlIG5lZWQgdG8gcmV0cmlldmUgdGhlIGJyb3dzZXIgYWxpYXNlcyBhbmQgcGF0aHMgYmVmb3JlIHRlc3RzIGNvbXBpbGF0aW9uLlxuICAgICAgICBjb25zdCBicm93c2VySW5mbyA9IGF3YWl0IHRoaXMuX2dldEJyb3dzZXJJbmZvKCk7XG5cbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuX2NhblVzZVBhcmFsbGVsQm9vdHN0cmFwcGluZyhicm93c2VySW5mbykpXG4gICAgICAgICAgICByZXR1cm4geyByZXBvcnRlclBsdWdpbnMsIC4uLmF3YWl0IHRoaXMuX2Jvb3RzdHJhcFBhcmFsbGVsKGJyb3dzZXJJbmZvKSB9O1xuXG4gICAgICAgIHJldHVybiB7IHJlcG9ydGVyUGx1Z2lucywgLi4uYXdhaXQgdGhpcy5fYm9vdHN0cmFwU2VxdWVuY2UoYnJvd3NlckluZm8pIH07XG4gICAgfVxufVxuIl19