testcafe 1.14.1 → 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/LICENSE +21 -21
- package/bin/testcafe-with-v8-flag-filter.js +0 -0
- package/lib/api/exportable-lib/index.js +49 -49
- package/lib/api/request-hooks/assert-type.js +7 -7
- package/lib/api/request-hooks/hook-method-names.js +9 -9
- package/lib/api/request-hooks/hook.js +32 -32
- package/lib/api/request-hooks/interfaces.js +2 -2
- package/lib/api/request-hooks/request-logger.js +112 -112
- package/lib/api/request-hooks/request-mock/create-request-mock.js +10 -10
- package/lib/api/request-hooks/request-mock/index.js +44 -44
- package/lib/api/request-hooks/request-mock.js +46 -46
- package/lib/api/structure/base-unit.js +11 -11
- package/lib/api/structure/fixture.js +75 -75
- package/lib/api/structure/interfaces.js +2 -2
- package/lib/api/structure/test-file.js +31 -31
- package/lib/api/structure/test-timeout.js +9 -9
- package/lib/api/structure/test.js +85 -85
- package/lib/api/structure/testing-unit.js +89 -89
- package/lib/api/structure/unit-type.js +9 -9
- package/lib/api/test-controller/assertion.js +88 -88
- package/lib/api/test-controller/execution-context.js +82 -82
- package/lib/api/test-controller/index.js +358 -358
- package/lib/api/test-controller/proxy.js +28 -28
- package/lib/api/test-page-url.js +60 -60
- package/lib/api/test-run-tracker.js +68 -68
- package/lib/api/wrap-test-function.js +49 -49
- package/lib/assertions/executor.js +74 -74
- package/lib/assertions/get-fn.js +46 -46
- package/lib/assertions/type.js +20 -20
- package/lib/assets/content-types.js +9 -9
- package/lib/assets/injectables.js +18 -18
- package/lib/browser/connection/command.js +10 -10
- package/lib/browser/connection/error-hints.js +9 -9
- package/lib/browser/connection/gateway.js +159 -159
- package/lib/browser/connection/get-hints.js +33 -33
- package/lib/browser/connection/heartbeat-status.js +8 -8
- package/lib/browser/connection/index.js +328 -328
- package/lib/browser/connection/remotes-queue.js +46 -46
- package/lib/browser/connection/service-routes.js +12 -12
- package/lib/browser/connection/status.js +12 -12
- package/lib/browser/interfaces.js +2 -2
- package/lib/browser/provider/built-in/dedicated/base.js +80 -80
- package/lib/browser/provider/built-in/dedicated/chrome/browser-client.js +204 -204
- package/lib/browser/provider/built-in/dedicated/chrome/build-chrome-args.js +17 -17
- package/lib/browser/provider/built-in/dedicated/chrome/config.js +110 -110
- package/lib/browser/provider/built-in/dedicated/chrome/create-temp-profile.js +45 -45
- package/lib/browser/provider/built-in/dedicated/chrome/elapsed-upperbounds.js +15 -15
- package/lib/browser/provider/built-in/dedicated/chrome/index.js +102 -102
- package/lib/browser/provider/built-in/dedicated/chrome/interfaces.js +2 -2
- package/lib/browser/provider/built-in/dedicated/chrome/local-chrome.js +24 -24
- package/lib/browser/provider/built-in/dedicated/chrome/runtime-info.js +29 -29
- package/lib/browser/provider/built-in/dedicated/edge/index.js +10 -10
- package/lib/browser/provider/built-in/dedicated/edge/runtime-info.js +29 -29
- package/lib/browser/provider/built-in/dedicated/firefox/config.js +33 -33
- package/lib/browser/provider/built-in/dedicated/firefox/create-temp-profile.js +78 -78
- package/lib/browser/provider/built-in/dedicated/firefox/index.js +73 -73
- package/lib/browser/provider/built-in/dedicated/firefox/local-firefox.js +36 -36
- package/lib/browser/provider/built-in/dedicated/firefox/marionette-client/commands.js +13 -13
- package/lib/browser/provider/built-in/dedicated/firefox/marionette-client/index.js +200 -200
- package/lib/browser/provider/built-in/dedicated/firefox/runtime-info.js +17 -17
- package/lib/browser/provider/built-in/index.js +21 -21
- package/lib/browser/provider/built-in/locally-installed.js +30 -30
- package/lib/browser/provider/built-in/path.js +47 -47
- package/lib/browser/provider/built-in/remote.js +58 -58
- package/lib/browser/provider/index.js +303 -303
- package/lib/browser/provider/parse-provider-name.js +16 -16
- package/lib/browser/provider/plugin-host.js +121 -121
- package/lib/browser/provider/pool.js +115 -115
- package/lib/browser/provider/utils/argument-parsing.js +74 -74
- package/lib/browser/provider/utils/browser-starter.js +34 -34
- package/lib/browser/provider/utils/client-functions.js +24 -24
- package/lib/browser/provider/utils/get-maximized-headless-window-size.js +9 -9
- package/lib/cli/argument-parser.js +284 -284
- package/lib/cli/authentication-helper.js +35 -35
- package/lib/cli/cli.js +134 -134
- package/lib/cli/correct-browsers-and-sources.js +40 -40
- package/lib/cli/index.js +19 -19
- package/lib/cli/log.js +43 -43
- package/lib/cli/remotes-wizard.js +36 -36
- package/lib/cli/termination-handler.js +38 -38
- package/lib/client/automation/index.js +34 -16
- package/lib/client/automation/index.min.js +1 -1
- package/lib/client/browser/idle-page/index.html.mustache +35 -35
- package/lib/client/browser/idle-page/logo.svg +86 -86
- package/lib/client/core/index.js +14 -14
- package/lib/client/driver/index.js +46 -16
- package/lib/client/driver/index.min.js +1 -1
- package/lib/client/driver/internal-properties.js +9 -9
- package/lib/client/test-run/iframe.js.mustache +17 -17
- package/lib/client/test-run/index.js.mustache +51 -51
- package/lib/client/ui/index.js +14 -14
- package/lib/client/ui/sprite.svg +42 -42
- package/lib/client-functions/builder-symbol.js +4 -4
- package/lib/client-functions/client-function-builder.js +155 -155
- package/lib/client-functions/replicator.js +61 -61
- package/lib/client-functions/return-single-prop-mode.js +8 -8
- package/lib/client-functions/selector-api-execution-mode.js +20 -20
- package/lib/client-functions/selectors/add-api.js +645 -645
- package/lib/client-functions/selectors/create-snapshot-methods.js +13 -13
- package/lib/client-functions/selectors/prepare-api-args.js +20 -20
- package/lib/client-functions/selectors/selector-attribute-filter.js +22 -22
- package/lib/client-functions/selectors/selector-builder.js +153 -153
- package/lib/client-functions/selectors/selector-text-filter.js +43 -43
- package/lib/client-functions/selectors/snapshot-properties.js +48 -48
- package/lib/client-functions/types.js +18 -18
- package/lib/compiler/babel/format-babel-produced-code.js +10 -10
- package/lib/compiler/babel/get-base-babel-options.js +11 -11
- package/lib/compiler/babel/load-libs.js +63 -63
- package/lib/compiler/babel/preset-stage-2.js +19 -19
- package/lib/compiler/compile-client-function.js +73 -73
- package/lib/compiler/compilers.js +33 -33
- package/lib/compiler/index.js +92 -92
- package/lib/compiler/interfaces.js +2 -2
- package/lib/compiler/test-file/api-based.js +146 -146
- package/lib/compiler/test-file/base.js +36 -36
- package/lib/compiler/test-file/exportble-lib-path.js +5 -5
- package/lib/compiler/test-file/formats/coffeescript/compiler.js +38 -38
- package/lib/compiler/test-file/formats/coffeescript/get-test-list.js +29 -29
- package/lib/compiler/test-file/formats/es-next/compiler.js +42 -42
- package/lib/compiler/test-file/formats/es-next/get-test-list.js +166 -166
- package/lib/compiler/test-file/formats/es-next/is-flow-code.js +7 -7
- package/lib/compiler/test-file/formats/raw.js +85 -85
- package/lib/compiler/test-file/formats/typescript/compiler.js +135 -135
- package/lib/compiler/test-file/formats/typescript/get-test-list.js +185 -185
- package/lib/compiler/test-file/test-file-parser-base.js +214 -214
- package/lib/configuration/configuration-base.js +165 -165
- package/lib/configuration/constants.js +9 -9
- package/lib/configuration/customizable-compilers.js +7 -7
- package/lib/configuration/default-values.js +51 -51
- package/lib/configuration/interfaces.js +2 -2
- package/lib/configuration/option-names.js +53 -53
- package/lib/configuration/option-source.js +9 -9
- package/lib/configuration/option.js +14 -14
- package/lib/configuration/quarantine-option-names.js +8 -8
- package/lib/configuration/run-option-names.js +26 -26
- package/lib/configuration/screenshot-option-names.js +10 -10
- package/lib/configuration/testcafe-configuration.js +163 -163
- package/lib/configuration/types.js +2 -2
- package/lib/configuration/typescript-configuration.js +62 -62
- package/lib/custom-client-scripts/assert-type.js +7 -7
- package/lib/custom-client-scripts/client-script-init.js +2 -2
- package/lib/custom-client-scripts/client-script.js +106 -106
- package/lib/custom-client-scripts/get-code.js +11 -11
- package/lib/custom-client-scripts/get-url.js +6 -6
- package/lib/custom-client-scripts/load.js +15 -15
- package/lib/custom-client-scripts/problematic-scripts.js +2 -2
- package/lib/custom-client-scripts/routing.js +36 -36
- package/lib/custom-client-scripts/utils.js +60 -60
- package/lib/embedding-utils.js +83 -83
- package/lib/errors/create-stack-filter.js +18 -18
- package/lib/errors/error-list.js +26 -26
- package/lib/errors/get-callsite.js +31 -31
- package/lib/errors/internal-modules-prefix.js +8 -8
- package/lib/errors/is-internal-stack-frame.js +45 -45
- package/lib/errors/process-test-fn-error.js +37 -37
- package/lib/errors/runtime/index.js +123 -123
- package/lib/errors/runtime/templates.js +115 -115
- package/lib/errors/runtime/type-assertions.js +112 -112
- package/lib/errors/stack-cleaning-hook.js +64 -64
- package/lib/errors/test-run/formattable-adapter.js +59 -59
- package/lib/errors/test-run/index.js +301 -301
- package/lib/errors/test-run/render-error-template.js +31 -31
- package/lib/errors/test-run/templates.js +91 -91
- package/lib/errors/test-run/utils.js +89 -89
- package/lib/errors/types.js +156 -156
- package/lib/index.js +81 -81
- package/lib/live/bootstrapper.js +43 -43
- package/lib/live/controller.js +107 -107
- package/lib/live/file-watcher/index.js +67 -67
- package/lib/live/file-watcher/modules-graph.js +58 -58
- package/lib/live/keyboard-observer.js +76 -76
- package/lib/live/logger/index.js +64 -64
- package/lib/live/test-run-controller.js +96 -96
- package/lib/live/test-run-state.js +6 -6
- package/lib/live/test-run.js +56 -56
- package/lib/live/test-runner.js +167 -167
- package/lib/load-assets.js +29 -29
- package/lib/notifications/add-rendered-warning.js +16 -16
- package/lib/notifications/debug-logger.js +78 -78
- package/lib/notifications/deprecated.js +24 -24
- package/lib/notifications/information-message.js +9 -9
- package/lib/notifications/warning-log.js +31 -31
- package/lib/notifications/warning-message.js +47 -47
- package/lib/reporter/command/command-formatter.js +120 -109
- package/lib/reporter/command/format-command.js +8 -8
- package/lib/reporter/command/interfaces.js +2 -2
- package/lib/reporter/index.js +319 -314
- package/lib/reporter/interfaces.js +2 -2
- package/lib/reporter/plugin-host.js +135 -135
- package/lib/reporter/plugin-methods.js +12 -12
- package/lib/role/index.js +74 -74
- package/lib/role/marker-symbol.js +7 -7
- package/lib/role/phase.js +9 -9
- package/lib/runner/bootstrapper.js +271 -271
- package/lib/runner/browser-job-result.js +9 -9
- package/lib/runner/browser-job.js +152 -152
- package/lib/runner/browser-set.js +114 -114
- package/lib/runner/fixture-hook-controller.js +85 -85
- package/lib/runner/index.js +449 -449
- package/lib/runner/interfaces.js +2 -2
- package/lib/runner/reporter-stream-controller.js +27 -27
- package/lib/runner/task/index.js +151 -151
- package/lib/runner/task/phase.js +9 -9
- package/lib/runner/test-run-controller.js +165 -165
- package/lib/runner/tested-app.js +72 -72
- package/lib/screenshots/capturer.js +141 -141
- package/lib/screenshots/constants.js +11 -11
- package/lib/screenshots/crop.js +111 -111
- package/lib/screenshots/default-extension.js +4 -4
- package/lib/screenshots/index.js +67 -67
- package/lib/screenshots/utils.js +39 -39
- package/lib/services/compiler/host.js +190 -190
- package/lib/services/compiler/io.js +9 -9
- package/lib/services/compiler/protocol.js +17 -16
- package/lib/services/compiler/service.js +225 -212
- package/lib/services/compiler/test-run-proxy.js +111 -111
- package/lib/services/interfaces.js +2 -2
- package/lib/services/process-title.js +8 -8
- package/lib/services/serialization/prepare-options.js +17 -17
- package/lib/services/serialization/replicator/create-replicator.js +25 -25
- package/lib/services/serialization/replicator/custom-error-transform.js +26 -26
- package/lib/services/serialization/test-structure.js +92 -92
- package/lib/services/utils/ipc/interfaces.js +30 -30
- package/lib/services/utils/ipc/io.js +108 -108
- package/lib/services/utils/ipc/message.js +75 -75
- package/lib/services/utils/ipc/packet.js +55 -55
- package/lib/services/utils/ipc/proxy.js +109 -109
- package/lib/services/utils/ipc/transport.js +64 -64
- package/lib/shared/errors/index.js +382 -382
- package/lib/shared/node-modules-folder-name.js +4 -4
- package/lib/test-run/bookmark.js +90 -90
- package/lib/test-run/browser-console-messages.js +73 -73
- package/lib/test-run/browser-manipulation-queue.js +92 -92
- package/lib/test-run/client-messages.js +9 -9
- package/lib/test-run/commands/actions.js +486 -483
- package/lib/test-run/commands/assertion.js +45 -45
- package/lib/test-run/commands/base.js +14 -14
- package/lib/test-run/commands/browser-manipulation.js +95 -95
- package/lib/test-run/commands/from-object.js +82 -82
- package/lib/test-run/commands/observation.js +61 -61
- package/lib/test-run/commands/options.js +231 -215
- package/lib/test-run/commands/service.js +54 -48
- package/lib/test-run/commands/type.js +65 -64
- package/lib/test-run/commands/utils.js +87 -87
- package/lib/test-run/commands/validations/argument.js +90 -90
- package/lib/test-run/commands/validations/factories.js +47 -47
- package/lib/test-run/commands/validations/initializers.js +44 -44
- package/lib/test-run/debug-log.js +32 -32
- package/lib/test-run/execute-js-expression.js +74 -74
- package/lib/test-run/index.js +823 -799
- package/lib/test-run/marker-symbol.js +7 -7
- package/lib/test-run/observed-callsites-storage.js +17 -17
- package/lib/test-run/phase.js +16 -16
- package/lib/test-run/session-controller.js +104 -104
- package/lib/testcafe.js +118 -118
- package/lib/utils/assignable.js +39 -39
- package/lib/utils/async-event-emitter.js +28 -28
- package/lib/utils/async-queue.js +14 -14
- package/lib/utils/browser-connection-timeouts.js +19 -19
- package/lib/utils/callsite.js +17 -17
- package/lib/utils/check-file-path.js +31 -31
- package/lib/utils/check-url.js +51 -51
- package/lib/utils/convert-to-best-fit-type.js +16 -16
- package/lib/utils/correct-file-path.js +21 -21
- package/lib/utils/define-lazy-property.js +13 -13
- package/lib/utils/delay.js +6 -6
- package/lib/utils/delegated-api.js +44 -44
- package/lib/utils/detect-display.js +6 -6
- package/lib/utils/detect-ffmpeg.js +44 -44
- package/lib/utils/diff/colors.js +29 -29
- package/lib/utils/diff/index.js +52 -52
- package/lib/utils/diff/util.js +23 -23
- package/lib/utils/diff.js +29 -29
- package/lib/utils/escape-user-agent.js +10 -10
- package/lib/utils/flag-list.js +17 -17
- package/lib/utils/get-any-key.js +8 -8
- package/lib/utils/get-browser.js +8 -8
- package/lib/utils/get-common-path.js +34 -34
- package/lib/utils/get-filter-fn.js +40 -40
- package/lib/utils/get-options/base.js +36 -36
- package/lib/utils/get-options/compiler.js +33 -33
- package/lib/utils/get-options/grep.js +15 -15
- package/lib/utils/get-options/index.js +20 -20
- package/lib/utils/get-options/meta.js +22 -22
- package/lib/utils/get-options/quarantine.js +91 -91
- package/lib/utils/get-options/screenshot.js +17 -17
- package/lib/utils/get-options/ssl.js +45 -45
- package/lib/utils/get-options/video.js +10 -10
- package/lib/utils/get-viewport-width.js +17 -17
- package/lib/utils/guard-time-execution.js +10 -10
- package/lib/utils/handle-errors.js +74 -74
- package/lib/utils/handle-tag-args.js +8 -8
- package/lib/utils/http.js +30 -30
- package/lib/utils/is-localhost.js +11 -11
- package/lib/utils/is-password-input.js +11 -0
- package/lib/utils/is-repl.js +10 -10
- package/lib/utils/is-window-in-iframe.js +6 -6
- package/lib/utils/limit-number.js +10 -10
- package/lib/utils/make-reg-exp.js +7 -7
- package/lib/utils/moment-loader.js +20 -20
- package/lib/utils/parse-file-list.js +71 -71
- package/lib/utils/parse-user-agent.js +55 -55
- package/lib/utils/path-pattern.js +114 -114
- package/lib/utils/prepare-reporters.js +30 -30
- package/lib/utils/prerender-callsite.js +18 -18
- package/lib/utils/process.js +119 -119
- package/lib/utils/promisified-functions.js +46 -46
- package/lib/utils/re-executable-promise.js +39 -39
- package/lib/utils/render-callsite-sync.js +29 -29
- package/lib/utils/render-template.js +9 -9
- package/lib/utils/reporter.js +30 -30
- package/lib/utils/resolve-path-relatively-cwd.js +7 -7
- package/lib/utils/string.js +105 -105
- package/lib/utils/temp-directory/cleanup-process/commands.js +7 -7
- package/lib/utils/temp-directory/cleanup-process/index.js +143 -143
- package/lib/utils/temp-directory/cleanup-process/worker.js +58 -58
- package/lib/utils/temp-directory/index.js +87 -87
- package/lib/utils/temp-directory/lockfile.js +56 -56
- package/lib/utils/thennable.js +7 -7
- package/lib/utils/timer.js +15 -15
- package/lib/utils/to-posix-path.js +8 -8
- package/lib/utils/types.js +2 -2
- package/lib/video-recorder/interfaces.js +2 -2
- package/lib/video-recorder/process.js +126 -126
- package/lib/video-recorder/recorder.js +136 -136
- package/lib/video-recorder/test-run-video-recorder.js +69 -69
- package/lib/video-recorder/videos.js +37 -37
- package/package.json +2 -2
- package/ts-defs/index.d.ts +25 -14
- package/ts-defs/selectors.d.ts +16 -5
- package/ts-defs/testcafe-scripts.d.ts +17 -6
|
@@ -1,273 +1,273 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const path_1 = __importDefault(require("path"));
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const is_ci_1 = __importDefault(require("is-ci"));
|
|
9
|
-
const lodash_1 = require("lodash");
|
|
10
|
-
const make_dir_1 = __importDefault(require("make-dir"));
|
|
11
|
-
const os_family_1 = __importDefault(require("os-family"));
|
|
12
|
-
const debug_1 = __importDefault(require("debug"));
|
|
13
|
-
const pretty_hrtime_1 = __importDefault(require("pretty-hrtime"));
|
|
14
|
-
const testcafe_browser_tools_1 = require("testcafe-browser-tools");
|
|
15
|
-
const authentication_helper_1 = __importDefault(require("../cli/authentication-helper"));
|
|
16
|
-
const compiler_1 = __importDefault(require("../compiler"));
|
|
17
|
-
const connection_1 = __importDefault(require("../browser/connection"));
|
|
18
|
-
const pool_1 = __importDefault(require("../browser/provider/pool"));
|
|
19
|
-
const browser_set_1 = __importDefault(require("./browser-set"));
|
|
20
|
-
const remote_1 = __importDefault(require("../browser/provider/built-in/remote"));
|
|
21
|
-
const runtime_1 = require("../errors/runtime");
|
|
22
|
-
const types_1 = require("../errors/types");
|
|
23
|
-
const tested_app_1 = __importDefault(require("./tested-app"));
|
|
24
|
-
const parse_file_list_1 = __importDefault(require("../utils/parse-file-list"));
|
|
25
|
-
const resolve_path_relatively_cwd_1 = __importDefault(require("../utils/resolve-path-relatively-cwd"));
|
|
26
|
-
const load_1 = __importDefault(require("../custom-client-scripts/load"));
|
|
27
|
-
const string_1 = require("../utils/string");
|
|
28
|
-
const detect_display_1 = __importDefault(require("../utils/detect-display"));
|
|
29
|
-
const reporter_1 = require("../utils/reporter");
|
|
30
|
-
const warning_log_1 = __importDefault(require("../notifications/warning-log"));
|
|
31
|
-
const warning_message_1 = __importDefault(require("../notifications/warning-message"));
|
|
32
|
-
const guard_time_execution_1 = __importDefault(require("../utils/guard-time-execution"));
|
|
33
|
-
const DEBUG_SCOPE = 'testcafe:bootstrapper';
|
|
34
|
-
function isPromiseError(value) {
|
|
35
|
-
return value.error !== void 0;
|
|
36
|
-
}
|
|
37
|
-
class Bootstrapper {
|
|
38
|
-
constructor({ browserConnectionGateway, compilerService }) {
|
|
39
|
-
this.browserConnectionGateway = browserConnectionGateway;
|
|
40
|
-
this.concurrency = 1;
|
|
41
|
-
this.sources = [];
|
|
42
|
-
this.browsers = [];
|
|
43
|
-
this.reporters = [];
|
|
44
|
-
this.filter = void 0;
|
|
45
|
-
this.appCommand = void 0;
|
|
46
|
-
this.appInitDelay = void 0;
|
|
47
|
-
this.tsConfigPath = void 0;
|
|
48
|
-
this.clientScripts = [];
|
|
49
|
-
this.disableMultipleWindows = false;
|
|
50
|
-
this.compilerOptions = void 0;
|
|
51
|
-
this.debugLogger = debug_1.default(DEBUG_SCOPE);
|
|
52
|
-
this.warningLog = new warning_log_1.default();
|
|
53
|
-
this.compilerService = compilerService;
|
|
54
|
-
this.TESTS_COMPILATION_UPPERBOUND = 60;
|
|
55
|
-
}
|
|
56
|
-
static _getBrowserName(browser) {
|
|
57
|
-
if (browser instanceof connection_1.default)
|
|
58
|
-
return browser.browserInfo.browserName;
|
|
59
|
-
return browser.browserName;
|
|
60
|
-
}
|
|
61
|
-
static _splitBrowserInfo(browserInfo) {
|
|
62
|
-
const remotes = [];
|
|
63
|
-
const automated = [];
|
|
64
|
-
browserInfo.forEach(browser => {
|
|
65
|
-
if (browser instanceof connection_1.default)
|
|
66
|
-
remotes.push(browser);
|
|
67
|
-
else
|
|
68
|
-
automated.push(browser);
|
|
69
|
-
});
|
|
70
|
-
return { remotes, automated };
|
|
71
|
-
}
|
|
72
|
-
static async _hasLocalBrowsers(browserInfo) {
|
|
73
|
-
for (const browser of browserInfo) {
|
|
74
|
-
if (browser instanceof connection_1.default)
|
|
75
|
-
continue;
|
|
76
|
-
if (await browser.provider.isLocalBrowser(void 0, browser.browserName))
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
static async _checkRequiredPermissions(browserInfo) {
|
|
82
|
-
const hasLocalBrowsers = await Bootstrapper._hasLocalBrowsers(browserInfo);
|
|
83
|
-
const { error } = await authentication_helper_1.default(() => testcafe_browser_tools_1.findWindow(''), testcafe_browser_tools_1.errors.UnableToAccessScreenRecordingAPIError, {
|
|
84
|
-
interactive: hasLocalBrowsers && !is_ci_1.default
|
|
85
|
-
});
|
|
86
|
-
if (!error)
|
|
87
|
-
return;
|
|
88
|
-
if (hasLocalBrowsers)
|
|
89
|
-
throw error;
|
|
90
|
-
remote_1.default.canDetectLocalBrowsers = false;
|
|
91
|
-
}
|
|
92
|
-
static async _checkThatTestsCanRunWithoutDisplay(browserInfoSource) {
|
|
93
|
-
for (let browserInfo of browserInfoSource) {
|
|
94
|
-
if (browserInfo instanceof connection_1.default)
|
|
95
|
-
browserInfo = browserInfo.browserInfo;
|
|
96
|
-
const isLocalBrowser = await browserInfo.provider.isLocalBrowser(void 0, browserInfo.browserName);
|
|
97
|
-
const isHeadlessBrowser = await browserInfo.provider.isHeadlessBrowser(void 0, browserInfo.browserName);
|
|
98
|
-
if (isLocalBrowser && !isHeadlessBrowser) {
|
|
99
|
-
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotRunLocalNonHeadlessBrowserWithoutDisplay, browserInfo.alias);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
async _getBrowserInfo() {
|
|
104
|
-
if (!this.browsers.length)
|
|
105
|
-
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserNotSet);
|
|
106
|
-
const browserInfo = await Promise.all(this.browsers.map(browser => pool_1.default.getBrowserInfo(browser)));
|
|
107
|
-
return lodash_1.flatten(browserInfo);
|
|
108
|
-
}
|
|
109
|
-
_createAutomatedConnections(browserInfo) {
|
|
110
|
-
if (!browserInfo)
|
|
111
|
-
return [];
|
|
112
|
-
return browserInfo
|
|
113
|
-
.map(browser => lodash_1.times(this.concurrency, () => new connection_1.default(this.browserConnectionGateway, browser, false, this.disableMultipleWindows)));
|
|
114
|
-
}
|
|
115
|
-
_getBrowserSetOptions() {
|
|
116
|
-
return {
|
|
117
|
-
concurrency: this.concurrency,
|
|
118
|
-
browserInitTimeout: this.browserInitTimeout,
|
|
119
|
-
warningLog: this.warningLog
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
async _getBrowserConnections(browserInfo) {
|
|
123
|
-
const { automated, remotes } = Bootstrapper._splitBrowserInfo(browserInfo);
|
|
124
|
-
if (remotes && remotes.length % this.concurrency)
|
|
125
|
-
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotDivideRemotesCountByConcurrency);
|
|
126
|
-
let browserConnections = this._createAutomatedConnections(automated);
|
|
127
|
-
browserConnections = browserConnections.concat(lodash_1.chunk(remotes, this.concurrency));
|
|
128
|
-
return browser_set_1.default.from(browserConnections, this._getBrowserSetOptions());
|
|
129
|
-
}
|
|
130
|
-
_filterTests(tests, predicate) {
|
|
131
|
-
return tests.filter(test => predicate(test.name, test.fixture.name, test.fixture.path, test.meta, test.fixture.meta));
|
|
132
|
-
}
|
|
133
|
-
async _compileTests({ sourceList, compilerOptions }) {
|
|
134
|
-
if (this.compilerService) {
|
|
135
|
-
await this.compilerService.init();
|
|
136
|
-
return this.compilerService.getTests({ sourceList, compilerOptions });
|
|
137
|
-
}
|
|
138
|
-
const compiler = new compiler_1.default(sourceList, compilerOptions);
|
|
139
|
-
return compiler.getTests();
|
|
140
|
-
}
|
|
141
|
-
async _getTests() {
|
|
142
|
-
const cwd = process.cwd();
|
|
143
|
-
const sourceList = await parse_file_list_1.default(this.sources, cwd);
|
|
144
|
-
if (!sourceList.length)
|
|
145
|
-
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testFilesNotFound, string_1.getConcatenatedValuesString(this.sources, '\n', ''), cwd);
|
|
146
|
-
let tests = await guard_time_execution_1.default(async () => await this._compileTests({ sourceList, compilerOptions: this.compilerOptions }), elapsedTime => {
|
|
147
|
-
this.debugLogger(`tests compilation took ${pretty_hrtime_1.default(elapsedTime)}`);
|
|
148
|
-
const [elapsedSeconds] = elapsedTime;
|
|
149
|
-
if (elapsedSeconds > this.TESTS_COMPILATION_UPPERBOUND)
|
|
150
|
-
this.warningLog.addWarning(warning_message_1.default.testsCompilationTakesTooLong, pretty_hrtime_1.default(elapsedTime));
|
|
151
|
-
});
|
|
152
|
-
const testsWithOnlyFlag = tests.filter(test => test.only);
|
|
153
|
-
if (testsWithOnlyFlag.length)
|
|
154
|
-
tests = testsWithOnlyFlag;
|
|
155
|
-
if (!tests.length)
|
|
156
|
-
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRun);
|
|
157
|
-
if (this.filter)
|
|
158
|
-
tests = this._filterTests(tests, this.filter);
|
|
159
|
-
if (!tests.length)
|
|
160
|
-
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRunDueFiltering);
|
|
161
|
-
return tests;
|
|
162
|
-
}
|
|
163
|
-
async _ensureOutStream(outStream) {
|
|
164
|
-
if (typeof outStream !== 'string')
|
|
165
|
-
return outStream;
|
|
166
|
-
const fullReporterOutputPath = resolve_path_relatively_cwd_1.default(outStream);
|
|
167
|
-
await make_dir_1.default(path_1.default.dirname(fullReporterOutputPath));
|
|
168
|
-
return fs_1.default.createWriteStream(fullReporterOutputPath);
|
|
169
|
-
}
|
|
170
|
-
static _addDefaultReporter(reporters) {
|
|
171
|
-
reporters.push({
|
|
172
|
-
name: 'spec',
|
|
173
|
-
output: process.stdout
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
async _getReporterPlugins() {
|
|
177
|
-
if (!this.reporters.length)
|
|
178
|
-
Bootstrapper._addDefaultReporter(this.reporters);
|
|
179
|
-
return Promise.all(this.reporters.map(async ({ name, output }) => {
|
|
180
|
-
const pluginFactory = reporter_1.getPluginFactory(name);
|
|
181
|
-
const processedName = reporter_1.processReporterName(name);
|
|
182
|
-
const outStream = output ? await this._ensureOutStream(output) : void 0;
|
|
183
|
-
return {
|
|
184
|
-
plugin: pluginFactory(),
|
|
185
|
-
name: processedName,
|
|
186
|
-
outStream
|
|
187
|
-
};
|
|
188
|
-
}));
|
|
189
|
-
}
|
|
190
|
-
async _startTestedApp() {
|
|
191
|
-
if (!this.appCommand)
|
|
192
|
-
return void 0;
|
|
193
|
-
const testedApp = new tested_app_1.default();
|
|
194
|
-
await testedApp.start(this.appCommand, this.appInitDelay);
|
|
195
|
-
return testedApp;
|
|
196
|
-
}
|
|
197
|
-
async _canUseParallelBootstrapping(browserInfo) {
|
|
198
|
-
const isLocalPromises = browserInfo.map(browser => browser.provider.isLocalBrowser(void 0, Bootstrapper._getBrowserName(browser)));
|
|
199
|
-
const isLocalBrowsers = await Promise.all(isLocalPromises);
|
|
200
|
-
return isLocalBrowsers.every(result => result);
|
|
201
|
-
}
|
|
202
|
-
async _bootstrapSequence(browserInfo) {
|
|
203
|
-
const tests = await this._getTests();
|
|
204
|
-
const testedApp = await this._startTestedApp();
|
|
205
|
-
const browserSet = await this._getBrowserConnections(browserInfo);
|
|
206
|
-
return { tests, testedApp, browserSet };
|
|
207
|
-
}
|
|
208
|
-
_wrapBootstrappingPromise(promise) {
|
|
209
|
-
return promise
|
|
210
|
-
.then(result => ({ error: void 0, result }))
|
|
211
|
-
.catch(error => ({ result: void 0, error }));
|
|
212
|
-
}
|
|
213
|
-
async _getBootstrappingError(browserSetStatus, testsStatus, testedAppStatus) {
|
|
214
|
-
if (!isPromiseError(browserSetStatus))
|
|
215
|
-
await browserSetStatus.result.dispose();
|
|
216
|
-
if (!isPromiseError(browserSetStatus) && !isPromiseError(testedAppStatus) && testedAppStatus.result)
|
|
217
|
-
await testedAppStatus.result.kill();
|
|
218
|
-
if (isPromiseError(testsStatus))
|
|
219
|
-
return testsStatus.error;
|
|
220
|
-
if (isPromiseError(testedAppStatus))
|
|
221
|
-
return testedAppStatus.error;
|
|
222
|
-
if (isPromiseError(browserSetStatus))
|
|
223
|
-
return browserSetStatus.error;
|
|
224
|
-
return new Error('Unexpected call');
|
|
225
|
-
}
|
|
226
|
-
_getBootstrappingPromises(arg) {
|
|
227
|
-
const result = {};
|
|
228
|
-
for (const k in arg)
|
|
229
|
-
result[k] = this._wrapBootstrappingPromise(arg[k]);
|
|
230
|
-
return result;
|
|
231
|
-
}
|
|
232
|
-
async _bootstrapParallel(browserInfo) {
|
|
233
|
-
const bootstrappingPromises = {
|
|
234
|
-
browserSet: this._getBrowserConnections(browserInfo),
|
|
235
|
-
tests: this._getTests(),
|
|
236
|
-
app: this._startTestedApp()
|
|
237
|
-
};
|
|
238
|
-
const bootstrappingResultPromises = this._getBootstrappingPromises(bootstrappingPromises);
|
|
239
|
-
const bootstrappingResults = await Promise.all([
|
|
240
|
-
bootstrappingResultPromises.browserSet,
|
|
241
|
-
bootstrappingResultPromises.tests,
|
|
242
|
-
bootstrappingResultPromises.app
|
|
243
|
-
]);
|
|
244
|
-
const [browserSetResults, testResults, appResults] = bootstrappingResults;
|
|
245
|
-
if (isPromiseError(browserSetResults) || isPromiseError(testResults) || isPromiseError(appResults))
|
|
246
|
-
throw await this._getBootstrappingError(...bootstrappingResults);
|
|
247
|
-
return {
|
|
248
|
-
browserSet: browserSetResults.result,
|
|
249
|
-
tests: testResults.result,
|
|
250
|
-
testedApp: appResults.result
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
// API
|
|
254
|
-
async createRunnableConfiguration() {
|
|
255
|
-
const reporterPlugins = await this._getReporterPlugins();
|
|
256
|
-
const commonClientScripts = await load_1.default(this.clientScripts);
|
|
257
|
-
// NOTE: If a user forgot to specify a browser, but has specified a path to tests, the specified path will be
|
|
258
|
-
// considered as the browser argument, and the tests path argument will have the predefined default value.
|
|
259
|
-
// It's very ambiguous for the user, who might be confused by compilation errors from an unexpected test.
|
|
260
|
-
// So, we need to retrieve the browser aliases and paths before tests compilation.
|
|
261
|
-
const browserInfo = await this._getBrowserInfo();
|
|
262
|
-
if (os_family_1.default.mac)
|
|
263
|
-
await Bootstrapper._checkRequiredPermissions(browserInfo);
|
|
264
|
-
if (os_family_1.default.linux && !detect_display_1.default())
|
|
265
|
-
await Bootstrapper._checkThatTestsCanRunWithoutDisplay(browserInfo);
|
|
266
|
-
if (await this._canUseParallelBootstrapping(browserInfo))
|
|
267
|
-
return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapParallel(browserInfo)), { commonClientScripts });
|
|
268
|
-
return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapSequence(browserInfo)), { commonClientScripts });
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
exports.default = Bootstrapper;
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const is_ci_1 = __importDefault(require("is-ci"));
|
|
9
|
+
const lodash_1 = require("lodash");
|
|
10
|
+
const make_dir_1 = __importDefault(require("make-dir"));
|
|
11
|
+
const os_family_1 = __importDefault(require("os-family"));
|
|
12
|
+
const debug_1 = __importDefault(require("debug"));
|
|
13
|
+
const pretty_hrtime_1 = __importDefault(require("pretty-hrtime"));
|
|
14
|
+
const testcafe_browser_tools_1 = require("testcafe-browser-tools");
|
|
15
|
+
const authentication_helper_1 = __importDefault(require("../cli/authentication-helper"));
|
|
16
|
+
const compiler_1 = __importDefault(require("../compiler"));
|
|
17
|
+
const connection_1 = __importDefault(require("../browser/connection"));
|
|
18
|
+
const pool_1 = __importDefault(require("../browser/provider/pool"));
|
|
19
|
+
const browser_set_1 = __importDefault(require("./browser-set"));
|
|
20
|
+
const remote_1 = __importDefault(require("../browser/provider/built-in/remote"));
|
|
21
|
+
const runtime_1 = require("../errors/runtime");
|
|
22
|
+
const types_1 = require("../errors/types");
|
|
23
|
+
const tested_app_1 = __importDefault(require("./tested-app"));
|
|
24
|
+
const parse_file_list_1 = __importDefault(require("../utils/parse-file-list"));
|
|
25
|
+
const resolve_path_relatively_cwd_1 = __importDefault(require("../utils/resolve-path-relatively-cwd"));
|
|
26
|
+
const load_1 = __importDefault(require("../custom-client-scripts/load"));
|
|
27
|
+
const string_1 = require("../utils/string");
|
|
28
|
+
const detect_display_1 = __importDefault(require("../utils/detect-display"));
|
|
29
|
+
const reporter_1 = require("../utils/reporter");
|
|
30
|
+
const warning_log_1 = __importDefault(require("../notifications/warning-log"));
|
|
31
|
+
const warning_message_1 = __importDefault(require("../notifications/warning-message"));
|
|
32
|
+
const guard_time_execution_1 = __importDefault(require("../utils/guard-time-execution"));
|
|
33
|
+
const DEBUG_SCOPE = 'testcafe:bootstrapper';
|
|
34
|
+
function isPromiseError(value) {
|
|
35
|
+
return value.error !== void 0;
|
|
36
|
+
}
|
|
37
|
+
class Bootstrapper {
|
|
38
|
+
constructor({ browserConnectionGateway, compilerService }) {
|
|
39
|
+
this.browserConnectionGateway = browserConnectionGateway;
|
|
40
|
+
this.concurrency = 1;
|
|
41
|
+
this.sources = [];
|
|
42
|
+
this.browsers = [];
|
|
43
|
+
this.reporters = [];
|
|
44
|
+
this.filter = void 0;
|
|
45
|
+
this.appCommand = void 0;
|
|
46
|
+
this.appInitDelay = void 0;
|
|
47
|
+
this.tsConfigPath = void 0;
|
|
48
|
+
this.clientScripts = [];
|
|
49
|
+
this.disableMultipleWindows = false;
|
|
50
|
+
this.compilerOptions = void 0;
|
|
51
|
+
this.debugLogger = debug_1.default(DEBUG_SCOPE);
|
|
52
|
+
this.warningLog = new warning_log_1.default();
|
|
53
|
+
this.compilerService = compilerService;
|
|
54
|
+
this.TESTS_COMPILATION_UPPERBOUND = 60;
|
|
55
|
+
}
|
|
56
|
+
static _getBrowserName(browser) {
|
|
57
|
+
if (browser instanceof connection_1.default)
|
|
58
|
+
return browser.browserInfo.browserName;
|
|
59
|
+
return browser.browserName;
|
|
60
|
+
}
|
|
61
|
+
static _splitBrowserInfo(browserInfo) {
|
|
62
|
+
const remotes = [];
|
|
63
|
+
const automated = [];
|
|
64
|
+
browserInfo.forEach(browser => {
|
|
65
|
+
if (browser instanceof connection_1.default)
|
|
66
|
+
remotes.push(browser);
|
|
67
|
+
else
|
|
68
|
+
automated.push(browser);
|
|
69
|
+
});
|
|
70
|
+
return { remotes, automated };
|
|
71
|
+
}
|
|
72
|
+
static async _hasLocalBrowsers(browserInfo) {
|
|
73
|
+
for (const browser of browserInfo) {
|
|
74
|
+
if (browser instanceof connection_1.default)
|
|
75
|
+
continue;
|
|
76
|
+
if (await browser.provider.isLocalBrowser(void 0, browser.browserName))
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
static async _checkRequiredPermissions(browserInfo) {
|
|
82
|
+
const hasLocalBrowsers = await Bootstrapper._hasLocalBrowsers(browserInfo);
|
|
83
|
+
const { error } = await authentication_helper_1.default(() => testcafe_browser_tools_1.findWindow(''), testcafe_browser_tools_1.errors.UnableToAccessScreenRecordingAPIError, {
|
|
84
|
+
interactive: hasLocalBrowsers && !is_ci_1.default
|
|
85
|
+
});
|
|
86
|
+
if (!error)
|
|
87
|
+
return;
|
|
88
|
+
if (hasLocalBrowsers)
|
|
89
|
+
throw error;
|
|
90
|
+
remote_1.default.canDetectLocalBrowsers = false;
|
|
91
|
+
}
|
|
92
|
+
static async _checkThatTestsCanRunWithoutDisplay(browserInfoSource) {
|
|
93
|
+
for (let browserInfo of browserInfoSource) {
|
|
94
|
+
if (browserInfo instanceof connection_1.default)
|
|
95
|
+
browserInfo = browserInfo.browserInfo;
|
|
96
|
+
const isLocalBrowser = await browserInfo.provider.isLocalBrowser(void 0, browserInfo.browserName);
|
|
97
|
+
const isHeadlessBrowser = await browserInfo.provider.isHeadlessBrowser(void 0, browserInfo.browserName);
|
|
98
|
+
if (isLocalBrowser && !isHeadlessBrowser) {
|
|
99
|
+
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotRunLocalNonHeadlessBrowserWithoutDisplay, browserInfo.alias);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async _getBrowserInfo() {
|
|
104
|
+
if (!this.browsers.length)
|
|
105
|
+
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserNotSet);
|
|
106
|
+
const browserInfo = await Promise.all(this.browsers.map(browser => pool_1.default.getBrowserInfo(browser)));
|
|
107
|
+
return lodash_1.flatten(browserInfo);
|
|
108
|
+
}
|
|
109
|
+
_createAutomatedConnections(browserInfo) {
|
|
110
|
+
if (!browserInfo)
|
|
111
|
+
return [];
|
|
112
|
+
return browserInfo
|
|
113
|
+
.map(browser => lodash_1.times(this.concurrency, () => new connection_1.default(this.browserConnectionGateway, browser, false, this.disableMultipleWindows)));
|
|
114
|
+
}
|
|
115
|
+
_getBrowserSetOptions() {
|
|
116
|
+
return {
|
|
117
|
+
concurrency: this.concurrency,
|
|
118
|
+
browserInitTimeout: this.browserInitTimeout,
|
|
119
|
+
warningLog: this.warningLog
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
async _getBrowserConnections(browserInfo) {
|
|
123
|
+
const { automated, remotes } = Bootstrapper._splitBrowserInfo(browserInfo);
|
|
124
|
+
if (remotes && remotes.length % this.concurrency)
|
|
125
|
+
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotDivideRemotesCountByConcurrency);
|
|
126
|
+
let browserConnections = this._createAutomatedConnections(automated);
|
|
127
|
+
browserConnections = browserConnections.concat(lodash_1.chunk(remotes, this.concurrency));
|
|
128
|
+
return browser_set_1.default.from(browserConnections, this._getBrowserSetOptions());
|
|
129
|
+
}
|
|
130
|
+
_filterTests(tests, predicate) {
|
|
131
|
+
return tests.filter(test => predicate(test.name, test.fixture.name, test.fixture.path, test.meta, test.fixture.meta));
|
|
132
|
+
}
|
|
133
|
+
async _compileTests({ sourceList, compilerOptions }) {
|
|
134
|
+
if (this.compilerService) {
|
|
135
|
+
await this.compilerService.init();
|
|
136
|
+
return this.compilerService.getTests({ sourceList, compilerOptions });
|
|
137
|
+
}
|
|
138
|
+
const compiler = new compiler_1.default(sourceList, compilerOptions);
|
|
139
|
+
return compiler.getTests();
|
|
140
|
+
}
|
|
141
|
+
async _getTests() {
|
|
142
|
+
const cwd = process.cwd();
|
|
143
|
+
const sourceList = await parse_file_list_1.default(this.sources, cwd);
|
|
144
|
+
if (!sourceList.length)
|
|
145
|
+
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testFilesNotFound, string_1.getConcatenatedValuesString(this.sources, '\n', ''), cwd);
|
|
146
|
+
let tests = await guard_time_execution_1.default(async () => await this._compileTests({ sourceList, compilerOptions: this.compilerOptions }), elapsedTime => {
|
|
147
|
+
this.debugLogger(`tests compilation took ${pretty_hrtime_1.default(elapsedTime)}`);
|
|
148
|
+
const [elapsedSeconds] = elapsedTime;
|
|
149
|
+
if (elapsedSeconds > this.TESTS_COMPILATION_UPPERBOUND)
|
|
150
|
+
this.warningLog.addWarning(warning_message_1.default.testsCompilationTakesTooLong, pretty_hrtime_1.default(elapsedTime));
|
|
151
|
+
});
|
|
152
|
+
const testsWithOnlyFlag = tests.filter(test => test.only);
|
|
153
|
+
if (testsWithOnlyFlag.length)
|
|
154
|
+
tests = testsWithOnlyFlag;
|
|
155
|
+
if (!tests.length)
|
|
156
|
+
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRun);
|
|
157
|
+
if (this.filter)
|
|
158
|
+
tests = this._filterTests(tests, this.filter);
|
|
159
|
+
if (!tests.length)
|
|
160
|
+
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRunDueFiltering);
|
|
161
|
+
return tests;
|
|
162
|
+
}
|
|
163
|
+
async _ensureOutStream(outStream) {
|
|
164
|
+
if (typeof outStream !== 'string')
|
|
165
|
+
return outStream;
|
|
166
|
+
const fullReporterOutputPath = resolve_path_relatively_cwd_1.default(outStream);
|
|
167
|
+
await make_dir_1.default(path_1.default.dirname(fullReporterOutputPath));
|
|
168
|
+
return fs_1.default.createWriteStream(fullReporterOutputPath);
|
|
169
|
+
}
|
|
170
|
+
static _addDefaultReporter(reporters) {
|
|
171
|
+
reporters.push({
|
|
172
|
+
name: 'spec',
|
|
173
|
+
output: process.stdout
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
async _getReporterPlugins() {
|
|
177
|
+
if (!this.reporters.length)
|
|
178
|
+
Bootstrapper._addDefaultReporter(this.reporters);
|
|
179
|
+
return Promise.all(this.reporters.map(async ({ name, output }) => {
|
|
180
|
+
const pluginFactory = reporter_1.getPluginFactory(name);
|
|
181
|
+
const processedName = reporter_1.processReporterName(name);
|
|
182
|
+
const outStream = output ? await this._ensureOutStream(output) : void 0;
|
|
183
|
+
return {
|
|
184
|
+
plugin: pluginFactory(),
|
|
185
|
+
name: processedName,
|
|
186
|
+
outStream
|
|
187
|
+
};
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
async _startTestedApp() {
|
|
191
|
+
if (!this.appCommand)
|
|
192
|
+
return void 0;
|
|
193
|
+
const testedApp = new tested_app_1.default();
|
|
194
|
+
await testedApp.start(this.appCommand, this.appInitDelay);
|
|
195
|
+
return testedApp;
|
|
196
|
+
}
|
|
197
|
+
async _canUseParallelBootstrapping(browserInfo) {
|
|
198
|
+
const isLocalPromises = browserInfo.map(browser => browser.provider.isLocalBrowser(void 0, Bootstrapper._getBrowserName(browser)));
|
|
199
|
+
const isLocalBrowsers = await Promise.all(isLocalPromises);
|
|
200
|
+
return isLocalBrowsers.every(result => result);
|
|
201
|
+
}
|
|
202
|
+
async _bootstrapSequence(browserInfo) {
|
|
203
|
+
const tests = await this._getTests();
|
|
204
|
+
const testedApp = await this._startTestedApp();
|
|
205
|
+
const browserSet = await this._getBrowserConnections(browserInfo);
|
|
206
|
+
return { tests, testedApp, browserSet };
|
|
207
|
+
}
|
|
208
|
+
_wrapBootstrappingPromise(promise) {
|
|
209
|
+
return promise
|
|
210
|
+
.then(result => ({ error: void 0, result }))
|
|
211
|
+
.catch(error => ({ result: void 0, error }));
|
|
212
|
+
}
|
|
213
|
+
async _getBootstrappingError(browserSetStatus, testsStatus, testedAppStatus) {
|
|
214
|
+
if (!isPromiseError(browserSetStatus))
|
|
215
|
+
await browserSetStatus.result.dispose();
|
|
216
|
+
if (!isPromiseError(browserSetStatus) && !isPromiseError(testedAppStatus) && testedAppStatus.result)
|
|
217
|
+
await testedAppStatus.result.kill();
|
|
218
|
+
if (isPromiseError(testsStatus))
|
|
219
|
+
return testsStatus.error;
|
|
220
|
+
if (isPromiseError(testedAppStatus))
|
|
221
|
+
return testedAppStatus.error;
|
|
222
|
+
if (isPromiseError(browserSetStatus))
|
|
223
|
+
return browserSetStatus.error;
|
|
224
|
+
return new Error('Unexpected call');
|
|
225
|
+
}
|
|
226
|
+
_getBootstrappingPromises(arg) {
|
|
227
|
+
const result = {};
|
|
228
|
+
for (const k in arg)
|
|
229
|
+
result[k] = this._wrapBootstrappingPromise(arg[k]);
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
async _bootstrapParallel(browserInfo) {
|
|
233
|
+
const bootstrappingPromises = {
|
|
234
|
+
browserSet: this._getBrowserConnections(browserInfo),
|
|
235
|
+
tests: this._getTests(),
|
|
236
|
+
app: this._startTestedApp()
|
|
237
|
+
};
|
|
238
|
+
const bootstrappingResultPromises = this._getBootstrappingPromises(bootstrappingPromises);
|
|
239
|
+
const bootstrappingResults = await Promise.all([
|
|
240
|
+
bootstrappingResultPromises.browserSet,
|
|
241
|
+
bootstrappingResultPromises.tests,
|
|
242
|
+
bootstrappingResultPromises.app
|
|
243
|
+
]);
|
|
244
|
+
const [browserSetResults, testResults, appResults] = bootstrappingResults;
|
|
245
|
+
if (isPromiseError(browserSetResults) || isPromiseError(testResults) || isPromiseError(appResults))
|
|
246
|
+
throw await this._getBootstrappingError(...bootstrappingResults);
|
|
247
|
+
return {
|
|
248
|
+
browserSet: browserSetResults.result,
|
|
249
|
+
tests: testResults.result,
|
|
250
|
+
testedApp: appResults.result
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// API
|
|
254
|
+
async createRunnableConfiguration() {
|
|
255
|
+
const reporterPlugins = await this._getReporterPlugins();
|
|
256
|
+
const commonClientScripts = await load_1.default(this.clientScripts);
|
|
257
|
+
// NOTE: If a user forgot to specify a browser, but has specified a path to tests, the specified path will be
|
|
258
|
+
// considered as the browser argument, and the tests path argument will have the predefined default value.
|
|
259
|
+
// It's very ambiguous for the user, who might be confused by compilation errors from an unexpected test.
|
|
260
|
+
// So, we need to retrieve the browser aliases and paths before tests compilation.
|
|
261
|
+
const browserInfo = await this._getBrowserInfo();
|
|
262
|
+
if (os_family_1.default.mac)
|
|
263
|
+
await Bootstrapper._checkRequiredPermissions(browserInfo);
|
|
264
|
+
if (os_family_1.default.linux && !detect_display_1.default())
|
|
265
|
+
await Bootstrapper._checkThatTestsCanRunWithoutDisplay(browserInfo);
|
|
266
|
+
if (await this._canUseParallelBootstrapping(browserInfo))
|
|
267
|
+
return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapParallel(browserInfo)), { commonClientScripts });
|
|
268
|
+
return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapSequence(browserInfo)), { commonClientScripts });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
exports.default = Bootstrapper;
|
|
272
272
|
module.exports = exports.default;
|
|
273
273
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bm5lci9ib290c3RyYXBwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxnREFBd0I7QUFDeEIsNENBQW9CO0FBQ3BCLGtEQUF5QjtBQUN6QixtQ0FJZ0I7QUFFaEIsd0RBQStCO0FBQy9CLDBEQUEyQjtBQUMzQixrREFBMEI7QUFDMUIsa0VBQXVDO0FBQ3ZDLG1FQUE0RDtBQUM1RCx5RkFBZ0U7QUFDaEUsMkRBQW1DO0FBQ25DLHVFQUF1RTtBQUN2RSxvRUFBMkQ7QUFDM0QsZ0VBQXVDO0FBQ3ZDLGlGQUF3RTtBQUN4RSwrQ0FBaUQ7QUFDakQsMkNBQWlEO0FBQ2pELDhEQUFxQztBQUNyQywrRUFBcUQ7QUFDckQsdUdBQTRFO0FBQzVFLHlFQUE4RDtBQUM5RCw0Q0FBOEQ7QUFXOUQsNkVBQW9EO0FBQ3BELGdEQUEwRTtBQUUxRSwrRUFBc0Q7QUFDdEQsdUZBQWdFO0FBQ2hFLHlGQUErRDtBQUUvRCxNQUFNLFdBQVcsR0FBRyx1QkFBdUIsQ0FBQztBQWlDNUMsU0FBUyxjQUFjLENBQThCLEtBQTBCO0lBQzNFLE9BQVEsS0FBeUIsQ0FBQyxLQUFLLEtBQUssS0FBSyxDQUFDLENBQUM7QUFDdkQsQ0FBQztBQWFELE1BQXFCLFlBQVk7SUFxQjdCLFlBQW9CLEVBQUUsd0JBQXdCLEVBQUUsZUFBZSxFQUFvQjtRQUMvRSxJQUFJLENBQUMsd0JBQXdCLEdBQUcsd0JBQXdCLENBQUM7UUFDekQsSUFBSSxDQUFDLFdBQVcsR0FBZ0IsQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxPQUFPLEdBQW9CLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsUUFBUSxHQUFtQixFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLFNBQVMsR0FBa0IsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxNQUFNLEdBQXFCLEtBQUssQ0FBQyxDQUFDO1FBQ3ZDLElBQUksQ0FB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b3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCBpc0NJIGZyb20gJ2lzLWNpJztcbmltcG9ydCB7XG4gICAgZmxhdHRlbixcbiAgICBjaHVuayxcbiAgICB0aW1lc1xufSBmcm9tICdsb2Rhc2gnO1xuXG5pbXBvcnQgbWFrZURpciBmcm9tICdtYWtlLWRpcic7XG5pbXBvcnQgT1MgZnJvbSAnb3MtZmFtaWx5JztcbmltcG9ydCBkZWJ1ZyBmcm9tICdkZWJ1Zyc7XG5pbXBvcnQgcHJldHR5VGltZSBmcm9tICdwcmV0dHktaHJ0aW1lJztcbmltcG9ydCB7IGVycm9ycywgZmluZFdpbmRvdyB9IGZyb20gJ3Rlc3RjYWZlLWJyb3dzZXItdG9vbHMnO1xuaW1wb3J0IGF1dGhlbnRpY2F0aW9uSGVscGVyIGZyb20gJy4uL2NsaS9hdXRoZW50aWNhdGlvbi1oZWxwZXInO1xuaW1wb3J0IENvbXBpbGVyIGZyb20gJy4uL2NvbXBpbGVyJztcbmltcG9ydCBCcm93c2VyQ29ubmVjdGlvbiwgeyBCcm93c2VySW5mbyB9IGZyb20gJy4uL2Jyb3dzZXIvY29ubmVjdGlvbic7XG5pbXBvcnQgYnJvd3NlclByb3ZpZGVyUG9vbCBmcm9tICcuLi9icm93c2VyL3Byb3ZpZGVyL3Bvb2wnO1xuaW1wb3J0IEJyb3dzZXJTZXQgZnJvbSAnLi9icm93c2VyLXNldCc7XG5pbXBvcnQgUmVtb3RlQnJvd3NlclByb3ZpZGVyIGZyb20gJy4uL2Jyb3dzZXIvcHJvdmlkZXIvYnVpbHQtaW4vcmVtb3RlJztcbmltcG9ydCB7IEdlbmVyYWxFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9ydW50aW1lJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcbmltcG9ydCBUZXN0ZWRBcHAgZnJvbSAnLi90ZXN0ZWQtYXBwJztcbmltcG9ydCBwYXJzZUZpbGVMaXN0IGZyb20gJy4uL3V0aWxzL3BhcnNlLWZpbGUtbGlzdCc7XG5pbXBvcnQgcmVzb2x2ZVBhdGhSZWxhdGl2ZWx5Q3dkIGZyb20gJy4uL3V0aWxzL3Jlc29sdmUtcGF0aC1yZWxhdGl2ZWx5LWN3ZCc7XG5pbXBvcnQgbG9hZENsaWVudFNjcmlwdHMgZnJvbSAnLi4vY3VzdG9tLWNsaWVudC1zY3JpcHRzL2xvYWQnO1xuaW1wb3J0IHsgZ2V0Q29uY2F0ZW5hdGVkVmFsdWVzU3RyaW5nIH0gZnJvbSAnLi4vdXRpbHMvc3RyaW5nJztcblxuaW1wb3J0IHsgV3JpdGFibGUgYXMgV3JpdGFibGVTdHJlYW0gfSBmcm9tICdzdHJlYW0nO1xuaW1wb3J0IHsgUmVwb3J0ZXJTb3VyY2UsIFJlcG9ydGVyUGx1Z2luU291cmNlIH0gZnJvbSAnLi4vcmVwb3J0ZXIvaW50ZXJmYWNlcyc7XG5pbXBvcnQgQ2xpZW50U2NyaXB0IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9jbGllbnQtc2NyaXB0JztcbmltcG9ydCBDbGllbnRTY3JpcHRJbml0IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9jbGllbnQtc2NyaXB0LWluaXQnO1xuaW1wb3J0IEJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSBmcm9tICcuLi9icm93c2VyL2Nvbm5lY3Rpb24vZ2F0ZXdheSc7XG5pbXBvcnQgeyBDb21waWxlckFyZ3VtZW50cyB9IGZyb20gJy4uL2NvbXBpbGVyL2ludGVyZmFjZXMnO1xuaW1wb3J0IENvbXBpbGVyU2VydmljZSBmcm9tICcuLi9zZXJ2aWNlcy9jb21waWxlci9ob3N0JztcbmltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSAnLi4vYXBpL3N0cnVjdHVyZS9pbnRlcmZhY2VzJztcbmltcG9ydCBUZXN0IGZyb20gJy4uL2FwaS9zdHJ1Y3R1cmUvdGVzdCc7XG5pbXBvcnQgZGV0ZWN0RGlzcGxheSBmcm9tICcuLi91dGlscy9kZXRlY3QtZGlzcGxheSc7XG5pbXBvcnQgeyBnZXRQbHVnaW5GYWN0b3J5LCBwcm9jZXNzUmVwb3J0ZXJOYW1lIH0gZnJvbSAnLi4vdXRpbHMvcmVwb3J0ZXInO1xuaW1wb3J0IHsgQm9vdHN0cmFwcGVySW5pdCwgQnJvd3NlclNldE9wdGlvbnMgfSBmcm9tICcuL2ludGVyZmFjZXMnO1xuaW1wb3J0IFdhcm5pbmdMb2cgZnJvbSAnLi4vbm90aWZpY2F0aW9ucy93YXJuaW5nLWxvZyc7XG5pbXBvcnQgV0FSTklOR19NRVNTQUdFUyBmcm9tICcuLi9ub3RpZmljYXRpb25zL3dhcm5pbmctbWVzc2FnZSc7XG5pbXBvcnQgZ3VhcmRUaW1lRXhlY3V0aW9uIGZyb20gJy4uL3V0aWxzL2d1YXJkLXRpbWUtZXhlY3V0aW9uJztcblxuY29uc3QgREVCVUdfU0NPUEUgPSAndGVzdGNhZmU6Ym9vdHN0cmFwcGVyJztcblxudHlwZSBUZXN0U291cmNlID0gdW5rbm93bjtcblxudHlwZSBCcm93c2VyU291cmNlID0gQnJvd3NlckNvbm5lY3Rpb24gfCBzdHJpbmc7XG5cbmludGVyZmFjZSBGaWx0ZXIge1xuICAgICh0ZXN0TmFtZTogc3RyaW5nLCBmaXh0dXJlTmFtZTogc3RyaW5nLCBmaXh0dXJlUGF0aDogc3RyaW5nLCB0ZXN0TWV0YTogTWV0YWRhdGEsIGZpeHR1cmVNZXRhOiBNZXRhZGF0YSk6IGJvb2xlYW47XG59XG5cbnR5cGUgQnJvd3NlckluZm9Tb3VyY2UgPSBCcm93c2VySW5mbyB8IEJyb3dzZXJDb25uZWN0aW9uO1xuXG5pbnRlcmZhY2UgUHJvbWlzZVN1Y2Nlc3M8VD4ge1xuICAgIHJlc3VsdDogVDtcbn1cblxuaW50ZXJmYWNlIFByb21pc2VFcnJvcjxFIGV4dGVuZHMgRXJyb3IgPSBFcnJvcj4ge1xuICAgIGVycm9yOiBFO1xufVxuXG5pbnRlcmZhY2UgQmFzaWNSdW50aW1lUmVzb3VyY2VzIHtcbiAgICBicm93c2VyU2V0OiBCcm93c2VyU2V0O1xuICAgIHRlc3RzOiBUZXN0W107XG4gICAgdGVzdGVkQXBwPzogVGVzdGVkQXBwO1xufVxuXG5pbnRlcmZhY2UgUnVudGltZVJlc291cmNlcyBleHRlbmRzIEJhc2ljUnVudGltZVJlc291cmNlcyB7XG4gICAgcmVwb3J0ZXJQbHVnaW5zOiBSZXBvcnRlclBsdWdpblNvdXJjZVtdO1xuICAgIGNvbW1vbkNsaWVudFNjcmlwdHM6IENsaWVudFNjcmlwdFtdO1xufVxuXG50eXBlIFByb21pc2VSZXN1bHQ8VCwgRSBleHRlbmRzIEVycm9yID0gRXJyb3I+ID0gUHJvbWlzZVN1Y2Nlc3M8VD4gfCBQcm9taXNlRXJyb3I8RT47XG5cbmZ1bmN0aW9uIGlzUHJvbWlzZUVycm9yPFQsIEUgZXh0ZW5kcyBFcnJvciA9IEVycm9yPiAodmFsdWU6IFByb21pc2VSZXN1bHQ8VCwgRT4pOiB2YWx1ZSBpcyBQcm9taXNlRXJyb3I8RT4ge1xuICAgIHJldHVybiAodmFsdWUgYXMgUHJvbWlzZUVycm9yPEU+KS5lcnJvciAhPT0gdm9pZCAwO1xufVxuXG5pbnRlcmZhY2UgU2VwYXJhdGVkQnJvd3NlckluZm8ge1xuICAgIHJlbW90ZXM6IEJyb3dzZXJDb25uZWN0aW9uW107XG4gICAgYXV0b21hdGVkOiBCcm93c2VySW5mb1tdO1xufVxuXG50eXBlIFByb21pc2VDb2xsZWN0aW9uPFQ+ID0ge1xuICAgIFtLIGluIGtleW9mIFRdOiBQcm9taXNlPFRbS10+XG59XG5cbnR5cGUgUmVzdWx0Q29sbGVjdGlvbjxUPiA9IHsgW1AgaW4ga2V5b2YgVF06IFByb21pc2VSZXN1bHQ8VFtQXT4gfTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQm9vdHN0cmFwcGVyIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheTogQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5O1xuICAgIHB1YmxpYyBjb25jdXJyZW5jeTogbnVtYmVyO1xuICAgIHB1YmxpYyBzb3VyY2VzOiBUZXN0U291cmNlW107XG4gICAgcHVibGljIGJyb3dzZXJzOiBCcm93c2VyU291cmNlW107XG4gICAgcHVibGljIHJlcG9ydGVyczogUmVwb3J0ZXJTb3VyY2VbXTtcbiAgICBwdWJsaWMgZmlsdGVyPzogRmlsdGVyO1xuICAgIHB1YmxpYyBhcHBDb21tYW5kPzogc3RyaW5nO1xuICAgIHB1YmxpYyBhcHBJbml0RGVsYXk/OiBudW1iZXI7XG4gICAgcHVibGljIHRzQ29uZmlnUGF0aD86IHN0cmluZztcbiAgICBwdWJsaWMgY2xpZW50U2NyaXB0czogQ2xpZW50U2NyaXB0SW5pdFtdO1xuICAgIHB1YmxpYyBkaXNhYmxlTXVsdGlwbGVXaW5kb3dzOiBib29sZWFuO1xuICAgIHB1YmxpYyBjb21waWxlck9wdGlvbnM/OiBDb21waWxlck9wdGlvbnM7XG4gICAgcHVibGljIGJyb3dzZXJJbml0VGltZW91dD86IG51bWJlcjtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgY29tcGlsZXJTZXJ2aWNlPzogQ29tcGlsZXJTZXJ2aWNlO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVidWdMb2dnZXI6IGRlYnVnLkRlYnVnZ2VyO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgd2FybmluZ0xvZzogV2FybmluZ0xvZztcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgVEVTVFNfQ09NUElMQVRJT05fVVBQRVJCT1VORDogbnVtYmVyO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yICh7IGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSwgY29tcGlsZXJTZXJ2aWNlIH06IEJvb3RzdHJhcHBlckluaXQpIHtcbiAgICAgICAgdGhpcy5icm93c2VyQ29ubmVjdGlvbkdhdGV3YXkgPSBicm93c2VyQ29ubmVjdGlvbkdhdGV3YXk7XG4gICAgICAgIHRoaXMuY29uY3VycmVuY3kgICAgICAgICAgICAgID0gMTtcbiAgICAgICAgdGhpcy5zb3VyY2VzICAgICAgICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5icm93c2VycyAgICAgICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5yZXBvcnRlcnMgICAgICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5maWx0ZXIgICAgICAgICAgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMuYXBwQ29tbWFuZCAgICAgICAgICAgICAgID0gdm9pZCAwO1xuICAgICAgICB0aGlzLmFwcEluaXREZWxheSAgICAgICAgICAgICA9IHZvaWQgMDtcbiAgICAgICAgdGhpcy50c0NvbmZpZ1BhdGggICAgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMuY2xpZW50U2NyaXB0cyAgICAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMuZGlzYWJsZU11bHRpcGxlV2luZG93cyAgID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY29tcGlsZXJPcHRpb25zICAgICAgICAgID0gdm9pZCAwO1xuICAgICAgICB0aGlzLmRlYnVnTG9nZ2VyICAgICAgICAgICAgICA9IGRlYnVnKERFQlVHX1NDT1BFKTtcbiAgICAgICAgdGhpcy53YXJuaW5nTG9nICAgICAgICAgICAgICAgPSBuZXcgV2FybmluZ0xvZygpO1xuICAgICAgICB0aGlzLmNvbXBpbGVyU2VydmljZSAgICAgICAgICA9IGNvbXBpbGVyU2VydmljZTtcblxuICAgICAgICB0aGlzLlRFU1RTX0NPTVBJTEFUSU9OX1VQUEVSQk9VTkQgPSA2MDtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBfZ2V0QnJvd3Nlck5hbWUgKGJyb3dzZXI6IEJyb3dzZXJJbmZvU291cmNlKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKGJyb3dzZXIgaW5zdGFuY2VvZiBCcm93c2VyQ29ubmVjdGlvbilcbiAgICAgICAgICAgIHJldHVybiBicm93c2VyLmJyb3dzZXJJbmZvLmJyb3dzZXJOYW1lO1xuXG4gICAgICAgIHJldHVybiBicm93c2VyLmJyb3dzZXJOYW1lO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9zcGxpdEJyb3dzZXJJbmZvIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFNlcGFyYXRlZEJyb3dzZXJJbmZvIHtcbiAgICAgICAgY29uc3QgcmVtb3RlczogQnJvd3NlckNvbm5lY3Rpb25bXSAgPSBbXTtcbiAgICAgICAgY29uc3QgYXV0b21hdGVkOiBCcm93c2VySW5mb1tdICAgICAgPSBbXTtcblxuICAgICAgICBicm93c2VySW5mby5mb3JFYWNoKGJyb3dzZXIgPT4ge1xuICAgICAgICAgICAgaWYgKGJyb3dzZXIgaW5zdGFuY2VvZiBCcm93c2VyQ29ubmVjdGlvbilcbiAgICAgICAgICAgICAgICByZW1vdGVzLnB1c2goYnJvd3Nlcik7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgYXV0b21hdGVkLnB1c2goYnJvd3Nlcik7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB7IHJlbW90ZXMsIGF1dG9tYXRlZCB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIGFzeW5jIF9oYXNMb2NhbEJyb3dzZXJzIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBmb3IgKGNvbnN0IGJyb3dzZXIgb2YgYnJvd3NlckluZm8pIHtcbiAgICAgICAgICAgIGlmIChicm93c2VyIGluc3RhbmNlb2YgQnJvd3NlckNvbm5lY3Rpb24pXG4gICAgICAgICAgICAgICAgY29udGludWU7XG5cbiAgICAgICAgICAgIGlmIChhd2FpdCBicm93c2VyLnByb3ZpZGVyLmlzTG9jYWxCcm93c2VyKHZvaWQgMCwgYnJvd3Nlci5icm93c2VyTmFtZSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgX2NoZWNrUmVxdWlyZWRQZXJtaXNzaW9ucyAoYnJvd3NlckluZm86IEJyb3dzZXJJbmZvU291cmNlW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgaGFzTG9jYWxCcm93c2VycyA9IGF3YWl0IEJvb3RzdHJhcHBlci5faGFzTG9jYWxCcm93c2Vycyhicm93c2VySW5mbyk7XG5cbiAgICAgICAgY29uc3QgeyBlcnJvciB9ID0gYXdhaXQgYXV0aGVudGljYXRpb25IZWxwZXIoXG4gICAgICAgICAgICAoKSA9PiBmaW5kV2luZG93KCcnKSxcbiAgICAgICAgICAgIGVycm9ycy5VbmFibGVUb0FjY2Vzc1NjcmVlblJlY29yZGluZ0FQSUVycm9yLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGludGVyYWN0aXZlOiBoYXNMb2NhbEJyb3dzZXJzICYmICFpc0NJXG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKCFlcnJvcilcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBpZiAoaGFzTG9jYWxCcm93c2VycylcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuXG4gICAgICAgIFJlbW90ZUJyb3dzZXJQcm92aWRlci5jYW5EZXRlY3RMb2NhbEJyb3dzZXJzID0gZmFsc2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgX2NoZWNrVGhhdFRlc3RzQ2FuUnVuV2l0aG91dERpc3BsYXkgKGJyb3dzZXJJbmZvU291cmNlOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGZvciAobGV0IGJyb3dzZXJJbmZvIG9mIGJyb3dzZXJJbmZvU291cmNlKSB7XG4gICAgICAgICAgICBpZiAoYnJvd3NlckluZm8gaW5zdGFuY2VvZiBCcm93c2VyQ29ubmVjdGlvbilcbiAgICAgICAgICAgICAgICBicm93c2VySW5mbyA9IGJyb3dzZXJJbmZvLmJyb3dzZXJJbmZvO1xuXG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsQnJvd3NlciAgICA9IGF3YWl0IGJyb3dzZXJJbmZvLnByb3ZpZGVyLmlzTG9jYWxCcm93c2VyKHZvaWQgMCwgYnJvd3NlckluZm8uYnJvd3Nlck5hbWUpO1xuICAgICAgICAgICAgY29uc3QgaXNIZWFkbGVzc0Jyb3dzZXIgPSBhd2FpdCBicm93c2VySW5mby5wcm92aWRlci5pc0hlYWRsZXNzQnJvd3Nlcih2b2lkIDAsIGJyb3dzZXJJbmZvLmJyb3dzZXJOYW1lKTtcblxuICAgICAgICAgICAgaWYgKGlzTG9jYWxCcm93c2VyICYmICFpc0hlYWRsZXNzQnJvd3Nlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIFJVTlRJTUVfRVJST1JTLmNhbm5vdFJ1bkxvY2FsTm9uSGVhZGxlc3NCcm93c2VyV2l0aG91dERpc3BsYXksXG4gICAgICAgICAgICAgICAgICAgIGJyb3dzZXJJbmZvLmFsaWFzXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldEJyb3dzZXJJbmZvICgpOiBQcm9taXNlPEJyb3dzZXJJbmZvU291cmNlW10+IHtcbiAgICAgICAgaWYgKCF0aGlzLmJyb3dzZXJzLmxlbmd0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuYnJvd3Nlck5vdFNldCk7XG5cbiAgICAgICAgY29uc3QgYnJvd3NlckluZm8gPSBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmJyb3dzZXJzLm1hcChicm93c2VyID0+IGJyb3dzZXJQcm92aWRlclBvb2wuZ2V0QnJvd3NlckluZm8oYnJvd3NlcikpKTtcblxuICAgICAgICByZXR1cm4gZmxhdHRlbihicm93c2VySW5mbyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfY3JlYXRlQXV0b21hdGVkQ29ubmVjdGlvbnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1tdKTogQnJvd3NlckNvbm5lY3Rpb25bXVtdIHtcbiAgICAgICAgaWYgKCFicm93c2VySW5mbylcbiAgICAgICAgICAgIHJldHVybiBbXTtcblxuICAgICAgICByZXR1cm4gYnJvd3NlckluZm9cbiAgICAgICAgICAgIC5tYXAoYnJvd3NlciA9PiB0aW1lcyh0aGlzLmNvbmN1cnJlbmN5LCAoKSA9PiBuZXcgQnJvd3NlckNvbm5lY3Rpb24odGhpcy5icm93c2VyQ29ubmVjdGlvbkdhdGV3YXksIGJyb3dzZXIsIGZhbHNlLCB0aGlzLmRpc2FibGVNdWx0aXBsZVdpbmRvd3MpKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0QnJvd3NlclNldE9wdGlvbnMgKCk6IEJyb3dzZXJTZXRPcHRpb25zIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNvbmN1cnJlbmN5OiAgICAgICAgdGhpcy5jb25jdXJyZW5jeSxcbiAgICAgICAgICAgIGJyb3dzZXJJbml0VGltZW91dDogdGhpcy5icm93c2VySW5pdFRpbWVvdXQsXG4gICAgICAgICAgICB3YXJuaW5nTG9nOiAgICAgICAgIHRoaXMud2FybmluZ0xvZ1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldEJyb3dzZXJDb25uZWN0aW9ucyAoYnJvd3NlckluZm86IEJyb3dzZXJJbmZvU291cmNlW10pOiBQcm9taXNlPEJyb3dzZXJTZXQ+IHtcbiAgICAgICAgY29uc3QgeyBhdXRvbWF0ZWQsIHJlbW90ZXMgfSA9IEJvb3RzdHJhcHBlci5fc3BsaXRCcm93c2VySW5mbyhicm93c2VySW5mbyk7XG5cbiAgICAgICAgaWYgKHJlbW90ZXMgJiYgcmVtb3Rlcy5sZW5ndGggJSB0aGlzLmNvbmN1cnJlbmN5KVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5jYW5ub3REaXZpZGVSZW1vdGVzQ291bnRCeUNvbmN1cnJlbmN5KTtcblxuICAgICAgICBsZXQgYnJvd3NlckNvbm5lY3Rpb25zID0gdGhpcy5fY3JlYXRlQXV0b21hdGVkQ29ubmVjdGlvbnMoYXV0b21hdGVkKTtcblxuICAgICAgICBicm93c2VyQ29ubmVjdGlvbnMgPSBicm93c2VyQ29ubmVjdGlvbnMuY29uY2F0KGNodW5rKHJlbW90ZXMsIHRoaXMuY29uY3VycmVuY3kpKTtcblxuICAgICAgICByZXR1cm4gQnJvd3NlclNldC5mcm9tKGJyb3dzZXJDb25uZWN0aW9ucywgdGhpcy5fZ2V0QnJvd3NlclNldE9wdGlvbnMoKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZmlsdGVyVGVzdHMgKHRlc3RzOiBUZXN0W10sIHByZWRpY2F0ZTogRmlsdGVyKTogVGVzdFtdIHtcbiAgICAgICAgcmV0dXJuIHRlc3RzLmZpbHRlcih0ZXN0ID0+IHByZWRpY2F0ZSh0ZXN0Lm5hbWUgYXMgc3RyaW5nLCB0ZXN0LmZpeHR1cmUubmFtZSBhcyBzdHJpbmcsIHRlc3QuZml4dHVyZS5wYXRoLCB0ZXN0Lm1ldGEsIHRlc3QuZml4dHVyZS5tZXRhKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY29tcGlsZVRlc3RzICh7IHNvdXJjZUxpc3QsIGNvbXBpbGVyT3B0aW9ucyB9OiBDb21waWxlckFyZ3VtZW50cyk6IFByb21pc2U8VGVzdFtdPiB7XG4gICAgICAgIGlmICh0aGlzLmNvbXBpbGVyU2VydmljZSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jb21waWxlclNlcnZpY2UuaW5pdCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb21waWxlclNlcnZpY2UuZ2V0VGVzdHMoeyBzb3VyY2VMaXN0LCBjb21waWxlck9wdGlvbnMgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb21waWxlciA9IG5ldyBDb21waWxlcihzb3VyY2VMaXN0LCBjb21waWxlck9wdGlvbnMpO1xuXG4gICAgICAgIHJldHVybiBjb21waWxlci5nZXRUZXN0cygpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldFRlc3RzICgpOiBQcm9taXNlPFRlc3RbXT4ge1xuICAgICAgICBjb25zdCBjd2QgICAgICAgID0gcHJvY2Vzcy5jd2QoKTtcbiAgICAgICAgY29uc3Qgc291cmNlTGlzdCA9IGF3YWl0IHBhcnNlRmlsZUxpc3QodGhpcy5zb3VyY2VzLCBjd2QpO1xuXG4gICAgICAgIGlmICghc291cmNlTGlzdC5sZW5ndGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLnRlc3RGaWxlc05vdEZvdW5kLCBnZXRDb25jYXRlbmF0ZWRWYWx1ZXNTdHJpbmcodGhpcy5zb3VyY2VzLCAnXFxuJywgJycpLCBjd2QpO1xuXG4gICAgICAgIGxldCB0ZXN0cyA9IGF3YWl0IGd1YXJkVGltZUV4ZWN1dGlvbihcbiAgICAgICAgICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMuX2NvbXBpbGVUZXN0cyh7IHNvdXJjZUxpc3QsIGNvbXBpbGVyT3B0aW9uczogdGhpcy5jb21waWxlck9wdGlvbnMgfSksXG4gICAgICAgICAgICBlbGFwc2VkVGltZSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5kZWJ1Z0xvZ2dlcihgdGVzdHMgY29tcGlsYXRpb24gdG9vayAke3ByZXR0eVRpbWUoZWxhcHNlZFRpbWUpfWApO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgWyBlbGFwc2VkU2Vjb25kcyBdID0gZWxhcHNlZFRpbWU7XG5cbiAgICAgICAgICAgICAgICBpZiAoZWxhcHNlZFNlY29uZHMgPiB0aGlzLlRFU1RTX0NPTVBJTEFUSU9OX1VQUEVSQk9VTkQpXG4gICAgICAgICAgICAgICAgICAgIHRoaXMud2FybmluZ0xvZy5hZGRXYXJuaW5nKFdBUk5JTkdfTUVTU0FHRVMudGVzdHNDb21waWxhdGlvblRha2VzVG9vTG9uZywgcHJldHR5VGltZShlbGFwc2VkVGltZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IHRlc3RzV2l0aE9ubHlGbGFnID0gdGVzdHMuZmlsdGVyKHRlc3QgPT4gdGVzdC5vbmx5KTtcblxuICAgICAgICBpZiAodGVzdHNXaXRoT25seUZsYWcubGVuZ3RoKVxuICAgICAgICAgICAgdGVzdHMgPSB0ZXN0c1dpdGhPbmx5RmxhZztcblxuICAgICAgICBpZiAoIXRlc3RzLmxlbmd0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMubm9UZXN0c1RvUnVuKTtcblxuICAgICAgICBpZiAodGhpcy5maWx0ZXIpXG4gICAgICAgICAgICB0ZXN0cyA9IHRoaXMuX2ZpbHRlclRlc3RzKHRlc3RzLCB0aGlzLmZpbHRlcik7XG5cbiAgICAgICAgaWYgKCF0ZXN0cy5sZW5ndGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLm5vVGVzdHNUb1J1bkR1ZUZpbHRlcmluZyk7XG5cbiAgICAgICAgcmV0dXJuIHRlc3RzO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2Vuc3VyZU91dFN0cmVhbSAob3V0U3RyZWFtOiBzdHJpbmcgfCBXcml0YWJsZVN0cmVhbSk6IFByb21pc2U8V3JpdGFibGVTdHJlYW0+IHtcbiAgICAgICAgaWYgKHR5cGVvZiBvdXRTdHJlYW0gIT09ICdzdHJpbmcnKVxuICAgICAgICAgICAgcmV0dXJuIG91dFN0cmVhbTtcblxuICAgICAgICBjb25zdCBmdWxsUmVwb3J0ZXJPdXRwdXRQYXRoID0gcmVzb2x2ZVBhdGhSZWxhdGl2ZWx5Q3dkKG91dFN0cmVhbSk7XG5cbiAgICAgICAgYXdhaXQgbWFrZURpcihwYXRoLmRpcm5hbWUoZnVsbFJlcG9ydGVyT3V0cHV0UGF0aCkpO1xuXG4gICAgICAgIHJldHVybiBmcy5jcmVhdGVXcml0ZVN0cmVhbShmdWxsUmVwb3J0ZXJPdXRwdXRQYXRoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBfYWRkRGVmYXVsdFJlcG9ydGVyIChyZXBvcnRlcnM6IFJlcG9ydGVyU291cmNlW10pOiB2b2lkIHtcbiAgICAgICAgcmVwb3J0ZXJzLnB1c2goe1xuICAgICAgICAgICAgbmFtZTogICAnc3BlYycsXG4gICAgICAgICAgICBvdXRwdXQ6IHByb2Nlc3Muc3Rkb3V0XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldFJlcG9ydGVyUGx1Z2lucyAoKTogUHJvbWlzZTxSZXBvcnRlclBsdWdpblNvdXJjZVtdPiB7XG4gICAgICAgIGlmICghdGhpcy5yZXBvcnRlcnMubGVuZ3RoKVxuICAgICAgICAgICAgQm9vdHN0cmFwcGVyLl9hZGREZWZhdWx0UmVwb3J0ZXIodGhpcy5yZXBvcnRlcnMpO1xuXG4gICAgICAgIHJldHVybiBQcm9taXNlLmFsbCh0aGlzLnJlcG9ydGVycy5tYXAoYXN5bmMgKHsgbmFtZSwgb3V0cHV0IH0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBsdWdpbkZhY3RvcnkgPSBnZXRQbHVnaW5GYWN0b3J5KG5hbWUpO1xuICAgICAgICAgICAgY29uc3QgcHJvY2Vzc2VkTmFtZSA9IHByb2Nlc3NSZXBvcnRlck5hbWUobmFtZSk7XG4gICAgICAgICAgICBjb25zdCBvdXRTdHJlYW0gICAgID0gb3V0cHV0ID8gYXdhaXQgdGhpcy5fZW5zdXJlT3V0U3RyZWFtKG91dHB1dCkgOiB2b2lkIDA7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcGx1Z2luOiBwbHVnaW5GYWN0b3J5KCksXG4gICAgICAgICAgICAgICAgbmFtZTogICBwcm9jZXNzZWROYW1lLFxuICAgICAgICAgICAgICAgIG91dFN0cmVhbVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3N0YXJ0VGVzdGVkQXBwICgpOiBQcm9taXNlPFRlc3RlZEFwcHx1bmRlZmluZWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLmFwcENvbW1hbmQpXG4gICAgICAgICAgICByZXR1cm4gdm9pZCAwO1xuXG4gICAgICAgIGNvbnN0IHRlc3RlZEFwcCA9IG5ldyBUZXN0ZWRBcHAoKTtcblxuICAgICAgICBhd2FpdCB0ZXN0ZWRBcHAuc3RhcnQodGhpcy5hcHBDb21tYW5kLCB0aGlzLmFwcEluaXREZWxheSBhcyBudW1iZXIpO1xuXG4gICAgICAgIHJldHVybiB0ZXN0ZWRBcHA7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY2FuVXNlUGFyYWxsZWxCb290c3RyYXBwaW5nIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBjb25zdCBpc0xvY2FsUHJvbWlzZXMgPSBicm93c2VySW5mby5tYXAoYnJvd3NlciA9PiBicm93c2VyLnByb3ZpZGVyLmlzTG9jYWxCcm93c2VyKHZvaWQgMCwgQm9vdHN0cmFwcGVyLl9nZXRCcm93c2VyTmFtZShicm93c2VyKSkpO1xuICAgICAgICBjb25zdCBpc0xvY2FsQnJvd3NlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChpc0xvY2FsUHJvbWlzZXMpO1xuXG4gICAgICAgIHJldHVybiBpc0xvY2FsQnJvd3NlcnMuZXZlcnkocmVzdWx0ID0+IHJlc3VsdCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfYm9vdHN0cmFwU2VxdWVuY2UgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxCYXNpY1J1bnRpbWVSZXNvdXJjZXM+IHtcbiAgICAgICAgY29uc3QgdGVzdHMgICAgICAgPSBhd2FpdCB0aGlzLl9nZXRUZXN0cygpO1xuICAgICAgICBjb25zdCB0ZXN0ZWRBcHAgICA9IGF3YWl0IHRoaXMuX3N0YXJ0VGVzdGVkQXBwKCk7XG4gICAgICAgIGNvbnN0IGJyb3dzZXJTZXQgID0gYXdhaXQgdGhpcy5fZ2V0QnJvd3NlckNvbm5lY3Rpb25zKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICByZXR1cm4geyB0ZXN0cywgdGVzdGVkQXBwLCBicm93c2VyU2V0IH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfd3JhcEJvb3RzdHJhcHBpbmdQcm9taXNlPFQ+IChwcm9taXNlOiBQcm9taXNlPFQ+KTogUHJvbWlzZTxQcm9taXNlUmVzdWx0PFQ+PiB7XG4gICAgICAgIHJldHVybiBwcm9taXNlXG4gICAgICAgICAgICAudGhlbihyZXN1bHQgPT4gKHsgZXJyb3I6IHZvaWQgMCwgcmVzdWx0IH0pKVxuICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+ICh7IHJlc3VsdDogdm9pZCAwLCBlcnJvciB9KSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZ2V0Qm9vdHN0cmFwcGluZ0Vycm9yIChicm93c2VyU2V0U3RhdHVzOiBQcm9taXNlUmVzdWx0PEJyb3dzZXJTZXQ+LCB0ZXN0c1N0YXR1czogUHJvbWlzZVJlc3VsdDxUZXN0W10+LCB0ZXN0ZWRBcHBTdGF0dXM6IFByb21pc2VSZXN1bHQ8VGVzdGVkQXBwfHVuZGVmaW5lZD4pOiBQcm9taXNlPEVycm9yPiB7XG4gICAgICAgIGlmICghaXNQcm9taXNlRXJyb3IoYnJvd3NlclNldFN0YXR1cykpXG4gICAgICAgICAgICBhd2FpdCBicm93c2VyU2V0U3RhdHVzLnJlc3VsdC5kaXNwb3NlKCk7XG5cbiAgICAgICAgaWYgKCFpc1Byb21pc2VFcnJvcihicm93c2VyU2V0U3RhdHVzKSAmJiAhaXNQcm9taXNlRXJyb3IodGVzdGVkQXBwU3RhdHVzKSAmJiB0ZXN0ZWRBcHBTdGF0dXMucmVzdWx0KVxuICAgICAgICAgICAgYXdhaXQgdGVzdGVkQXBwU3RhdHVzLnJlc3VsdC5raWxsKCk7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKHRlc3RzU3RhdHVzKSlcbiAgICAgICAgICAgIHJldHVybiB0ZXN0c1N0YXR1cy5lcnJvcjtcblxuICAgICAgICBpZiAoaXNQcm9taXNlRXJyb3IodGVzdGVkQXBwU3RhdHVzKSlcbiAgICAgICAgICAgIHJldHVybiB0ZXN0ZWRBcHBTdGF0dXMuZXJyb3I7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKGJyb3dzZXJTZXRTdGF0dXMpKVxuICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXJTZXRTdGF0dXMuZXJyb3I7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignVW5leHBlY3RlZCBjYWxsJyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0Qm9vdHN0cmFwcGluZ1Byb21pc2VzPFQ+IChhcmc6IFByb21pc2VDb2xsZWN0aW9uPFQ+KTogUHJvbWlzZUNvbGxlY3Rpb248UmVzdWx0Q29sbGVjdGlvbjxUPj4ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSB7fSBhcyB1bmtub3duIGFzIFByb21pc2VDb2xsZWN0aW9uPFJlc3VsdENvbGxlY3Rpb248VD4+O1xuXG4gICAgICAgIGZvciAoY29uc3QgayBpbiBhcmcpXG4gICAgICAgICAgICByZXN1bHRba10gPSB0aGlzLl93cmFwQm9vdHN0cmFwcGluZ1Byb21pc2UoYXJnW2tdKTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2Jvb3RzdHJhcFBhcmFsbGVsIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8QmFzaWNSdW50aW1lUmVzb3VyY2VzPiB7XG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdQcm9taXNlcyA9IHtcbiAgICAgICAgICAgIGJyb3dzZXJTZXQ6IHRoaXMuX2dldEJyb3dzZXJDb25uZWN0aW9ucyhicm93c2VySW5mbyksXG4gICAgICAgICAgICB0ZXN0czogICAgICB0aGlzLl9nZXRUZXN0cygpLFxuICAgICAgICAgICAgYXBwOiAgICAgICAgdGhpcy5fc3RhcnRUZXN0ZWRBcHAoKVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdSZXN1bHRQcm9taXNlcyA9IHRoaXMuX2dldEJvb3RzdHJhcHBpbmdQcm9taXNlcyhib290c3RyYXBwaW5nUHJvbWlzZXMpO1xuXG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgYm9vdHN0cmFwcGluZ1Jlc3VsdFByb21pc2VzLmJyb3dzZXJTZXQsXG4gICAgICAgICAgICBib290c3RyYXBwaW5nUmVzdWx0UHJvbWlzZXMudGVzdHMsXG4gICAgICAgICAgICBib290c3RyYXBwaW5nUmVzdWx0UHJvbWlzZXMuYXBwXG4gICAgICAgIF0pO1xuXG4gICAgICAgIGNvbnN0IFticm93c2VyU2V0UmVzdWx0cywgdGVzdFJlc3VsdHMsIGFwcFJlc3VsdHNdID0gYm9vdHN0cmFwcGluZ1Jlc3VsdHM7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKGJyb3dzZXJTZXRSZXN1bHRzKSB8fCBpc1Byb21pc2VFcnJvcih0ZXN0UmVzdWx0cykgfHwgaXNQcm9taXNlRXJyb3IoYXBwUmVzdWx0cykpXG4gICAgICAgICAgICB0aHJvdyBhd2FpdCB0aGlzLl9nZXRCb290c3RyYXBwaW5nRXJyb3IoLi4uYm9vdHN0cmFwcGluZ1Jlc3VsdHMpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBicm93c2VyU2V0OiBicm93c2VyU2V0UmVzdWx0cy5yZXN1bHQsXG4gICAgICAgICAgICB0ZXN0czogICAgICB0ZXN0UmVzdWx0cy5yZXN1bHQsXG4gICAgICAgICAgICB0ZXN0ZWRBcHA6ICBhcHBSZXN1bHRzLnJlc3VsdFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8vIEFQSVxuICAgIHB1YmxpYyBhc3luYyBjcmVhdGVSdW5uYWJsZUNvbmZpZ3VyYXRpb24gKCk6IFByb21pc2U8UnVudGltZVJlc291cmNlcz4ge1xuICAgICAgICBjb25zdCByZXBvcnRlclBsdWdpbnMgICAgID0gYXdhaXQgdGhpcy5fZ2V0UmVwb3J0ZXJQbHVnaW5zKCk7XG4gICAgICAgIGNvbnN0IGNvbW1vbkNsaWVudFNjcmlwdHMgPSBhd2FpdCBsb2FkQ2xpZW50U2NyaXB0cyh0aGlzLmNsaWVudFNjcmlwdHMpO1xuXG4gICAgICAgIC8vIE5PVEU6IElmIGEgdXNlciBmb3Jnb3QgdG8gc3BlY2lmeSBhIGJyb3dzZXIsIGJ1dCBoYXMgc3BlY2lmaWVkIGEgcGF0aCB0byB0ZXN0cywgdGhlIHNwZWNpZmllZCBwYXRoIHdpbGwgYmVcbiAgICAgICAgLy8gY29uc2lkZXJlZCBhcyB0aGUgYnJvd3NlciBhcmd1bWVudCwgYW5kIHRoZSB0ZXN0cyBwYXRoIGFyZ3VtZW50IHdpbGwgaGF2ZSB0aGUgcHJlZGVmaW5lZCBkZWZhdWx0IHZhbHVlLlxuICAgICAgICAvLyBJdCdzIHZlcnkgYW1iaWd1b3VzIGZvciB0aGUgdXNlciwgd2hvIG1pZ2h0IGJlIGNvbmZ1c2VkIGJ5IGNvbXBpbGF0aW9uIGVycm9ycyBmcm9tIGFuIHVuZXhwZWN0ZWQgdGVzdC5cbiAgICAgICAgLy8gU28sIHdlIG5lZWQgdG8gcmV0cmlldmUgdGhlIGJyb3dzZXIgYWxpYXNlcyBhbmQgcGF0aHMgYmVmb3JlIHRlc3RzIGNvbXBpbGF0aW9uLlxuICAgICAgICBjb25zdCBicm93c2VySW5mbyA9IGF3YWl0IHRoaXMuX2dldEJyb3dzZXJJbmZvKCk7XG5cbiAgICAgICAgaWYgKE9TLm1hYylcbiAgICAgICAgICAgIGF3YWl0IEJvb3RzdHJhcHBlci5fY2hlY2tSZXF1aXJlZFBlcm1pc3Npb25zKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICBpZiAoT1MubGludXggJiYgIWRldGVjdERpc3BsYXkoKSlcbiAgICAgICAgICAgIGF3YWl0IEJvb3RzdHJhcHBlci5fY2hlY2tUaGF0VGVzdHNDYW5SdW5XaXRob3V0RGlzcGxheShicm93c2VySW5mbyk7XG5cbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuX2NhblVzZVBhcmFsbGVsQm9vdHN0cmFwcGluZyhicm93c2VySW5mbykpXG4gICAgICAgICAgICByZXR1cm4geyByZXBvcnRlclBsdWdpbnMsIC4uLmF3YWl0IHRoaXMuX2Jvb3RzdHJhcFBhcmFsbGVsKGJyb3dzZXJJbmZvKSwgY29tbW9uQ2xpZW50U2NyaXB0cyB9O1xuXG4gICAgICAgIHJldHVybiB7IHJlcG9ydGVyUGx1Z2lucywgLi4uYXdhaXQgdGhpcy5fYm9vdHN0cmFwU2VxdWVuY2UoYnJvd3NlckluZm8pLCBjb21tb25DbGllbnRTY3JpcHRzIH07XG4gICAgfVxufVxuIl19
|