UNPKG

creevey

Version:

creevey is a tool for automated visual testing, that tightly integrated with storybook

212 lines (169 loc) 27.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = worker; var _util = require("util"); var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _chai = _interopRequireDefault(require("chai")); var _chalk = _interopRequireDefault(require("chalk")); var _mocha = _interopRequireWildcard(require("mocha")); var _seleniumWebdriver = require("selenium-webdriver"); var _types = require("../../types"); var _selenium = require("../../selenium"); var _chaiImage = _interopRequireDefault(require("../../chai-image")); var _reporter = require("./reporter"); var _helpers = require("./helpers"); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const statAsync = (0, _util.promisify)(_fs.default.stat); const readdirAsync = (0, _util.promisify)(_fs.default.readdir); const readFileAsync = (0, _util.promisify)(_fs.default.readFile); const writeFileAsync = (0, _util.promisify)(_fs.default.writeFile); const mkdirAsync = (0, _util.promisify)(_fs.default.mkdir); async function getStat(filePath) { try { return await statAsync(filePath); } catch (error) { if (error.code === 'ENOENT') { return null; } throw error; } } async function getLastImageNumber(imageDir, imageName) { const actualImagesRegexp = new RegExp(`${imageName}-actual-(\\d+)\\.png`); try { var _await$readdirAsync$m; return (_await$readdirAsync$m = (await readdirAsync(imageDir)).map(filename => filename.replace(actualImagesRegexp, '$1')).map(Number).filter(x => !isNaN(x)).sort((a, b) => b - a)[0]) !== null && _await$readdirAsync$m !== void 0 ? _await$readdirAsync$m : 0; } catch (_error) { return 0; } } // After end of each suite mocha clean all hooks and don't allow re-run tests without full re-init // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore see issue for more info https://github.com/mochajs/mocha/issues/2783 _mocha.Suite.prototype.cleanReferences = _types.noop; function patchMochaInterface(suite) { suite.on('pre-require', context => { // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore context.it.skip = (_browsers, title, fn) => context.it(title, fn); }); } // FIXME browser options hotfix async function worker(config, options) { let retries = 0; let images = {}; let error = null; const testScope = []; function runHandler(failures) { if (process.send) { if (failures > 0) { const isTimeout = typeof error == 'string' && error.toLowerCase().includes('timeout'); process.send(JSON.stringify({ type: isTimeout ? 'error' : 'test', payload: { status: 'failed', images, error } })); } else { process.send(JSON.stringify({ type: 'test', payload: { status: 'success', images } })); } } // TODO Should we move into `process.on`? images = {}; error = null; } async function getExpected(imageName) { // context => [kind, story, test, browser] // rootSuite -> kindSuite -> storyTest -> [browsers.png] // rootSuite -> kindSuite -> storySuite -> test -> [browsers.png] const testPath = [...testScope]; if (!imageName) imageName = testPath.pop(); const image = images[imageName] = images[imageName] || {}; const reportImageDir = _path.default.join(config.reportDir, ...testPath); const imageNumber = (await getLastImageNumber(reportImageDir, imageName)) + 1; const onCompare = async (actual, expect, diff) => { image.actual = `${imageName}-actual-${imageNumber}.png`; await mkdirAsync(reportImageDir, { recursive: true }); await writeFileAsync(_path.default.join(reportImageDir, image.actual), actual); if (!diff || !expect) return; image.expect = `${imageName}-expect-${imageNumber}.png`; image.diff = `${imageName}-diff-${imageNumber}.png`; await writeFileAsync(_path.default.join(reportImageDir, image.expect), expect); await writeFileAsync(_path.default.join(reportImageDir, image.diff), diff); }; const expectImageDir = _path.default.join(config.screenDir, ...testPath); const expectImageStat = await getStat(_path.default.join(expectImageDir, `${imageName}.png`)); if (!expectImageStat) return { expected: null, onCompare }; const expected = await readFileAsync(_path.default.join(expectImageDir, `${imageName}.png`)); return { expected, onCompare }; } const mochaOptions = { timeout: 30000, reporter: process.env.TEAMCITY_VERSION ? _reporter.TeamcityReporter : options.reporter || _reporter.CreeveyReporter, // eslint-disable-next-line @typescript-eslint/ban-ts-ignore //@ts-ignore Should update @types/mocha for new major release https://github.com/mochajs/mocha/releases/tag/v7.0.0 reporterOption: { reportDir: config.reportDir, topLevelSuite: options.browser, willRetry: () => retries < config.maxRetries, images: () => images } }; const mocha = new _mocha.default(mochaOptions); // TODO Move to beforeAll _chai.default.use((0, _chaiImage.default)(getExpected, config.diffOptions)); await (0, _helpers.addTestsFromStories)(mocha.suite, options.browser, config); const browserConfig = config.browsers[options.browser]; const browser = await (0, _selenium.getBrowser)(config, browserConfig); setInterval(() => { browser.getCurrentUrl().then(url => { if (options.debug) console.log((0, _chalk.default)`[{blue WORKER}{grey :${options.browser}:${process.pid}}] {grey current url} ${url}`); }); }, 10 * 1000); mocha.suite.beforeAll(function () { this.config = config; this.browser = browser; this.keys = _seleniumWebdriver.Key; this.expect = _chai.default.expect; this.browserName = options.browser; this.testScope = testScope; }); // TODO Handle story context mocha.suite.beforeEach(_selenium.switchStory); patchMochaInterface(mocha.suite); process.on('message', message => { const test = JSON.parse(message); retries = test.retries; const testPath = [...test.path].reverse().join(' ').replace(/[|\\{}()[\]^$+*?.-]/g, '\\$&'); mocha.grep(new RegExp(`^${testPath}$`)); const runner = mocha.run(runHandler); // TODO How handle browser corruption? runner.on('fail', (_test, reason) => error = reason instanceof Error ? reason.stack || reason.message : reason); }); console.log('[CreeveyWorker]:', `Ready ${options.browser}:${process.pid}`); if (process.send) { process.send(JSON.stringify({ type: 'ready' })); } process.on('disconnect', () => { Promise.race([new Promise(resolve => setTimeout(resolve, 10000)), browser.close()]).then(() => process.exit(0)); }); process.on('SIGINT', _types.noop); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2ZXIvd29ya2VyL3dvcmtlci50cyJdLCJuYW1lcyI6WyJzdGF0QXN5bmMiLCJmcyIsInN0YXQiLCJyZWFkZGlyQXN5bmMiLCJyZWFkZGlyIiwicmVhZEZpbGVBc3luYyIsInJlYWRGaWxlIiwid3JpdGVGaWxlQXN5bmMiLCJ3cml0ZUZpbGUiLCJta2RpckFzeW5jIiwibWtkaXIiLCJnZXRTdGF0IiwiZmlsZVBhdGgiLCJlcnJvciIsImNvZGUiLCJnZXRMYXN0SW1hZ2VOdW1iZXIiLCJpbWFnZURpciIsImltYWdlTmFtZSIsImFjdHVhbEltYWdlc1JlZ2V4cCIsIlJlZ0V4cCIsIm1hcCIsImZpbGVuYW1lIiwicmVwbGFjZSIsIk51bWJlciIsImZpbHRlciIsIngiLCJpc05hTiIsInNvcnQiLCJhIiwiYiIsIl9lcnJvciIsIlN1aXRlIiwicHJvdG90eXBlIiwiY2xlYW5SZWZlcmVuY2VzIiwibm9vcCIsInBhdGNoTW9jaGFJbnRlcmZhY2UiLCJzdWl0ZSIsIm9uIiwiY29udGV4dCIsIml0Iiwic2tpcCIsIl9icm93c2VycyIsInRpdGxlIiwiZm4iLCJ3b3JrZXIiLCJjb25maWciLCJvcHRpb25zIiwicmV0cmllcyIsImltYWdlcyIsInRlc3RTY29wZSIsInJ1bkhhbmRsZXIiLCJmYWlsdXJlcyIsInByb2Nlc3MiLCJzZW5kIiwiaXNUaW1lb3V0IiwidG9Mb3dlckNhc2UiLCJpbmNsdWRlcyIsIkpTT04iLCJzdHJpbmdpZnkiLCJ0eXBlIiwicGF5bG9hZCIsInN0YXR1cyIsImdldEV4cGVjdGVkIiwidGVzdFBhdGgiLCJwb3AiLCJpbWFnZSIsInJlcG9ydEltYWdlRGlyIiwicGF0aCIsImpvaW4iLCJyZXBvcnREaXIiLCJpbWFnZU51bWJlciIsIm9uQ29tcGFyZSIsImFjdHVhbCIsImV4cGVjdCIsImRpZmYiLCJyZWN1cnNpdmUiLCJleHBlY3RJbWFnZURpciIsInNjcmVlbkRpciIsImV4cGVjdEltYWdlU3RhdCIsImV4cGVjdGVkIiwibW9jaGFPcHRpb25zIiwidGltZW91dCIsInJlcG9ydGVyIiwiZW52IiwiVEVBTUNJVFlfVkVSU0lPTiIsIlRlYW1jaXR5UmVwb3J0ZXIiLCJDcmVldmV5UmVwb3J0ZXIiLCJyZXBvcnRlck9wdGlvbiIsInRvcExldmVsU3VpdGUiLCJicm93c2VyIiwid2lsbFJldHJ5IiwibWF4UmV0cmllcyIsIm1vY2hhIiwiTW9jaGEiLCJjaGFpIiwidXNlIiwiZGlmZk9wdGlvbnMiLCJicm93c2VyQ29uZmlnIiwiYnJvd3NlcnMiLCJzZXRJbnRlcnZhbCIsImdldEN1cnJlbnRVcmwiLCJ0aGVuIiwidXJsIiwiZGVidWciLCJjb25zb2xlIiwibG9nIiwicGlkIiwiYmVmb3JlQWxsIiwia2V5cyIsIktleSIsImJyb3dzZXJOYW1lIiwiYmVmb3JlRWFjaCIsInN3aXRjaFN0b3J5IiwibWVzc2FnZSIsInRlc3QiLCJwYXJzZSIsInJldmVyc2UiLCJncmVwIiwicnVubmVyIiwicnVuIiwiX3Rlc3QiLCJyZWFzb24iLCJFcnJvciIsInN0YWNrIiwiUHJvbWlzZSIsInJhY2UiLCJyZXNvbHZlIiwic2V0VGltZW91dCIsImNsb3NlIiwiZXhpdCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7Ozs7OztBQUVBLE1BQU1BLFNBQVMsR0FBRyxxQkFBVUMsWUFBR0MsSUFBYixDQUFsQjtBQUNBLE1BQU1DLFlBQVksR0FBRyxxQkFBVUYsWUFBR0csT0FBYixDQUFyQjtBQUNBLE1BQU1DLGFBQWEsR0FBRyxxQkFBVUosWUFBR0ssUUFBYixDQUF0QjtBQUNBLE1BQU1DLGNBQWMsR0FBRyxxQkFBVU4sWUFBR08sU0FBYixDQUF2QjtBQUNBLE1BQU1DLFVBQVUsR0FBRyxxQkFBVVIsWUFBR1MsS0FBYixDQUFuQjs7QUFFQSxlQUFlQyxPQUFmLENBQXVCQyxRQUF2QixFQUFnRTtBQUM5RCxNQUFJO0FBQ0YsV0FB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aEJELElBQUFBLE9BQU8sQ0FBQ0MsSUFBUixDQUFhSSxJQUFJLENBQUNDLFNBQUwsQ0FBZTtBQUFFQyxNQUFBQSxJQUFJLEVBQUU7QUFBUixLQUFmLENBQWI7QUFDRDs7QUFDRFAsRUFBQUEsT0FBTyxDQUFDZixFQUFSLENBQVcsWUFBWCxFQUF5QixNQUFNO0FBQzdCdUYsSUFBQUEsT0FBTyxDQUFDQyxJQUFSLENBQWEsQ0FBQyxJQUFJRCxPQUFKLENBQWFFLE9BQUQsSUFBYUMsVUFBVSxDQUFDRCxPQUFELEVBQVUsS0FBVixDQUFuQyxDQUFELEVBQXVEckMsT0FBTyxDQUFDdUMsS0FBUixFQUF2RCxDQUFiLEVBQXNGM0IsSUFBdEYsQ0FBMkYsTUFBTWpELE9BQU8sQ0FBQzZFLElBQVIsQ0FBYSxDQUFiLENBQWpHO0FBQ0QsR0FGRDtBQUdBN0UsRUFBQUEsT0FBTyxDQUFDZixFQUFSLENBQVcsUUFBWCxFQUFxQkgsV0FBckI7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHByb21pc2lmeSB9IGZyb20gJ3V0aWwnO1xuaW1wb3J0IGZzLCB7IFN0YXRzIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgY2hhaSBmcm9tICdjaGFpJztcbmltcG9ydCBjaGFsayBmcm9tICdjaGFsayc7XG5pbXBvcnQgTW9jaGEsIHsgU3VpdGUsIENvbnRleHQsIEFzeW5jRnVuYywgTW9jaGFPcHRpb25zIH0gZnJvbSAnbW9jaGEnO1xuaW1wb3J0IHsgS2V5IH0gZnJvbSAnc2VsZW5pdW0td2ViZHJpdmVyJztcbmltcG9ydCB7IENvbmZpZywgSW1hZ2VzLCBPcHRpb25zLCBCcm93c2VyQ29uZmlnLCBub29wIH0gZnJvbSAnLi4vLi4vdHlwZXMnO1xuaW1wb3J0IHsgZ2V0QnJvd3Nlciwgc3dpdGNoU3RvcnkgfSBmcm9tICcuLi8uLi9zZWxlbml1bSc7XG5pbXBvcnQgY2hhaUltYWdlIGZyb20gJy4uLy4uL2NoYWktaW1hZ2UnO1xuaW1wb3J0IHsgQ3JlZXZleVJlcG9ydGVyLCBUZWFtY2l0eVJlcG9ydGVyIH0gZnJvbSAnLi9yZXBvcnRlcic7XG5pbXBvcnQgeyBhZGRUZXN0c0Zyb21TdG9yaWVzIH0gZnJvbSAnLi9oZWxwZXJzJztcblxuY29uc3Qgc3RhdEFzeW5jID0gcHJvbWlzaWZ5KGZzLnN0YXQpO1xuY29uc3QgcmVhZGRpckFzeW5jID0gcHJvbWlzaWZ5KGZzLnJlYWRkaXIpO1xuY29uc3QgcmVhZEZpbGVBc3luYyA9IHByb21pc2lmeShmcy5yZWFkRmlsZSk7XG5jb25zdCB3cml0ZUZpbGVBc3luYyA9IHByb21pc2lmeShmcy53cml0ZUZpbGUpO1xuY29uc3QgbWtkaXJBc3luYyA9IHByb21pc2lmeShmcy5ta2Rpcik7XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFN0YXQoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8U3RhdHMgfCBudWxsPiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHN0YXRBc3luYyhmaWxlUGF0aCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yLmNvZGUgPT09ICdFTk9FTlQnKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0TGFzdEltYWdlTnVtYmVyKGltYWdlRGlyOiBzdHJpbmcsIGltYWdlTmFtZTogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgY29uc3QgYWN0dWFsSW1hZ2VzUmVnZXhwID0gbmV3IFJlZ0V4cChgJHtpbWFnZU5hbWV9LWFjdHVhbC0oXFxcXGQrKVxcXFwucG5nYCk7XG5cbiAgdHJ5IHtcbiAgICByZXR1cm4gKFxuICAgICAgKGF3YWl0IHJlYWRkaXJBc3luYyhpbWFnZURpcikpXG4gICAgICAgIC5tYXAoKGZpbGVuYW1lKSA9PiBmaWxlbmFtZS5yZXBsYWNlKGFjdHVhbEltYWdlc1JlZ2V4cCwgJyQxJykpXG4gICAgICAgIC5tYXAoTnVtYmVyKVxuICAgICAgICAuZmlsdGVyKCh4KSA9PiAhaXNOYU4oeCkpXG4gICAgICAgIC5zb3J0KChhLCBiKSA9PiBiIC0gYSlbMF0gPz8gMFxuICAgICk7XG4gIH0gY2F0Y2ggKF9lcnJvcikge1xuICAgIHJldHVybiAwO1xuICB9XG59XG5cbi8vIEFmdGVyIGVuZCBvZiBlYWNoIHN1aXRlIG1vY2hhIGNsZWFuIGFsbCBob29rcyBhbmQgZG9uJ3QgYWxsb3cgcmUtcnVuIHRlc3RzIHdpdGhvdXQgZnVsbCByZS1pbml0XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1pZ25vcmVcbi8vIEB0cy1pZ25vcmUgc2VlIGlzc3VlIGZvciBtb3JlIGluZm8gaHR0cHM6Ly9naXRodWIuY29tL21vY2hhanMvbW9jaGEvaXNzdWVzLzI3ODNcblN1aXRlLnByb3RvdHlwZS5jbGVhblJlZmVyZW5jZXMgPSBub29wO1xuXG5mdW5jdGlvbiBwYXRjaE1vY2hhSW50ZXJmYWNlKHN1aXRlOiBTdWl0ZSk6IHZvaWQge1xuICBzdWl0ZS5vbigncHJlLXJlcXVpcmUnLCAoY29udGV4dCkgPT4ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXRzLWlnbm9yZVxuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBjb250ZXh0Lml0LnNraXAgPSAoX2Jyb3dzZXJzOiBzdHJpbmdbXSwgdGl0bGU6IHN0cmluZywgZm4/OiBBc3luY0Z1bmMpID0+IGNvbnRleHQuaXQodGl0bGUsIGZuKTtcbiAgfSk7XG59XG5cbi8vIEZJWE1FIGJyb3dzZXIgb3B0aW9ucyBob3RmaXhcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIHdvcmtlcihjb25maWc6IENvbmZpZywgb3B0aW9uczogT3B0aW9ucyAmIHsgYnJvd3Nlcjogc3RyaW5nIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgbGV0IHJldHJpZXMgPSAwO1xuICBsZXQgaW1hZ2VzOiBQYXJ0aWFsPHsgW25hbWU6IHN0cmluZ106IFBhcnRpYWw8SW1hZ2VzPiB9PiA9IHt9O1xuICBsZXQgZXJyb3I6IEVycm9yIHwge30gfCBzdHJpbmcgfCB1bmRlZmluZWQgfCBudWxsID0gbnVsbDtcbiAgY29uc3QgdGVzdFNjb3BlOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGZ1bmN0aW9uIHJ1bkhhbmRsZXIoZmFpbHVyZXM6IG51bWJlcik6IHZvaWQge1xuICAgIGlmIChwcm9jZXNzLnNlbmQpIHtcbiAgICAgIGlmIChmYWlsdXJlcyA+IDApIHtcbiAgICAgICAgY29uc3QgaXNUaW1lb3V0ID0gdHlwZW9mIGVycm9yID09ICdzdHJpbmcnICYmIGVycm9yLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoJ3RpbWVvdXQnKTtcbiAgICAgICAgcHJvY2Vzcy5zZW5kKFxuICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHsgdHlwZTogaXNUaW1lb3V0ID8gJ2Vycm9yJyA6ICd0ZXN0JywgcGF5bG9hZDogeyBzdGF0dXM6ICdmYWlsZWQnLCBpbWFnZXMsIGVycm9yIH0gfSksXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwcm9jZXNzLnNlbmQoSlNPTi5zdHJpbmdpZnkoeyB0eXBlOiAndGVzdCcsIHBheWxvYWQ6IHsgc3RhdHVzOiAnc3VjY2VzcycsIGltYWdlcyB9IH0pKTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gVE9ETyBTaG91bGQgd2UgbW92ZSBpbnRvIGBwcm9jZXNzLm9uYD9cbiAgICBpbWFnZXMgPSB7fTtcbiAgICBlcnJvciA9IG51bGw7XG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBnZXRFeHBlY3RlZChcbiAgICBpbWFnZU5hbWU/OiBzdHJpbmcsXG4gICk6IFByb21pc2U8XG4gICAgfCB7IGV4cGVjdGVkOiBCdWZmZXIgfCBudWxsOyBvbkNvbXBhcmU6IChhY3R1YWw6IEJ1ZmZlciwgZXhwZWN0PzogQnVmZmVyLCBkaWZmPzogQnVmZmVyKSA9PiBQcm9taXNlPHZvaWQ+IH1cbiAgICB8IEJ1ZmZlclxuICAgIHwgbnVsbFxuICA+IHtcbiAgICAvLyBjb250ZXh0ID0+IFtraW5kLCBzdG9yeSwgdGVzdCwgYnJvd3Nlcl1cbiAgICAvLyByb290U3VpdGUgLT4ga2luZFN1aXRlIC0+IHN0b3J5VGVzdCAtPiBbYnJvd3NlcnMucG5nXVxuICAgIC8vIHJvb3RTdWl0ZSAtPiBraW5kU3VpdGUgLT4gc3RvcnlTdWl0ZSAtPiB0ZXN0IC0+IFticm93c2Vycy5wbmddXG4gICAgY29uc3QgdGVzdFBhdGggPSBbLi4udGVzdFNjb3BlXTtcbiAgICBpZiAoIWltYWdlTmFtZSkgaW1hZ2VOYW1lID0gdGVzdFBhdGgucG9wKCkgYXMgc3RyaW5nO1xuXG4gICAgY29uc3QgaW1hZ2UgPSAoaW1hZ2VzW2ltYWdlTmFtZV0gPSBpbWFnZXNbaW1hZ2VOYW1lXSB8fCB7fSk7XG4gICAgY29uc3QgcmVwb3J0SW1hZ2VEaXIgPSBwYXRoLmpvaW4oY29uZmlnLnJlcG9ydERpciwgLi4udGVzdFBhdGgpO1xuICAgIGNvbnN0IGltYWdlTnVtYmVyID0gKGF3YWl0IGdldExhc3RJbWFnZU51bWJlcihyZXBvcnRJbWFnZURpciwgaW1hZ2VOYW1lKSkgKyAxO1xuICAgIGNvbnN0IG9uQ29tcGFyZSA9IGFzeW5jIChhY3R1YWw6IEJ1ZmZlciwgZXhwZWN0PzogQnVmZmVyLCBkaWZmPzogQnVmZmVyKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICBpbWFnZS5hY3R1YWwgPSBgJHtpbWFnZU5hbWV9LWFjdHVhbC0ke2ltYWdlTnVtYmVyfS5wbmdgO1xuICAgICAgYXdhaXQgbWtkaXJBc3luYyhyZXBvcnRJbWFnZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBhd2FpdCB3cml0ZUZpbGVBc3luYyhwYXRoLmpvaW4ocmVwb3J0SW1hZ2VEaXIsIGltYWdlLmFjdHVhbCksIGFjdHVhbCk7XG5cbiAgICAgIGlmICghZGlmZiB8fCAhZXhwZWN0KSByZXR1cm47XG5cbiAgICAgIGltYWdlLmV4cGVjdCA9IGAke2ltYWdlTmFtZX0tZXhwZWN0LSR7aW1hZ2VOdW1iZXJ9LnBuZ2A7XG4gICAgICBpbWFnZS5kaWZmID0gYCR7aW1hZ2VOYW1lfS1kaWZmLSR7aW1hZ2VOdW1iZXJ9LnBuZ2A7XG4gICAgICBhd2FpdCB3cml0ZUZpbGVBc3luYyhwYXRoLmpvaW4ocmVwb3J0SW1hZ2VEaXIsIGltYWdlLmV4cGVjdCksIGV4cGVjdCk7XG4gICAgICBhd2FpdCB3cml0ZUZpbGVBc3luYyhwYXRoLmpvaW4ocmVwb3J0SW1hZ2VEaXIsIGltYWdlLmRpZmYpLCBkaWZmKTtcbiAgICB9O1xuXG4gICAgY29uc3QgZXhwZWN0SW1hZ2VEaXIgPSBwYXRoLmpvaW4oY29uZmlnLnNjcmVlbkRpciwgLi4udGVzdFBhdGgpO1xuICAgIGNvbnN0IGV4cGVjdEltYWdlU3RhdCA9IGF3YWl0IGdldFN0YXQocGF0aC5qb2luKGV4cGVjdEltYWdlRGlyLCBgJHtpbWFnZU5hbWV9LnBuZ2ApKTtcbiAgICBpZiAoIWV4cGVjdEltYWdlU3RhdCkgcmV0dXJuIHsgZXhwZWN0ZWQ6IG51bGwsIG9uQ29tcGFyZSB9O1xuXG4gICAgY29uc3QgZXhwZWN0ZWQgPSBhd2FpdCByZWFkRmlsZUFzeW5jKHBhdGguam9pbihleHBlY3RJbWFnZURpciwgYCR7aW1hZ2VOYW1lfS5wbmdgKSk7XG5cbiAgICByZXR1cm4geyBleHBlY3RlZCwgb25Db21wYXJlIH07XG4gIH1cblxuICBjb25zdCBtb2NoYU9wdGlvbnM6IE1vY2hhT3B0aW9ucyA9IHtcbiAgICB0aW1lb3V0OiAzMDAwMCxcbiAgICByZXBvcnRlcjogcHJvY2Vzcy5lbnYuVEVBTUNJVFlfVkVSU0lPTiA/IFRlYW1jaXR5UmVwb3J0ZXIgOiBvcHRpb25zLnJlcG9ydGVyIHx8IENyZWV2ZXlSZXBvcnRlcixcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1pZ25vcmVcbiAgICAvL0B0cy1pZ25vcmUgU2hvdWxkIHVwZGF0ZSBAdHlwZXMvbW9jaGEgZm9yIG5ldyBtYWpvciByZWxlYXNlIGh0dHBzOi8vZ2l0aHViLmNvbS9tb2NoYWpzL21vY2hhL3JlbGVhc2VzL3RhZy92Ny4wLjBcbiAgICByZXBvcnRlck9wdGlvbjoge1xuICAgICAgcmVwb3J0RGlyOiBjb25maWcucmVwb3J0RGlyLFxuICAgICAgdG9wTGV2ZWxTdWl0ZTogb3B0aW9ucy5icm93c2VyLFxuICAgICAgd2lsbFJldHJ5OiAoKSA9PiByZXRyaWVzIDwgY29uZmlnLm1heFJldHJpZXMsXG4gICAgICBpbWFnZXM6ICgpID0+IGltYWdlcyxcbiAgICB9LFxuICB9O1xuICBjb25zdCBtb2NoYSA9IG5ldyBNb2NoYShtb2NoYU9wdGlvbnMpO1xuXG4gIC8vIFRPRE8gTW92ZSB0byBiZWZvcmVBbGxcbiAgY2hhaS51c2UoY2hhaUltYWdlKGdldEV4cGVjdGVkLCBjb25maWcuZGlmZk9wdGlvbnMpKTtcblxuICBhd2FpdCBhZGRUZXN0c0Zyb21TdG9yaWVzKG1vY2hhLnN1aXRlLCBvcHRpb25zLmJyb3dzZXIsIGNvbmZpZyk7XG5cbiAgY29uc3QgYnJvd3NlckNvbmZpZyA9IGNvbmZpZy5icm93c2Vyc1tvcHRpb25zLmJyb3dzZXJdIGFzIEJyb3dzZXJDb25maWc7XG4gIGNvbnN0IGJyb3dzZXIgPSBhd2FpdCBnZXRCcm93c2VyKGNvbmZpZywgYnJvd3NlckNvbmZpZyk7XG5cbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgIGJyb3dzZXIuZ2V0Q3VycmVudFVybCgpLnRoZW4oKHVybCkgPT4ge1xuICAgICAgaWYgKG9wdGlvbnMuZGVidWcpXG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrYFt7Ymx1ZSBXT1JLRVJ9e2dyZXkgOiR7b3B0aW9ucy5icm93c2VyfToke3Byb2Nlc3MucGlkfX1dIHtncmV5IGN1cnJlbnQgdXJsfSAke3VybH1gKTtcbiAgICB9KTtcbiAgfSwgMTAgKiAxMDAwKTtcblxuICBtb2NoYS5zdWl0ZS5iZWZvcmVBbGwoZnVuY3Rpb24gKHRoaXM6IENvbnRleHQpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmJyb3dzZXIgPSBicm93c2VyO1xuICAgIHRoaXMua2V5cyA9IEtleTtcbiAgICB0aGlzLmV4cGVjdCA9IGNoYWkuZXhwZWN0O1xuICAgIHRoaXMuYnJvd3Nlck5hbWUgPSBvcHRpb25zLmJyb3dzZXI7XG4gICAgdGhpcy50ZXN0U2NvcGUgPSB0ZXN0U2NvcGU7XG4gIH0pO1xuICAvLyBUT0RPIEhhbmRsZSBzdG9yeSBjb250ZXh0XG4gIG1vY2hhLnN1aXRlLmJlZm9yZUVhY2goc3dpdGNoU3RvcnkpO1xuICBwYXRjaE1vY2hhSW50ZXJmYWNlKG1vY2hhLnN1aXRlKTtcblxuICBwcm9jZXNzLm9uKCdtZXNzYWdlJywgKG1lc3NhZ2UpID0+IHtcbiAgICBjb25zdCB0ZXN0OiB7IGlkOiBzdHJpbmc7IHBhdGg6IHN0cmluZ1tdOyByZXRyaWVzOiBudW1iZXIgfSA9IEpTT04ucGFyc2UobWVzc2FnZSk7XG4gICAgcmV0cmllcyA9IHRlc3QucmV0cmllcztcbiAgICBjb25zdCB0ZXN0UGF0aCA9IFsuLi50ZXN0LnBhdGhdXG4gICAgICAucmV2ZXJzZSgpXG4gICAgICAuam9pbignICcpXG4gICAgICAucmVwbGFjZSgvW3xcXFxce30oKVtcXF1eJCsqPy4tXS9nLCAnXFxcXCQmJyk7XG5cbiAgICBtb2NoYS5ncmVwKG5ldyBSZWdFeHAoYF4ke3Rlc3RQYXRofSRgKSk7XG4gICAgY29uc3QgcnVubmVyID0gbW9jaGEucnVuKHJ1bkhhbmRsZXIpO1xuXG4gICAgLy8gVE9ETyBIb3cgaGFuZGxlIGJyb3dzZXIgY29ycnVwdGlvbj9cbiAgICBydW5uZXIub24oJ2ZhaWwnLCAoX3Rlc3QsIHJlYXNvbikgPT4gKGVycm9yID0gcmVhc29uIGluc3RhbmNlb2YgRXJyb3IgPyByZWFzb24uc3RhY2sgfHwgcmVhc29uLm1lc3NhZ2UgOiByZWFzb24pKTtcbiAgfSk7XG5cbiAgY29uc29sZS5sb2coJ1tDcmVldmV5V29ya2VyXTonLCBgUmVhZHkgJHtvcHRpb25zLmJyb3dzZXJ9OiR7cHJvY2Vzcy5waWR9YCk7XG5cbiAgaWYgKHByb2Nlc3Muc2VuZCkge1xuICAgIHByb2Nlc3Muc2VuZChKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICdyZWFkeScgfSkpO1xuICB9XG4gIHByb2Nlc3Mub24oJ2Rpc2Nvbm5lY3QnLCAoKSA9PiB7XG4gICAgUHJvbWlzZS5yYWNlKFtuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxMDAwMCkpLCBicm93c2VyLmNsb3NlKCldKS50aGVuKCgpID0+IHByb2Nlc3MuZXhpdCgwKSk7XG4gIH0pO1xuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBub29wKTtcbn1cbiJdfQ==