appium-xcuitest-driver 4.16.1 → 4.16.3
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 +14 -0
- package/README.md +1 -0
- package/build/lib/commands/xctest.js +22 -3
- package/build/lib/commands/xctest.js.map +1 -1
- package/lib/commands/xctest.js +31 -3
- package/npm-shrinkwrap.json +10 -10
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [4.16.3](https://github.com/appium/appium-xcuitest-driver/compare/v4.16.2...v4.16.3) (2022-12-19)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* set permissions for simulator ([#1473](https://github.com/appium/appium-xcuitest-driver/issues/1473)) ([a885628](https://github.com/appium/appium-xcuitest-driver/commit/a8856286ea7304a9c2ec3ed8c46a5c66526bc102))
|
|
7
|
+
|
|
8
|
+
## [4.16.2](https://github.com/appium/appium-xcuitest-driver/compare/v4.16.1...v4.16.2) (2022-12-18)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* XCTest command ([#1471](https://github.com/appium/appium-xcuitest-driver/issues/1471)) ([d176f45](https://github.com/appium/appium-xcuitest-driver/commit/d176f455c23b4c6b59ff72be36d3050c60bcf470))
|
|
14
|
+
|
|
1
15
|
## [4.16.1](https://github.com/appium/appium-xcuitest-driver/compare/v4.16.0...v4.16.1) (2022-12-17)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -1048,6 +1048,7 @@ The API calls returns a map with the following entries:
|
|
|
1048
1048
|
* testName: Name of the test (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')
|
|
1049
1049
|
* passed: Did the tests pass?
|
|
1050
1050
|
* crashed: Did the tests crash?
|
|
1051
|
+
* status: Test result status (e.g.: 'passed', 'failed', 'crashed')
|
|
1051
1052
|
* duration: How long did the tests take (in seconds)
|
|
1052
1053
|
* failureMessage: Failure message (if applicable)
|
|
1053
1054
|
* location The geolocation of the test (if applicable)
|
|
@@ -52,6 +52,7 @@ function parseXCTestStdout(stdout) {
|
|
|
52
52
|
}
|
|
53
53
|
return parseInt(value, 10);
|
|
54
54
|
}
|
|
55
|
+
return value;
|
|
55
56
|
}
|
|
56
57
|
if (!stdout) {
|
|
57
58
|
return [];
|
|
@@ -68,12 +69,26 @@ function parseXCTestStdout(stdout) {
|
|
|
68
69
|
for (const prop of properties) {
|
|
69
70
|
if (entryIndex === 0) {
|
|
70
71
|
output.testName = prop.trim();
|
|
72
|
+
} else if (prop.trim().startsWith('Location')) {
|
|
73
|
+
output.location = prop.substring(prop.indexOf('Location') + 8).trim();
|
|
71
74
|
} else {
|
|
72
75
|
let [key, value] = prop.split(':');
|
|
73
76
|
output[parseKey(key.trim())] = parseValue(value ? value.trim() : '');
|
|
74
77
|
}
|
|
75
78
|
entryIndex++;
|
|
76
79
|
}
|
|
80
|
+
if (!output.passed) {
|
|
81
|
+
output.passed = output.status === 'passed';
|
|
82
|
+
output.crashed = output.status === 'crashed';
|
|
83
|
+
} else if (!output.status) {
|
|
84
|
+
if (output.passed) {
|
|
85
|
+
output.status = 'passed';
|
|
86
|
+
} else if (output.crashed) {
|
|
87
|
+
output.status = 'crashed';
|
|
88
|
+
} else {
|
|
89
|
+
output.status = 'failed';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
77
92
|
results.push(output);
|
|
78
93
|
}
|
|
79
94
|
return results;
|
|
@@ -95,8 +110,9 @@ commands.mobileRunXCTest = async function runXCTest({
|
|
|
95
110
|
return await new _bluebird.default((resolve, reject) => {
|
|
96
111
|
let mostRecentLogObject = null;
|
|
97
112
|
let xctestTimeout;
|
|
113
|
+
let lastErrorMessage = null;
|
|
98
114
|
if (timeout > 0) {
|
|
99
|
-
xctestTimeout = setTimeout(() => reject(`Timed out after '${timeout}ms' waiting for XCTest to complete`), timeout);
|
|
115
|
+
xctestTimeout = setTimeout(() => reject(new _driver.errors.TimeoutError(`Timed out after '${timeout}ms' waiting for XCTest to complete`)), timeout);
|
|
100
116
|
}
|
|
101
117
|
subproc.on('output', (stdout, stderr) => {
|
|
102
118
|
if (stdout) {
|
|
@@ -107,13 +123,16 @@ commands.mobileRunXCTest = async function runXCTest({
|
|
|
107
123
|
this.log.debug(err.stack);
|
|
108
124
|
}
|
|
109
125
|
}
|
|
126
|
+
if (stderr) {
|
|
127
|
+
lastErrorMessage = stderr;
|
|
128
|
+
}
|
|
110
129
|
stdout && xctestLog.info(stdout);
|
|
111
130
|
stderr && xctestLog.error(stderr);
|
|
112
131
|
});
|
|
113
132
|
subproc.on('exit', (code, signal) => {
|
|
114
133
|
clearTimeout(xctestTimeout);
|
|
115
134
|
if (code !== 0) {
|
|
116
|
-
const err = new Error(mostRecentLogObject);
|
|
135
|
+
const err = new Error(lastErrorMessage || mostRecentLogObject);
|
|
117
136
|
err.code = code;
|
|
118
137
|
if (signal != null) {
|
|
119
138
|
err.signal = signal;
|
|
@@ -160,4 +179,4 @@ commands.mobileListXCTestsInTestBundle = async function listXCTestsInTestBundle(
|
|
|
160
179
|
Object.assign(commands);
|
|
161
180
|
var _default = commands;
|
|
162
181
|
exports.default = _default;
|
|
163
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjb21tYW5kcyIsIlhDVEVTVF9USU1FT1VUIiwieGN0ZXN0TG9nIiwibG9nZ2VyIiwiZ2V0TG9nZ2VyIiwiYXNzZXJ0SURCIiwib3B0cyIsImRldmljZSIsImlkYiIsImxhdW5jaFdpdGhJREIiLCJFcnJvciIsInBhcnNlWENUZXN0U3Rkb3V0Iiwic3Rkb3V0IiwicGFyc2VLZXkiLCJuYW1lIiwid29yZHMiLCJzcGxpdCIsIm91dCIsIndvcmQiLCJzdWJzdHIiLCJ0b1VwcGVyQ2FzZSIsInRvTG93ZXJDYXNlIiwicGFyc2VWYWx1ZSIsInZhbHVlIiwiaXNOYU4iLCJfIiwiaXNTdHJpbmciLCJpbmRleE9mIiwicGFyc2VGbG9hdCIsInBhcnNlSW50IiwibGluZXMiLCJ0cmltIiwibGVuZ3RoIiwiaW5jbHVkZXMiLCJyZXN1bHRzIiwibGluZSIsInByb3BlcnRpZXMiLCJvdXRwdXQiLCJlbnRyeUluZGV4IiwicHJvcCIsInRlc3ROYW1lIiwia2V5IiwicHVzaCIsIm1vYmlsZVJ1blhDVGVzdCIsInJ1blhDVGVzdCIsInRlc3RSdW5uZXJCdW5kbGVJZCIsImFwcFVuZGVyVGVzdEJ1bmRsZUlkIiwieGN0ZXN0QnVuZGxlSWQiLCJ0ZXN0VHlwZSIsImVudiIsImFyZ3MiLCJ0aW1lb3V0Iiwic3VicHJvYyIsInJ1blhDVUlUZXN0IiwiQiIsInJlc29sdmUiLCJyZWplY3QiLCJtb3N0UmVjZW50TG9nT2JqZWN0IiwieGN0ZXN0VGltZW91dCIsInNldFRpbWVvdXQiLCJvbiIsInN0ZGVyciIsImVyciIsImxvZyIsIndhcm4iLCJkZWJ1ZyIsInN0YWNrIiwiaW5mbyIsImVycm9yIiwiY29kZSIsInNpZ25hbCIsImNsZWFyVGltZW91dCIsInJlc3VsdCIsInBhc3NlZCIsIm1vYmlsZUluc3RhbGxYQ1Rlc3RCdW5kbGUiLCJpbnN0YWxsWENUZXN0QnVuZGxlIiwieGN0ZXN0QXBwIiwiZXJyb3JzIiwiSW52YWxpZEFyZ3VtZW50RXJyb3IiLCJyZXMiLCJoZWxwZXJzIiwiY29uZmlndXJlQXBwIiwibW9iaWxlTGlzdFhDVGVzdEJ1bmRsZXMiLCJsaXN0WENUZXN0c0luVGVzdEJ1bmRsZSIsImxpc3RYQ1Rlc3RCdW5kbGVzIiwibW9iaWxlTGlzdFhDVGVzdHNJblRlc3RCdW5kbGUiLCJidW5kbGUiLCJPYmplY3QiLCJhc3NpZ24iXSwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvY29tbWFuZHMveGN0ZXN0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBCIGZyb20gJ2JsdWViaXJkJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJ2FwcGl1bS9zdXBwb3J0JztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBlcnJvcnMgfSBmcm9tICdhcHBpdW0vZHJpdmVyJztcblxuXG5jb25zdCBjb21tYW5kcyA9IHt9O1xuXG5jb25zdCBYQ1RFU1RfVElNRU9VVCA9IDYwICogNjAgKiAxMDAwOyAvLyA2MCBtaW51dGUgdGltZW91dFxuXG5jb25zdCB4Y3Rlc3RMb2cgPSBsb2dnZXIuZ2V0TG9nZ2VyKCdYQ1Rlc3QnKTtcblxuLyoqXG4gKiBBc3NlcnRzIHRoYXQgSURCIGlzIHByZXNlbnQgYW5kIHRoYXQgbGF1bmNoV2l0aElEQiB3YXMgdXNlZFxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRzIE9wdHMgb2JqZWN0IGZyb20gdGhlIGRyaXZlciBpbnN0YW5jZVxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0SURCIChvcHRzKSB7XG4gIGlmICghb3B0cy5kZXZpY2U/LmlkYiB8fCAhb3B0cy5sYXVuY2hXaXRoSURCKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUbyB1c2UgWENUZXN0IHJ1bm5lciwgSURCIChodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2svaWRiKSBtdXN0IGJlIGluc3RhbGxlZCBgICtcbiAgICAgIGBhbmQgc2Vzc2lvbnMgbXVzdCBiZSBydW4gd2l0aCB0aGUgXCJsYXVuY2hXaXRoSURCXCIgY2FwYWJpbGl0eWApO1xuICB9XG4gIHJldHVybiBvcHRzLmRldmljZS5pZGI7XG59XG5cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBYQ1Rlc3RSZXN1bHRcbiAqXG4gKiBAcHJvcGVydHkge3N0cmluZ30gdGVzdE5hbWUgTmFtZSBvZiB0aGUgdGVzdCAoZS5nLjogJ1hDVGVzdGVyQXBwVUlUZXN0cyAtIFhDVGVzdGVyQXBwVUlUZXN0cy5YQ1Rlc3RlckFwcFVJVGVzdHMvdGVzdEV4YW1wbGUnKVxuICogQHByb3BlcnR5IHtib29sZWFufSBwYXNzZWQgRGlkIHRoZSB0ZXN0cyBwYXNzP1xuICogQHByb3BlcnR5IHtib29sZWFufSBjcmFzaGVkIERpZCB0aGUgdGVzdHMgY3Jhc2g/XG4gKiBAcHJvcGVydHkge251bWJlcn0gZHVyYXRpb24gSG93IGxvbmcgZGlkIHRoZSB0ZXN0cyB0YWtlIChpbiBzZWNvbmRzKVxuICogQHByb3BlcnR5IHtzdHJpbmd9IGZhaWx1cmVNZXNzYWdlIEZhaWx1cmUgbWVzc2FnZSAoaWYgYXBwbGljYWJsZSlcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBsb2NhdGlvbiBUaGUgZ2VvbG9jYXRpb24gb2YgdGhlIHRlc3RzIChpZiBhcHBsaWNhYmxlKVxuICovXG5cbi8qKlxuICogUGFyc2UgdGhlIHN0ZG91dCBvZiBYQyB0ZXN0IGxvZ1xuICogQHBhcmFtIHtzdHJpbmd9IHN0ZG91dCBBIGxpbmUgb2Ygc3RhbmRhcmQgb3V0IGZyb20gYGlkYiB4Y3Rlc3QgcnVuIC4uLmBcbiAqIEByZXR1cm5zIHtBcnJheTxYQ1Rlc3RSZXN1bHQ+fSByZXN1bHRzIFRoZSBmaW5hbCBvdXRwdXQgb2YgdGhlIFhDVGVzdCBydW5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlWENUZXN0U3Rkb3V0IChzdGRvdXQpIHtcbiAgLy8gUGFyc2VzIGEgJ2tleScgaW50byBKU09OIGZvcm1hdFxuICBmdW5jdGlvbiBwYXJzZUtleSAobmFtZSkge1xuICAgIGNvbnN0IHdvcmRzID0gbmFtZS5zcGxpdCgnICcpO1xuICAgIGxldCBvdXQgPSAnJztcbiAgICBmb3IgKGNvbnN0IHdvcmQgb2Ygd29yZHMpIHtcbiAgICAgIG91dCArPSB3b3JkLnN1YnN0cigwLCAxKS50b1VwcGVyQ2FzZSgpICsgd29yZC5zdWJzdHIoMSk7XG4gICAgfVxuICAgIHJldHVybiBvdXQuc3Vic3RyKDAsIDEpLnRvTG93ZXJDYXNlKCkgKyBvdXQuc3Vic3RyKDEpO1xuICB9XG5cbiAgLy8gUGFyc2VzIGEgJ3ZhbHVlJyBpbnRvIEpTT04gZm9ybWF0XG4gIGZ1bmN0aW9uIHBhcnNlVmFsdWUgKHZhbHVlKSB7XG4gICAgdmFsdWUgPSB2YWx1ZSB8fCAnJztcbiAgICBzd2l0Y2ggKHZhbHVlLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIGNhc2UgJ3RydWUnOiByZXR1cm4gdHJ1ZTtcbiAgICAgIGNhc2UgJ2ZhbHNlJzogcmV0dXJuIGZhbHNlO1xuICAgICAgY2FzZSAnJzogcmV0dXJuIG51bGw7XG4gICAgICBkZWZhdWx0OiBicmVhaztcbiAgICB9XG4gICAgaWYgKCFpc05hTih2YWx1ZSkpIHtcbiAgICAgIGlmICghXy5pc1N0cmluZyh2YWx1ZSkpIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9IGVsc2UgaWYgKHZhbHVlLmluZGV4T2YoJy4nKSA+IDApIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQodmFsdWUpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHBhcnNlSW50KHZhbHVlLCAxMCk7XG4gICAgfVxuICB9XG4gIGlmICghc3Rkb3V0KSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLy8gUGFyc2UgZWFjaCBsaW5lIGludG8gYW4gYXJyYXlcbiAgY29uc3QgbGluZXMgPSBzdGRvdXQudHJpbSgpLnNwbGl0KCdcXG4nKTtcblxuICAvLyBPbmUgc2luZ2xlIHN0cmluZywganVzdCByZXR1cm4gdGhlIHN0cmluZ1xuICBpZiAobGluZXMubGVuZ3RoID09PSAxICYmICFsaW5lc1swXS5pbmNsdWRlcygnfCcpKSB7XG4gICAgcmV0dXJuIFtsaW5lc1swXV07XG4gIH1cblxuICBjb25zdCByZXN1bHRzID0gW107XG4gIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgIC8vIFRoZSBwcm9wZXJ0aWVzIGFyZSBzcGxpdCB1cCBieSBwaXBlcyBhbmQgZWFjaCBwcm9wZXJ0eVxuICAgIC8vIGhhcyB0aGUgZm9ybWF0IFwiU29tZSBLZXkgOiBTb21lIFZhbHVlXCJcbiAgICBjb25zdCBwcm9wZXJ0aWVzID0gbGluZS5zcGxpdCgnfCcpO1xuXG4gICAgLy8gUGFyc2UgZWFjaCBwcm9wZXJ0eVxuICAgIGNvbnN0IG91dHB1dCA9IHt9O1xuICAgIGxldCBlbnRyeUluZGV4ID0gMDtcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgcHJvcGVydGllcykge1xuICAgICAgaWYgKGVudHJ5SW5kZXggPT09IDApIHtcbiAgICAgICAgLy8gVGhlIGZpcnN0IHByb3BlcnR5IG9ubHkgY29udGFpbnMgb25lIHN0cmluZyB0aGF0IGNvbnRhaW5zXG4gICAgICAgIC8vIHRoZSB0ZXN0IG5hbWUgKGUuZy46ICdYQ1Rlc3RlckFwcFVJVGVzdHMgLSBYQ1Rlc3RlckFwcFVJVGVzdHMuWENUZXN0ZXJBcHBVSVRlc3RzL3Rlc3RFeGFtcGxlJylcbiAgICAgICAgb3V0cHV0LnRlc3ROYW1lID0gcHJvcC50cmltKCk7XG4gICAgICB9IGVsc2Uge1xuXG4gICAgICAgIGxldCBba2V5LCB2YWx1ZV0gPSBwcm9wLnNwbGl0KCc6Jyk7XG4gICAgICAgIG91dHB1dFtwYXJzZUtleShrZXkudHJpbSgpKV0gPSBwYXJzZVZhbHVlKHZhbHVlID8gdmFsdWUudHJpbSgpIDogJycpO1xuICAgICAgfVxuICAgICAgZW50cnlJbmRleCsrO1xuICAgIH1cbiAgICAvLyBBZGQgdGhpcyBsaW5lIHRvIHRoZSByZXN1bHRzXG4gICAgcmVzdWx0cy5wdXNoKG91dHB1dCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gUnVuWENVSVRlc3RSZXNwb25zZVxuICpcbiAqIEBwcm9wZXJ0eSB7QXJyYXk8WENUZXN0UmVzdWx0Pn0gcmVzdWx0cyBUaGUgcmVzdWx0cyBvZiBhbGwgdGhlIHRlc3RzIHdpdGggaW5mb3JtYXRpb25cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBjb2RlIFRoZSBleGl0IGNvZGUgb2YgdGhlIHByb2Nlc3NcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzaWduYWwgVGhlIHNpZ25hbCB0aGF0IHRlcm1pbmF0ZWQgdGhlIHByb2Nlc3MgKG9yIG51bGwpIChlLmcuOiBTSUdURVJNKVxuICpcbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFJ1blhDVUlUZXN0T3B0aW9uc1xuICpcbiAqIEBwcm9wZXJ0eSB7IXN0cmluZ30gdGVzdFJ1bm5lckJ1bmRsZUlkIFRlc3QgYXBwIGJ1bmRsZSAoZS5nLjogJ2lvLmFwcGl1bS5YQ1Rlc3RlckFwcFVJVGVzdHMueGN0cnVubmVyJylcbiAqIEBwcm9wZXJ0eSB7IXN0cmluZ30gYXBwVW5kZXJUZXN0QnVuZGxlSWQgQXBwLXVuZGVyLXRlc3QgYnVuZGxlXG4gKiBAcHJvcGVydHkgeyFzdHJpbmd9IHhjVGVzdEJ1bmRsZUlEIHhjdGVzdCBidW5kbGUgaWRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0ZXN0VHlwZSBbdWldIFhDIHRlc3QgdHlwZS4gJ2FwcCcsICd1aScsIG9yICdsb2dpYydcbiAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBlbnYgRW52aXJvbm1lbnQgdmFyaWFibGVzIHBhc3NlZCB0byB0ZXN0XG4gKiBAcHJvcGVydHkge0FycmF5PFN0cmluZz59IGFyZ3MgTGF1bmNoIGFyZ3VtZW50cyB0byBzdGFydCB0aGUgdGVzdCB3aXRoIChzZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYXBwbGUuY29tL2RvY3VtZW50YXRpb24veGN0ZXN0L3hjdWlhcHBsaWNhdGlvbi8xNTAwNDc3LWxhdW5jaGFyZ3VtZW50cyBmb3IgcmVmZXJlbmNlKVxuICogQHByb3BlcnR5IHtudW1iZXJ9IHRpbWVvdXQgWzM2MDAwMF0gVGltZW91dCBpZiBzZXNzaW9uIGRvZXNuJ3QgY29tcGxldGUgYWZ0ZXIgZ2l2ZW4gdGltZSAoaW4gbWlsbGlzZWNvbmRzKVxuICovXG5cblxuLyoqXG4gKiBAdHlwZWRlZiB7RXJyb3J9IFhDVUlUZXN0RXJyb3JcbiAqXG4gKiBAcHJvcGVydHkge251bWJlcn0gY29kZSBTdWJwcm9jZXNzIGV4aXQgY29kZVxuICogQHByb3BlcnR5IHtzdHJpbmd9IHNpZ25hbCBUaGUgc2lnbmFsIChTSUcqKSB0aGF0IGNhdXNlZCB0aGUgcHJvY2VzcyB0byBmYWlsXG4gKiBAcHJvcGVydHkgeyFBcnJheTxYQ1Rlc3RSZXN1bHQ+fSByZXN1bHRzIFRoZSBvdXRwdXQgb2YgdGhlIGZhaWxlZCB0ZXN0IChpZiB0aGVyZSBpcyBvdXRwdXQpXG4gKi9cblxuLyoqXG4gKiBSdW4gYW4gWENUZXN0LiBMYXVuY2hlcyBhIHN1YnByb2Nlc3MgdGhhdCBydW5zIHRoZSBYQyBUZXN0IGFuZCBibG9ja3NcbiAqIHVudGlsIGl0IGlzIGNvbXBsZXRlLiBQYXJzZXMgdGhlIHN0ZG91dCBvZiB0aGUgcHJvY2VzcyBhbmQgcmV0dXJuc1xuICogcmVzdWx0IGFzIGFuIGFycmF5XG4gKlxuICogU2VlIGh0dHBzOi8vZmJpZGIuaW8vZG9jcy90ZXN0X2V4ZWN1dGlvbiBmb3IgcmVmZXJlbmNlXG4gKlxuICogQHBhcmFtIHtSdW5YQ1VJVGVzdE9wdGlvbnN9IHJ1blhDVUlUZXN0T3B0aW9uc1xuICogQHRocm93cyB7WENVSVRlc3RFcnJvcn0gRXJyb3IgdGhyb3duIGlmIHN1YnByb2Nlc3MgcmV0dXJucyBub24temVybyBleGl0IGNvZGVcbiAqIEByZXR1cm5zIHtSdW5YQ1VJVGVzdFJlc3BvbnNlfVxuICovXG5jb21tYW5kcy5tb2JpbGVSdW5YQ1Rlc3QgPSBhc3luYyBmdW5jdGlvbiBydW5YQ1Rlc3QgKHtcbiAgdGVzdFJ1bm5lckJ1bmRsZUlkLFxuICBhcHBVbmRlclRlc3RCdW5kbGVJZCxcbiAgeGN0ZXN0QnVuZGxlSWQsXG4gIHRlc3RUeXBlID0gJ3VpJyxcbiAgZW52LFxuICBhcmdzLFxuICB0aW1lb3V0ID0gWENURVNUX1RJTUVPVVQsXG59KSB7XG4gIGNvbnN0IHN1YnByb2MgPSBhd2FpdCBhc3NlcnRJREIodGhpcy5vcHRzKS5ydW5YQ1VJVGVzdChcbiAgICAgICAgdGVzdFJ1bm5lckJ1bmRsZUlkLCBhcHBVbmRlclRlc3RCdW5kbGVJZCwgeGN0ZXN0QnVuZGxlSWQsIHtlbnYsIGFyZ3MsIHRlc3RUeXBlfSxcbiAgKTtcbiAgcmV0dXJuIGF3YWl0IG5ldyBCKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBsZXQgbW9zdFJlY2VudExvZ09iamVjdCA9IG51bGw7XG4gICAgbGV0IHhjdGVzdFRpbWVvdXQ7XG4gICAgaWYgKHRpbWVvdXQgPiAwKSB7XG4gICAgICB4Y3Rlc3RUaW1lb3V0ID0gc2V0VGltZW91dChcbiAgICAgICAgKCkgPT4gcmVqZWN0KGBUaW1lZCBvdXQgYWZ0ZXIgJyR7dGltZW91dH1tcycgd2FpdGluZyBmb3IgWENUZXN0IHRvIGNvbXBsZXRlYCksXG4gICAgICAgIHRpbWVvdXRcbiAgICAgICk7XG4gICAgfVxuXG4gICAgc3VicHJvYy5vbignb3V0cHV0JywgKHN0ZG91dCwgc3RkZXJyKSA9PiB7XG4gICAgICBpZiAoc3Rkb3V0KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbW9zdFJlY2VudExvZ09iamVjdCA9IHBhcnNlWENUZXN0U3Rkb3V0KHN0ZG91dCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIC8vIEZhaWxzIGlmIGxvZyBwYXJzaW5nIGZhaWxzLlxuICAgICAgICAgIC8vIFRoaXMgaXMgaW4gY2FzZSBJREIgY2hhbmdlcyB0aGUgd2F5IHRoYXQgbG9ncyBhcmUgZm9ybWF0dGVkIGFuZFxuICAgICAgICAgIC8vIGl0IGJyZWFrcyAncGFyc2VYQ1Rlc3RTdGRvdXQnLiBJZiB0aGF0IGhhcHBlbnMgd2Ugc3RpbGwgd2FudCB0aGUgcHJvY2Vzc1xuICAgICAgICAgIC8vIHRvIGZpbmlzaFxuICAgICAgICAgIHRoaXMubG9nLndhcm4oYEZhaWxlZCB0byBwYXJzZSBsb2dzIGZyb20gdGVzdCBvdXRwdXQ6ICcke3N0ZG91dH0nYCk7XG4gICAgICAgICAgdGhpcy5sb2cuZGVidWcoZXJyLnN0YWNrKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgc3Rkb3V0ICYmIHhjdGVzdExvZy5pbmZvKHN0ZG91dCk7XG4gICAgICBzdGRlcnIgJiYgeGN0ZXN0TG9nLmVycm9yKHN0ZGVycik7XG4gICAgfSk7XG5cbiAgICBzdWJwcm9jLm9uKCdleGl0JywgKGNvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgY2xlYXJUaW1lb3V0KHhjdGVzdFRpbWVvdXQpO1xuICAgICAgaWYgKGNvZGUgIT09IDApIHtcbiAgICAgICAgY29uc3QgZXJyID0gbmV3IEVycm9yKG1vc3RSZWNlbnRMb2dPYmplY3QpO1xuICAgICAgICBlcnIuY29kZSA9IGNvZGU7XG4gICAgICAgIGlmIChzaWduYWwgIT0gbnVsbCkge1xuICAgICAgICAgIGVyci5zaWduYWwgPSBzaWduYWw7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1vc3RSZWNlbnRMb2dPYmplY3QpIHtcbiAgICAgICAgICBlcnIucmVzdWx0ID0gbW9zdFJlY2VudExvZ09iamVjdDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVqZWN0KGVycik7XG4gICAgICB9XG4gICAgICByZXNvbHZlKHtcbiAgICAgICAgY29kZSwgc2lnbmFsLCByZXN1bHRzOiBtb3N0UmVjZW50TG9nT2JqZWN0LCBwYXNzZWQ6IHRydWUsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IEluc3RhbGxYQ1Rlc3RCdW5kbGVPcHRzXG4gKlxuICogQHByb3BlcnR5IHt4Y3Rlc3RBcHB9IHhjdGVzdEJ1bmRsZSBQYXRoIG9mIHRoZSBYQ1Rlc3QgYXBwIChVUkwgb3IgLmFwcClcbiAqL1xuXG4vKipcbiAqIEluc3RhbGwgYW4gWENUZXN0QnVuZGxlXG4gKlxuICogQHBhcmFtIHtJbnN0YWxsWENUZXN0QnVuZGxlT3B0cyF9IG9wdHMgSW5zdGFsbCB4Y3Rlc3QgYnVuZGxlIG9wdHNcbiAqL1xuY29tbWFuZHMubW9iaWxlSW5zdGFsbFhDVGVzdEJ1bmRsZSA9IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxYQ1Rlc3RCdW5kbGUgKG9wdHMpIHtcbiAgY29uc3QgeyB4Y3Rlc3RBcHAgfSA9IG9wdHM7XG4gIGlmICghXy5pc1N0cmluZyh4Y3Rlc3RBcHApKSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5JbnZhbGlkQXJndW1lbnRFcnJvcihgJ3hjdGVzdEFwcCcgaXMgYSByZXF1aXJlZCBwYXJhbWV0ZXIgZm9yICdpbnN0YWxsWENUZXN0QnVuZGxlJyBhbmQgYCArXG4gICAgICBgbXVzdCBiZSBhIHN0cmluZy4gRm91bmQgJyR7eGN0ZXN0QXBwfSdgKTtcbiAgfVxuICB4Y3Rlc3RMb2cuaW5mbyhgSW5zdGFsbGluZyBidW5kbGUgJyR7eGN0ZXN0QXBwfSdgKTtcbiAgY29uc3QgaWRiID0gYXNzZXJ0SURCKHRoaXMub3B0cyk7XG4gIGNvbnN0IHJlcyA9IGF3YWl0IHRoaXMuaGVscGVycy5jb25maWd1cmVBcHAoeGN0ZXN0QXBwLCAnLnhjdGVzdCcpO1xuICBhd2FpdCBpZGIuaW5zdGFsbFhDVGVzdEJ1bmRsZShyZXMpO1xufTtcblxuLyoqXG4gKiBMaXN0IFhDVGVzdCBidW5kbGVzIHRoYXQgYXJlIGluc3RhbGxlZCBvbiBkZXZpY2VcbiAqXG4gKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gTGlzdCBvZiBYQ1Rlc3QgYnVuZGxlcyAoZS5nLjogXCJYQ1Rlc3RlckFwcFVJVGVzdHMuWENUZXN0ZXJBcHBVSVRlc3RzL3Rlc3RMYXVuY2hQZXJmb3JtYW5jZVwiKVxuICovXG5jb21tYW5kcy5tb2JpbGVMaXN0WENUZXN0QnVuZGxlcyA9IGFzeW5jIGZ1bmN0aW9uIGxpc3RYQ1Rlc3RzSW5UZXN0QnVuZGxlICgpIHtcbiAgcmV0dXJuIGF3YWl0IGFzc2VydElEQih0aGlzLm9wdHMpLmxpc3RYQ1Rlc3RCdW5kbGVzKCk7XG59O1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IExpc3RYQ1Rlc3RzT3B0c1xuICpcbiAqIEBwcm9wZXJ0eSB7IXN0cmluZ30gYnVuZGxlIEJ1bmRsZSBJRCBvZiB0aGUgWENUZXN0XG4gKi9cblxuLyoqXG4gKiBMaXN0IFhDVGVzdHMgaW4gYSB0ZXN0IGJ1bmRsZVxuICpcbiAqIEBwYXJhbSB7IUxpc3RYQ1Rlc3RzT3B0c30gb3B0cyBYQ1Rlc3QgbGlzdCBvcHRpb25zXG4gKlxuICogQHJldHVybnMge0FycmF5PHN0cmluZz59IFRoZSBsaXN0IG9mIHhjdGVzdHMgaW4gdGhlIHRlc3QgYnVuZGxlXG4gKiAgICAoZS5nLjogWyAnWENUZXN0ZXJBcHBVSVRlc3RzLlhDVGVzdGVyQXBwVUlUZXN0cy90ZXN0RXhhbXBsZScsXG4gICAgICAgICAgICAgICAgJ1hDVGVzdGVyQXBwVUlUZXN0cy5YQ1Rlc3RlckFwcFVJVGVzdHMvdGVzdExhdW5jaFBlcmZvcm1hbmNlJyBdIClcbiAqL1xuY29tbWFuZHMubW9iaWxlTGlzdFhDVGVzdHNJblRlc3RCdW5kbGUgPSBhc3luYyBmdW5jdGlvbiBsaXN0WENUZXN0c0luVGVzdEJ1bmRsZSAob3B0cykge1xuICBjb25zdCB7IGJ1bmRsZSB9ID0gb3B0cztcbiAgaWYgKCFfLmlzU3RyaW5nKGJ1bmRsZSkpIHtcbiAgICB0aHJvdyBuZXcgZXJyb3JzLkludmFsaWRBcmd1bWVudEVycm9yKGAnYnVuZGxlJyBpcyBhIHJlcXVpcmVkIHBhcmFtZXRlciBmb3IgJ2xpc3RYQ1Rlc3RzSW5UZXN0QnVuZGxlJyBhbmQgYCArXG4gICAgICBgbXVzdCBiZSBhIHN0cmluZy4gRm91bmQgJyR7YnVuZGxlfSdgKTtcbiAgfVxuICBjb25zdCBpZGIgPSBhc3NlcnRJREIodGhpcy5vcHRzKTtcbiAgcmV0dXJuIGF3YWl0IGlkYi5saXN0WENUZXN0c0luVGVzdEJ1bmRsZShidW5kbGUpO1xufTtcblxuT2JqZWN0LmFzc2lnbihjb21tYW5kcyk7XG5leHBvcnQgeyBjb21tYW5kcyB9O1xuZXhwb3J0IGRlZmF1bHQgY29tbWFuZHM7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUdBLE1BQU1BLFFBQVEsR0FBRyxDQUFDLENBQUM7QUFBQztBQUVwQixNQUFNQyxjQUFjLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJO0FBRXJDLE1BQU1DLFNBQVMsR0FBR0MsZUFBTSxDQUFDQyxTQUFTLENBQUMsUUFBUSxDQUFDO0FBT3JDLFNBQVNDLFNBQVMsQ0FBRUMsSUFBSSxFQUFFO0VBQUE7RUFDL0IsSUFBSSxrQkFBQ0EsSUFBSSxDQUFDQyxNQUFNLHlDQUFYLGFBQWFDLEdBQUcsS0FBSSxDQUFDRixJQUFJLENBQUNHLGFBQWEsRUFBRTtJQUM1QyxNQUFNLElBQUlDLEtBQUssQ0FBRSxnRkFBK0UsR0FDN0YsOERBQTZELENBQUM7RUFDbkU7RUFDQSxPQUFPSixJQUFJLENBQUNDLE1BQU0sQ0FBQ0MsR0FBRztBQUN4QjtBQW1CTyxTQUFTRyxpQkFBaUIsQ0FBRUMsTUFBTSxFQUFFO0VBRXpDLFNBQVNDLFFBQVEsQ0FBRUMsSUFBSSxFQUFFO0lBQ3ZCLE1BQU1DLEtBQUssR0FBR0QsSUFBSSxDQUFDRSxLQUFLLENBQUMsR0FBRyxDQUFDO0lBQzdCLElBQUlDLEdBQUcsR0FBRyxFQUFFO0lBQ1osS0FBSyxNQUFNQyxJQUFJLElBQUlILEtBQUssRUFBRTtNQUN4QkUsR0FBRyxJQUFJQyxJQUFJLENBQUNDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUNDLFdBQVcsRUFBRSxHQUFHRixJQUFJLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDekQ7SUFDQSxPQUFPRixHQUFHLENBQUNFLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUNFLFdBQVcsRUFBRSxHQUFHSixHQUFHLENBQUNFLE1BQU0sQ0FBQyxDQUFDLENBQUM7RUFDdkQ7RUFHQSxTQUFT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
|
|
182
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjb21tYW5kcyIsIlhDVEVTVF9USU1FT1VUIiwieGN0ZXN0TG9nIiwibG9nZ2VyIiwiZ2V0TG9nZ2VyIiwiYXNzZXJ0SURCIiwib3B0cyIsImRldmljZSIsImlkYiIsImxhdW5jaFdpdGhJREIiLCJFcnJvciIsInBhcnNlWENUZXN0U3Rkb3V0Iiwic3Rkb3V0IiwicGFyc2VLZXkiLCJuYW1lIiwid29yZHMiLCJzcGxpdCIsIm91dCIsIndvcmQiLCJzdWJzdHIiLCJ0b1VwcGVyQ2FzZSIsInRvTG93ZXJDYXNlIiwicGFyc2VWYWx1ZSIsInZhbHVlIiwiaXNOYU4iLCJfIiwiaXNTdHJpbmciLCJpbmRleE9mIiwicGFyc2VGbG9hdCIsInBhcnNlSW50IiwibGluZXMiLCJ0cmltIiwibGVuZ3RoIiwiaW5jbHVkZXMiLCJyZXN1bHRzIiwibGluZSIsInByb3BlcnRpZXMiLCJvdXRwdXQiLCJlbnRyeUluZGV4IiwicHJvcCIsInRlc3ROYW1lIiwic3RhcnRzV2l0aCIsImxvY2F0aW9uIiwic3Vic3RyaW5nIiwia2V5IiwicGFzc2VkIiwic3RhdHVzIiwiY3Jhc2hlZCIsInB1c2giLCJtb2JpbGVSdW5YQ1Rlc3QiLCJydW5YQ1Rlc3QiLCJ0ZXN0UnVubmVyQnVuZGxlSWQiLCJhcHBVbmRlclRlc3RCdW5kbGVJZCIsInhjdGVzdEJ1bmRsZUlkIiwidGVzdFR5cGUiLCJlbnYiLCJhcmdzIiwidGltZW91dCIsInN1YnByb2MiLCJydW5YQ1VJVGVzdCIsIkIiLCJyZXNvbHZlIiwicmVqZWN0IiwibW9zdFJlY2VudExvZ09iamVjdCIsInhjdGVzdFRpbWVvdXQiLCJsYXN0RXJyb3JNZXNzYWdlIiwic2V0VGltZW91dCIsImVycm9ycyIsIlRpbWVvdXRFcnJvciIsIm9uIiwic3RkZXJyIiwiZXJyIiwibG9nIiwid2FybiIsImRlYnVnIiwic3RhY2siLCJpbmZvIiwiZXJyb3IiLCJjb2RlIiwic2lnbmFsIiwiY2xlYXJUaW1lb3V0IiwicmVzdWx0IiwibW9iaWxlSW5zdGFsbFhDVGVzdEJ1bmRsZSIsImluc3RhbGxYQ1Rlc3RCdW5kbGUiLCJ4Y3Rlc3RBcHAiLCJJbnZhbGlkQXJndW1lbnRFcnJvciIsInJlcyIsImhlbHBlcnMiLCJjb25maWd1cmVBcHAiLCJtb2JpbGVMaXN0WENUZXN0QnVuZGxlcyIsImxpc3RYQ1Rlc3RzSW5UZXN0QnVuZGxlIiwibGlzdFhDVGVzdEJ1bmRsZXMiLCJtb2JpbGVMaXN0WENUZXN0c0luVGVzdEJ1bmRsZSIsImJ1bmRsZSIsIk9iamVjdCIsImFzc2lnbiJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jb21tYW5kcy94Y3Rlc3QuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnYXBwaXVtL3N1cHBvcnQnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IGVycm9ycyB9IGZyb20gJ2FwcGl1bS9kcml2ZXInO1xuXG5cbmNvbnN0IGNvbW1hbmRzID0ge307XG5cbmNvbnN0IFhDVEVTVF9USU1FT1VUID0gNjAgKiA2MCAqIDEwMDA7IC8vIDYwIG1pbnV0ZSB0aW1lb3V0XG5cbmNvbnN0IHhjdGVzdExvZyA9IGxvZ2dlci5nZXRMb2dnZXIoJ1hDVGVzdCcpO1xuXG4vKipcbiAqIEFzc2VydHMgdGhhdCBJREIgaXMgcHJlc2VudCBhbmQgdGhhdCBsYXVuY2hXaXRoSURCIHdhcyB1c2VkXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9wdHMgT3B0cyBvYmplY3QgZnJvbSB0aGUgZHJpdmVyIGluc3RhbmNlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NlcnRJREIgKG9wdHMpIHtcbiAgaWYgKCFvcHRzLmRldmljZT8uaWRiIHx8ICFvcHRzLmxhdW5jaFdpdGhJREIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRvIHVzZSBYQ1Rlc3QgcnVubmVyLCBJREIgKGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9pZGIpIG11c3QgYmUgaW5zdGFsbGVkIGAgK1xuICAgICAgYGFuZCBzZXNzaW9ucyBtdXN0IGJlIHJ1biB3aXRoIHRoZSBcImxhdW5jaFdpdGhJREJcIiBjYXBhYmlsaXR5YCk7XG4gIH1cbiAgcmV0dXJuIG9wdHMuZGV2aWNlLmlkYjtcbn1cblxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFhDVGVzdFJlc3VsdFxuICpcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0ZXN0TmFtZSBOYW1lIG9mIHRoZSB0ZXN0IChlLmcuOiAnWENUZXN0ZXJBcHBVSVRlc3RzIC0gWENUZXN0ZXJBcHBVSVRlc3RzLlhDVGVzdGVyQXBwVUlUZXN0cy90ZXN0RXhhbXBsZScpXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IHBhc3NlZCBEaWQgdGhlIHRlc3RzIHBhc3M/XG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGNyYXNoZWQgRGlkIHRoZSB0ZXN0cyBjcmFzaD9cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzdGF0dXMgVGVzdCByZXN1bHQgc3RhdHVzIChlLmcuOiAncGFzc2VkJywgJ2ZhaWxlZCcsICdjcmFzaGVkJylcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBkdXJhdGlvbiBIb3cgbG9uZyBkaWQgdGhlIHRlc3RzIHRha2UgKGluIHNlY29uZHMpXG4gKiBAcHJvcGVydHkge3N0cmluZ30gZmFpbHVyZU1lc3NhZ2UgRmFpbHVyZSBtZXNzYWdlIChpZiBhcHBsaWNhYmxlKVxuICogQHByb3BlcnR5IHtudW1iZXJ9IGxvY2F0aW9uIFRoZSBnZW9sb2NhdGlvbiBvZiB0aGUgdGVzdHMgKGlmIGFwcGxpY2FibGUpXG4gKi9cblxuLyoqXG4gKiBQYXJzZSB0aGUgc3Rkb3V0IG9mIFhDIHRlc3QgbG9nXG4gKiBAcGFyYW0ge3N0cmluZ30gc3Rkb3V0IEEgbGluZSBvZiBzdGFuZGFyZCBvdXQgZnJvbSBgaWRiIHhjdGVzdCBydW4gLi4uYFxuICogQHJldHVybnMge0FycmF5PFhDVGVzdFJlc3VsdD59IHJlc3VsdHMgVGhlIGZpbmFsIG91dHB1dCBvZiB0aGUgWENUZXN0IHJ1blxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VYQ1Rlc3RTdGRvdXQgKHN0ZG91dCkge1xuICAvLyBQYXJzZXMgYSAna2V5JyBpbnRvIEpTT04gZm9ybWF0XG4gIGZ1bmN0aW9uIHBhcnNlS2V5IChuYW1lKSB7XG4gICAgY29uc3Qgd29yZHMgPSBuYW1lLnNwbGl0KCcgJyk7XG4gICAgbGV0IG91dCA9ICcnO1xuICAgIGZvciAoY29uc3Qgd29yZCBvZiB3b3Jkcykge1xuICAgICAgb3V0ICs9IHdvcmQuc3Vic3RyKDAsIDEpLnRvVXBwZXJDYXNlKCkgKyB3b3JkLnN1YnN0cigxKTtcbiAgICB9XG4gICAgcmV0dXJuIG91dC5zdWJzdHIoMCwgMSkudG9Mb3dlckNhc2UoKSArIG91dC5zdWJzdHIoMSk7XG4gIH1cblxuICAvLyBQYXJzZXMgYSAndmFsdWUnIGludG8gSlNPTiBmb3JtYXRcbiAgZnVuY3Rpb24gcGFyc2VWYWx1ZSAodmFsdWUpIHtcbiAgICB2YWx1ZSA9IHZhbHVlIHx8ICcnO1xuICAgIHN3aXRjaCAodmFsdWUudG9Mb3dlckNhc2UoKSkge1xuICAgICAgY2FzZSAndHJ1ZSc6IHJldHVybiB0cnVlO1xuICAgICAgY2FzZSAnZmFsc2UnOiByZXR1cm4gZmFsc2U7XG4gICAgICBjYXNlICcnOiByZXR1cm4gbnVsbDtcbiAgICAgIGRlZmF1bHQ6IGJyZWFrO1xuICAgIH1cbiAgICBpZiAoIWlzTmFOKHZhbHVlKSkge1xuICAgICAgaWYgKCFfLmlzU3RyaW5nKHZhbHVlKSkge1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH0gZWxzZSBpZiAodmFsdWUuaW5kZXhPZignLicpID4gMCkge1xuICAgICAgICByZXR1cm4gcGFyc2VGbG9hdCh2YWx1ZSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcGFyc2VJbnQodmFsdWUsIDEwKTtcbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmICghc3Rkb3V0KSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLy8gUGFyc2UgZWFjaCBsaW5lIGludG8gYW4gYXJyYXlcbiAgY29uc3QgbGluZXMgPSBzdGRvdXQudHJpbSgpLnNwbGl0KCdcXG4nKTtcblxuICAvLyBPbmUgc2luZ2xlIHN0cmluZywganVzdCByZXR1cm4gdGhlIHN0cmluZ1xuICBpZiAobGluZXMubGVuZ3RoID09PSAxICYmICFsaW5lc1swXS5pbmNsdWRlcygnfCcpKSB7XG4gICAgcmV0dXJuIFtsaW5lc1swXV07XG4gIH1cblxuICBjb25zdCByZXN1bHRzID0gW107XG4gIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgIC8vIFRoZSBwcm9wZXJ0aWVzIGFyZSBzcGxpdCB1cCBieSBwaXBlcyBhbmQgZWFjaCBwcm9wZXJ0eVxuICAgIC8vIGhhcyB0aGUgZm9ybWF0IFwiU29tZSBLZXkgOiBTb21lIFZhbHVlXCJcbiAgICBjb25zdCBwcm9wZXJ0aWVzID0gbGluZS5zcGxpdCgnfCcpO1xuXG4gICAgLy8gUGFyc2UgZWFjaCBwcm9wZXJ0eVxuICAgIGNvbnN0IG91dHB1dCA9IHt9O1xuICAgIGxldCBlbnRyeUluZGV4ID0gMDtcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgcHJvcGVydGllcykge1xuICAgICAgaWYgKGVudHJ5SW5kZXggPT09IDApIHtcbiAgICAgICAgLy8gVGhlIGZpcnN0IHByb3BlcnR5IG9ubHkgY29udGFpbnMgb25lIHN0cmluZyB0aGF0IGNvbnRhaW5zXG4gICAgICAgIC8vIHRoZSB0ZXN0IG5hbWUgKGUuZy46ICdYQ1Rlc3RlckFwcFVJVGVzdHMgLSBYQ1Rlc3RlckFwcFVJVGVzdHMuWENUZXN0ZXJBcHBVSVRlc3RzL3Rlc3RFeGFtcGxlJylcbiAgICAgICAgb3V0cHV0LnRlc3ROYW1lID0gcHJvcC50cmltKCk7XG4gICAgICB9IGVsc2UgaWYgKHByb3AudHJpbSgpLnN0YXJ0c1dpdGgoJ0xvY2F0aW9uJykpIHtcbiAgICAgICAgLy8gVGhlIExvY2F0aW9uIHByb3BlcnR5IGhhcyBhIHZhbHVlIHRoYXQgY29tZXMgYWZ0ZXIgJ0xvY2F0aW9uJyB3aXRob3V0IGNvbG9uLlxuICAgICAgICAvLyBlLmcuIExvY2F0aW9uIC9wYXRoL3RvL1hDVGVzdGVyQXBwVUlUZXN0cy9YQ1Rlc3RlckFwcFVJVGVzdHMuc3dpZnQ6MzZcbiAgICAgICAgb3V0cHV0LmxvY2F0aW9uID0gcHJvcC5zdWJzdHJpbmcocHJvcC5pbmRleE9mKCdMb2NhdGlvbicpICsgOCkudHJpbSgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IFtrZXksIHZhbHVlXSA9IHByb3Auc3BsaXQoJzonKTtcbiAgICAgICAgb3V0cHV0W3BhcnNlS2V5KGtleS50cmltKCkpXSA9IHBhcnNlVmFsdWUodmFsdWUgPyB2YWx1ZS50cmltKCkgOiAnJyk7XG4gICAgICB9XG4gICAgICBlbnRyeUluZGV4Kys7XG4gICAgfVxuXG4gICAgLy8ga2VlcCBiYWNrd2FyZCBjb21wYXRpYmlsaXR5XG4gICAgLy8gb2xkIHBhdHRlcm46IFhDVGVzdGVyQXBwVUlUZXN0cyAtIFhDVGVzdGVyQXBwVUlUZXN0cy5YQ1Rlc3RlckFwcFVJVGVzdHMvdGVzdEV4YW1wbGUgfCBQYXNzZWQ6IFRydWUgfCBDcmFzaGVkOiBGYWxzZSB8IER1cmF0aW9uOiAxLjQ4NSB8IEZhaWx1cmUgbWVzc2FnZTogIHwgTG9jYXRpb24gOjBcbiAgICAvLyBsYXRlc3QgcGF0dGVybjogWENUZXN0ZXJBcHBVSVRlc3RzIC0gWENUZXN0ZXJBcHBVSVRlc3RzLlhDVGVzdGVyQXBwVUlUZXN0cy90ZXN0RXhhbXBsZSB8IFN0YXR1czogcGFzc2VkIHwgRHVyYXRpb246IDEuOTI1NTc4OTUxODM1NjMyM1xuICAgIGlmICghb3V0cHV0LnBhc3NlZCkge1xuICAgICAgb3V0cHV0LnBhc3NlZCA9IG91dHB1dC5zdGF0dXMgPT09ICdwYXNzZWQnO1xuICAgICAgb3V0cHV0LmNyYXNoZWQgPSBvdXRwdXQuc3RhdHVzID09PSAnY3Jhc2hlZCc7XG4gICAgfSBlbHNlIGlmICghb3V0cHV0LnN0YXR1cykge1xuICAgICAgaWYgKG91dHB1dC5wYXNzZWQpIHtcbiAgICAgICAgb3V0cHV0LnN0YXR1cyA9ICdwYXNzZWQnO1xuICAgICAgfSBlbHNlIGlmIChvdXRwdXQuY3Jhc2hlZCkge1xuICAgICAgICBvdXRwdXQuc3RhdHVzID0gJ2NyYXNoZWQnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb3V0cHV0LnN0YXR1cyA9ICdmYWlsZWQnO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFkZCB0aGlzIGxpbmUgdG8gdGhlIHJlc3VsdHNcbiAgICByZXN1bHRzLnB1c2gob3V0cHV0KTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cztcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBSdW5YQ1VJVGVzdFJlc3BvbnNlXG4gKlxuICogQHByb3BlcnR5IHtBcnJheTxYQ1Rlc3RSZXN1bHQ+fSByZXN1bHRzIFRoZSByZXN1bHRzIG9mIGFsbCB0aGUgdGVzdHMgd2l0aCBpbmZvcm1hdGlvblxuICogQHByb3BlcnR5IHtudW1iZXJ9IGNvZGUgVGhlIGV4aXQgY29kZSBvZiB0aGUgcHJvY2Vzc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IHNpZ25hbCBUaGUgc2lnbmFsIHRoYXQgdGVybWluYXRlZCB0aGUgcHJvY2VzcyAob3IgbnVsbCkgKGUuZy46IFNJR1RFUk0pXG4gKlxuICovXG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gUnVuWENVSVRlc3RPcHRpb25zXG4gKlxuICogQHByb3BlcnR5IHshc3RyaW5nfSB0ZXN0UnVubmVyQnVuZGxlSWQgVGVzdCBhcHAgYnVuZGxlIChlLmcuOiAnaW8uYXBwaXVtLlhDVGVzdGVyQXBwVUlUZXN0cy54Y3RydW5uZXInKVxuICogQHByb3BlcnR5IHshc3RyaW5nfSBhcHBVbmRlclRlc3RCdW5kbGVJZCBBcHAtdW5kZXItdGVzdCBidW5kbGVcbiAqIEBwcm9wZXJ0eSB7IXN0cmluZ30geGNUZXN0QnVuZGxlSUQgeGN0ZXN0IGJ1bmRsZSBpZFxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRlc3RUeXBlIFt1aV0gWEMgdGVzdCB0eXBlLiAnYXBwJywgJ3VpJywgb3IgJ2xvZ2ljJ1xuICogQHByb3BlcnR5IHtvYmplY3R9IGVudiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgcGFzc2VkIHRvIHRlc3RcbiAqIEBwcm9wZXJ0eSB7QXJyYXk8U3RyaW5nPn0gYXJncyBMYXVuY2ggYXJndW1lbnRzIHRvIHN0YXJ0IHRoZSB0ZXN0IHdpdGggKHNlZSBodHRwczovL2RldmVsb3Blci5hcHBsZS5jb20vZG9jdW1lbnRhdGlvbi94Y3Rlc3QveGN1aWFwcGxpY2F0aW9uLzE1MDA0NzctbGF1bmNoYXJndW1lbnRzIGZvciByZWZlcmVuY2UpXG4gKiBAcHJvcGVydHkge251bWJlcn0gdGltZW91dCBbMzYwMDAwXSBUaW1lb3V0IGlmIHNlc3Npb24gZG9lc24ndCBjb21wbGV0ZSBhZnRlciBnaXZlbiB0aW1lIChpbiBtaWxsaXNlY29uZHMpXG4gKi9cblxuXG4vKipcbiAqIEB0eXBlZGVmIHtFcnJvcn0gWENVSVRlc3RFcnJvclxuICpcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBjb2RlIFN1YnByb2Nlc3MgZXhpdCBjb2RlXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc2lnbmFsIFRoZSBzaWduYWwgKFNJRyopIHRoYXQgY2F1c2VkIHRoZSBwcm9jZXNzIHRvIGZhaWxcbiAqIEBwcm9wZXJ0eSB7IUFycmF5PFhDVGVzdFJlc3VsdD59IHJlc3VsdHMgVGhlIG91dHB1dCBvZiB0aGUgZmFpbGVkIHRlc3QgKGlmIHRoZXJlIGlzIG91dHB1dClcbiAqL1xuXG4vKipcbiAqIFJ1biBhbiBYQ1Rlc3QuIExhdW5jaGVzIGEgc3VicHJvY2VzcyB0aGF0IHJ1bnMgdGhlIFhDIFRlc3QgYW5kIGJsb2Nrc1xuICogdW50aWwgaXQgaXMgY29tcGxldGUuIFBhcnNlcyB0aGUgc3Rkb3V0IG9mIHRoZSBwcm9jZXNzIGFuZCByZXR1cm5zXG4gKiByZXN1bHQgYXMgYW4gYXJyYXlcbiAqXG4gKiBTZWUgaHR0cHM6Ly9mYmlkYi5pby9kb2NzL3Rlc3RfZXhlY3V0aW9uIGZvciByZWZlcmVuY2VcbiAqXG4gKiBAcGFyYW0ge1J1blhDVUlUZXN0T3B0aW9uc30gcnVuWENVSVRlc3RPcHRpb25zXG4gKiBAdGhyb3dzIHtYQ1VJVGVzdEVycm9yfSBFcnJvciB0aHJvd24gaWYgc3VicHJvY2VzcyByZXR1cm5zIG5vbi16ZXJvIGV4aXQgY29kZVxuICogQHJldHVybnMge1J1blhDVUlUZXN0UmVzcG9uc2V9XG4gKi9cbmNvbW1hbmRzLm1vYmlsZVJ1blhDVGVzdCA9IGFzeW5jIGZ1bmN0aW9uIHJ1blhDVGVzdCAoe1xuICB0ZXN0UnVubmVyQnVuZGxlSWQsXG4gIGFwcFVuZGVyVGVzdEJ1bmRsZUlkLFxuICB4Y3Rlc3RCdW5kbGVJZCxcbiAgdGVzdFR5cGUgPSAndWknLFxuICBlbnYsXG4gIGFyZ3MsXG4gIHRpbWVvdXQgPSBYQ1RFU1RfVElNRU9VVCxcbn0pIHtcbiAgY29uc3Qgc3VicHJvYyA9IGF3YWl0IGFzc2VydElEQih0aGlzLm9wdHMpLnJ1blhDVUlUZXN0KFxuICAgICAgICB0ZXN0UnVubmVyQnVuZGxlSWQsIGFwcFVuZGVyVGVzdEJ1bmRsZUlkLCB4Y3Rlc3RCdW5kbGVJZCwge2VudiwgYXJncywgdGVzdFR5cGV9LFxuICApO1xuICByZXR1cm4gYXdhaXQgbmV3IEIoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGxldCBtb3N0UmVjZW50TG9nT2JqZWN0ID0gbnVsbDtcbiAgICBsZXQgeGN0ZXN0VGltZW91dDtcbiAgICBsZXQgbGFzdEVycm9yTWVzc2FnZSA9IG51bGw7XG4gICAgaWYgKHRpbWVvdXQgPiAwKSB7XG4gICAgICB4Y3Rlc3RUaW1lb3V0ID0gc2V0VGltZW91dChcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBlcnJvcnMuVGltZW91dEVycm9yKGBUaW1lZCBvdXQgYWZ0ZXIgJyR7dGltZW91dH1tcycgd2FpdGluZyBmb3IgWENUZXN0IHRvIGNvbXBsZXRlYCkpLFxuICAgICAgICB0aW1lb3V0XG4gICAgICApO1xuICAgIH1cblxuICAgIHN1YnByb2Mub24oJ291dHB1dCcsIChzdGRvdXQsIHN0ZGVycikgPT4ge1xuICAgICAgaWYgKHN0ZG91dCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIG1vc3RSZWNlbnRMb2dPYmplY3QgPSBwYXJzZVhDVGVzdFN0ZG91dChzdGRvdXQpO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAvLyBGYWlscyBpZiBsb2cgcGFyc2luZyBmYWlscy5cbiAgICAgICAgICAvLyBUaGlzIGlzIGluIGNhc2UgSURCIGNoYW5nZXMgdGhlIHdheSB0aGF0IGxvZ3MgYXJlIGZvcm1hdHRlZCBhbmRcbiAgICAgICAgICAvLyBpdCBicmVha3MgJ3BhcnNlWENUZXN0U3Rkb3V0Jy4gSWYgdGhhdCBoYXBwZW5zIHdlIHN0aWxsIHdhbnQgdGhlIHByb2Nlc3NcbiAgICAgICAgICAvLyB0byBmaW5pc2hcbiAgICAgICAgICB0aGlzLmxvZy53YXJuKGBGYWlsZWQgdG8gcGFyc2UgbG9ncyBmcm9tIHRlc3Qgb3V0cHV0OiAnJHtzdGRvdXR9J2ApO1xuICAgICAgICAgIHRoaXMubG9nLmRlYnVnKGVyci5zdGFjayk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHN0ZGVycikge1xuICAgICAgICBsYXN0RXJyb3JNZXNzYWdlID0gc3RkZXJyO1xuICAgICAgfVxuXG4gICAgICBzdGRvdXQgJiYgeGN0ZXN0TG9nLmluZm8oc3Rkb3V0KTtcbiAgICAgIHN0ZGVyciAmJiB4Y3Rlc3RMb2cuZXJyb3Ioc3RkZXJyKTtcbiAgICB9KTtcblxuICAgIHN1YnByb2Mub24oJ2V4aXQnLCAoY29kZSwgc2lnbmFsKSA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQoeGN0ZXN0VGltZW91dCk7XG4gICAgICBpZiAoY29kZSAhPT0gMCkge1xuICAgICAgICBjb25zdCBlcnIgPSBuZXcgRXJyb3IobGFzdEVycm9yTWVzc2FnZSB8fCBtb3N0UmVjZW50TG9nT2JqZWN0KTtcbiAgICAgICAgZXJyLmNvZGUgPSBjb2RlO1xuICAgICAgICBpZiAoc2lnbmFsICE9IG51bGwpIHtcbiAgICAgICAgICBlcnIuc2lnbmFsID0gc2lnbmFsO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtb3N0UmVjZW50TG9nT2JqZWN0KSB7XG4gICAgICAgICAgZXJyLnJlc3VsdCA9IG1vc3RSZWNlbnRMb2dPYmplY3Q7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlamVjdChlcnIpO1xuICAgICAgfVxuICAgICAgcmVzb2x2ZSh7XG4gICAgICAgIGNvZGUsIHNpZ25hbCwgcmVzdWx0czogbW9zdFJlY2VudExvZ09iamVjdCwgcGFzc2VkOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBJbnN0YWxsWENUZXN0QnVuZGxlT3B0c1xuICpcbiAqIEBwcm9wZXJ0eSB7eGN0ZXN0QXBwfSB4Y3Rlc3RCdW5kbGUgUGF0aCBvZiB0aGUgWENUZXN0IGFwcCAoVVJMIG9yIC5hcHApXG4gKi9cblxuLyoqXG4gKiBJbnN0YWxsIGFuIFhDVGVzdEJ1bmRsZVxuICpcbiAqIEBwYXJhbSB7SW5zdGFsbFhDVGVzdEJ1bmRsZU9wdHMhfSBvcHRzIEluc3RhbGwgeGN0ZXN0IGJ1bmRsZSBvcHRzXG4gKi9cbmNvbW1hbmRzLm1vYmlsZUluc3RhbGxYQ1Rlc3RCdW5kbGUgPSBhc3luYyBmdW5jdGlvbiBpbnN0YWxsWENUZXN0QnVuZGxlIChvcHRzKSB7XG4gIGNvbnN0IHsgeGN0ZXN0QXBwIH0gPSBvcHRzO1xuICBpZiAoIV8uaXNTdHJpbmcoeGN0ZXN0QXBwKSkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuSW52YWxpZEFyZ3VtZW50RXJyb3IoYCd4Y3Rlc3RBcHAnIGlzIGEgcmVxdWlyZWQgcGFyYW1ldGVyIGZvciAnaW5zdGFsbFhDVGVzdEJ1bmRsZScgYW5kIGAgK1xuICAgICAgYG11c3QgYmUgYSBzdHJpbmcuIEZvdW5kICcke3hjdGVzdEFwcH0nYCk7XG4gIH1cbiAgeGN0ZXN0TG9nLmluZm8oYEluc3RhbGxpbmcgYnVuZGxlICcke3hjdGVzdEFwcH0nYCk7XG4gIGNvbnN0IGlkYiA9IGFzc2VydElEQih0aGlzLm9wdHMpO1xuICBjb25zdCByZXMgPSBhd2FpdCB0aGlzLmhlbHBlcnMuY29uZmlndXJlQXBwKHhjdGVzdEFwcCwgJy54Y3Rlc3QnKTtcbiAgYXdhaXQgaWRiLmluc3RhbGxYQ1Rlc3RCdW5kbGUocmVzKTtcbn07XG5cbi8qKlxuICogTGlzdCBYQ1Rlc3QgYnVuZGxlcyB0aGF0IGFyZSBpbnN0YWxsZWQgb24gZGV2aWNlXG4gKlxuICogQHJldHVybnMge0FycmF5PHN0cmluZz59IExpc3Qgb2YgWENUZXN0IGJ1bmRsZXMgKGUuZy46IFwiWENUZXN0ZXJBcHBVSVRlc3RzLlhDVGVzdGVyQXBwVUlUZXN0cy90ZXN0TGF1bmNoUGVyZm9ybWFuY2VcIilcbiAqL1xuY29tbWFuZHMubW9iaWxlTGlzdFhDVGVzdEJ1bmRsZXMgPSBhc3luYyBmdW5jdGlvbiBsaXN0WENUZXN0c0luVGVzdEJ1bmRsZSAoKSB7XG4gIHJldHVybiBhd2FpdCBhc3NlcnRJREIodGhpcy5vcHRzKS5saXN0WENUZXN0QnVuZGxlcygpO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBMaXN0WENUZXN0c09wdHNcbiAqXG4gKiBAcHJvcGVydHkgeyFzdHJpbmd9IGJ1bmRsZSBCdW5kbGUgSUQgb2YgdGhlIFhDVGVzdFxuICovXG5cbi8qKlxuICogTGlzdCBYQ1Rlc3RzIGluIGEgdGVzdCBidW5kbGVcbiAqXG4gKiBAcGFyYW0geyFMaXN0WENUZXN0c09wdHN9IG9wdHMgWENUZXN0IGxpc3Qgb3B0aW9uc1xuICpcbiAqIEByZXR1cm5zIHtBcnJheTxzdHJpbmc+fSBUaGUgbGlzdCBvZiB4Y3Rlc3RzIGluIHRoZSB0ZXN0IGJ1bmRsZVxuICogICAgKGUuZy46IFsgJ1hDVGVzdGVyQXBwVUlUZXN0cy5YQ1Rlc3RlckFwcFVJVGVzdHMvdGVzdEV4YW1wbGUnLFxuICAgICAgICAgICAgICAgICdYQ1Rlc3RlckFwcFVJVGVzdHMuWENUZXN0ZXJBcHBVSVRlc3RzL3Rlc3RMYXVuY2hQZXJmb3JtYW5jZScgXSApXG4gKi9cbmNvbW1hbmRzLm1vYmlsZUxpc3RYQ1Rlc3RzSW5UZXN0QnVuZGxlID0gYXN5bmMgZnVuY3Rpb24gbGlzdFhDVGVzdHNJblRlc3RCdW5kbGUgKG9wdHMpIHtcbiAgY29uc3QgeyBidW5kbGUgfSA9IG9wdHM7XG4gIGlmICghXy5pc1N0cmluZyhidW5kbGUpKSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5JbnZhbGlkQXJndW1lbnRFcnJvcihgJ2J1bmRsZScgaXMgYSByZXF1aXJlZCBwYXJhbWV0ZXIgZm9yICdsaXN0WENUZXN0c0luVGVzdEJ1bmRsZScgYW5kIGAgK1xuICAgICAgYG11c3QgYmUgYSBzdHJpbmcuIEZvdW5kICcke2J1bmRsZX0nYCk7XG4gIH1cbiAgY29uc3QgaWRiID0gYXNzZXJ0SURCKHRoaXMub3B0cyk7XG4gIHJldHVybiBhd2FpdCBpZGIubGlzdFhDVGVzdHNJblRlc3RCdW5kbGUoYnVuZGxlKTtcbn07XG5cbk9iamVjdC5hc3NpZ24oY29tbWFuZHMpO1xuZXhwb3J0IHsgY29tbWFuZHMgfTtcbmV4cG9ydCBkZWZhdWx0IGNvbW1hbmRzO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFHQSxNQUFNQSxRQUFRLEdBQUcsQ0FBQyxDQUFDO0FBQUM7QUFFcEIsTUFBTUMsY0FBYyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSTtBQUVyQyxNQUFNQyxTQUFTLEdBQUdDLGVBQU0sQ0FBQ0MsU0FBUyxDQUFDLFFBQVEsQ0FBQztBQU9yQyxTQUFTQyxTQUFTLENBQUVDLElBQUksRUFBRTtFQUFBO0VBQy9CLElBQUksa0JBQUNBLElBQUksQ0FBQ0MsTUFBTSx5Q0FBWCxhQUFhQyxHQUFHLEtBQUksQ0FBQ0YsSUFBSSxDQUFDRyxhQUFhLEVBQUU7SUFDNUMsTUFBTSxJQUFJQyxLQUFLLENBQUUsZ0ZBQStFLEdBQzdGLDhEQUE2RCxDQUFD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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xctest.js","names":["commands","XCTEST_TIMEOUT","xctestLog","logger","getLogger","assertIDB","opts","device","idb","launchWithIDB","Error","parseXCTestStdout","stdout","parseKey","name","words","split","out","word","substr","toUpperCase","toLowerCase","parseValue","value","isNaN","_","isString","indexOf","parseFloat","parseInt","lines","trim","length","includes","results","line","properties","output","entryIndex","prop","testName","key","push","mobileRunXCTest","runXCTest","testRunnerBundleId","appUnderTestBundleId","xctestBundleId","testType","env","args","timeout","subproc","runXCUITest","B","resolve","reject","mostRecentLogObject","xctestTimeout","setTimeout","on","stderr","err","log","warn","debug","stack","info","error","code","signal","clearTimeout","result","passed","mobileInstallXCTestBundle","installXCTestBundle","xctestApp","errors","InvalidArgumentError","res","helpers","configureApp","mobileListXCTestBundles","listXCTestsInTestBundle","listXCTestBundles","mobileListXCTestsInTestBundle","bundle","Object","assign"],"sources":["../../../lib/commands/xctest.js"],"sourcesContent":["import B from 'bluebird';\nimport { logger } from 'appium/support';\nimport _ from 'lodash';\nimport { errors } from 'appium/driver';\n\n\nconst commands = {};\n\nconst XCTEST_TIMEOUT = 60 * 60 * 1000; // 60 minute timeout\n\nconst xctestLog = logger.getLogger('XCTest');\n\n/**\n * Asserts that IDB is present and that launchWithIDB was used\n *\n * @param {object} opts Opts object from the driver instance\n */\nexport function assertIDB (opts) {\n if (!opts.device?.idb || !opts.launchWithIDB) {\n throw new Error(`To use XCTest runner, IDB (https://github.com/facebook/idb) must be installed ` +\n `and sessions must be run with the \"launchWithIDB\" capability`);\n }\n return opts.device.idb;\n}\n\n\n/**\n * @typedef {Object} XCTestResult\n *\n * @property {string} testName Name of the test (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')\n * @property {boolean} passed Did the tests pass?\n * @property {boolean} crashed Did the tests crash?\n * @property {number} duration How long did the tests take (in seconds)\n * @property {string} failureMessage Failure message (if applicable)\n * @property {number} location The geolocation of the tests (if applicable)\n */\n\n/**\n * Parse the stdout of XC test log\n * @param {string} stdout A line of standard out from `idb xctest run ...`\n * @returns {Array<XCTestResult>} results The final output of the XCTest run\n */\nexport function parseXCTestStdout (stdout) {\n // Parses a 'key' into JSON format\n function parseKey (name) {\n const words = name.split(' ');\n let out = '';\n for (const word of words) {\n out += word.substr(0, 1).toUpperCase() + word.substr(1);\n }\n return out.substr(0, 1).toLowerCase() + out.substr(1);\n }\n\n // Parses a 'value' into JSON format\n function parseValue (value) {\n value = value || '';\n switch (value.toLowerCase()) {\n case 'true': return true;\n case 'false': return false;\n case '': return null;\n default: break;\n }\n if (!isNaN(value)) {\n if (!_.isString(value)) {\n return 0;\n } else if (value.indexOf('.') > 0) {\n return parseFloat(value);\n }\n return parseInt(value, 10);\n }\n }\n if (!stdout) {\n return [];\n }\n\n // Parse each line into an array\n const lines = stdout.trim().split('\\n');\n\n // One single string, just return the string\n if (lines.length === 1 && !lines[0].includes('|')) {\n return [lines[0]];\n }\n\n const results = [];\n for (const line of lines) {\n // The properties are split up by pipes and each property\n // has the format \"Some Key : Some Value\"\n const properties = line.split('|');\n\n // Parse each property\n const output = {};\n let entryIndex = 0;\n for (const prop of properties) {\n if (entryIndex === 0) {\n // The first property only contains one string that contains\n // the test name (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')\n output.testName = prop.trim();\n } else {\n\n let [key, value] = prop.split(':');\n output[parseKey(key.trim())] = parseValue(value ? value.trim() : '');\n }\n entryIndex++;\n }\n // Add this line to the results\n results.push(output);\n }\n return results;\n}\n\n/**\n * @typedef {Object} RunXCUITestResponse\n *\n * @property {Array<XCTestResult>} results The results of all the tests with information\n * @property {number} code The exit code of the process\n * @property {string} signal The signal that terminated the process (or null) (e.g.: SIGTERM)\n *\n */\n\n/**\n * @typedef {Object} RunXCUITestOptions\n *\n * @property {!string} testRunnerBundleId Test app bundle (e.g.: 'io.appium.XCTesterAppUITests.xctrunner')\n * @property {!string} appUnderTestBundleId App-under-test bundle\n * @property {!string} xcTestBundleID xctest bundle id\n * @property {string} testType [ui] XC test type. 'app', 'ui', or 'logic'\n * @property {object} env Environment variables passed to test\n * @property {Array<String>} args Launch arguments to start the test with (see https://developer.apple.com/documentation/xctest/xcuiapplication/1500477-launcharguments for reference)\n * @property {number} timeout [360000] Timeout if session doesn't complete after given time (in milliseconds)\n */\n\n\n/**\n * @typedef {Error} XCUITestError\n *\n * @property {number} code Subprocess exit code\n * @property {string} signal The signal (SIG*) that caused the process to fail\n * @property {!Array<XCTestResult>} results The output of the failed test (if there is output)\n */\n\n/**\n * Run an XCTest. Launches a subprocess that runs the XC Test and blocks\n * until it is complete. Parses the stdout of the process and returns\n * result as an array\n *\n * See https://fbidb.io/docs/test_execution for reference\n *\n * @param {RunXCUITestOptions} runXCUITestOptions\n * @throws {XCUITestError} Error thrown if subprocess returns non-zero exit code\n * @returns {RunXCUITestResponse}\n */\ncommands.mobileRunXCTest = async function runXCTest ({\n testRunnerBundleId,\n appUnderTestBundleId,\n xctestBundleId,\n testType = 'ui',\n env,\n args,\n timeout = XCTEST_TIMEOUT,\n}) {\n const subproc = await assertIDB(this.opts).runXCUITest(\n testRunnerBundleId, appUnderTestBundleId, xctestBundleId, {env, args, testType},\n );\n return await new B((resolve, reject) => {\n let mostRecentLogObject = null;\n let xctestTimeout;\n if (timeout > 0) {\n xctestTimeout = setTimeout(\n () => reject(`Timed out after '${timeout}ms' waiting for XCTest to complete`),\n timeout\n );\n }\n\n subproc.on('output', (stdout, stderr) => {\n if (stdout) {\n try {\n mostRecentLogObject = parseXCTestStdout(stdout);\n } catch (err) {\n // Fails if log parsing fails.\n // This is in case IDB changes the way that logs are formatted and\n // it breaks 'parseXCTestStdout'. If that happens we still want the process\n // to finish\n this.log.warn(`Failed to parse logs from test output: '${stdout}'`);\n this.log.debug(err.stack);\n }\n }\n stdout && xctestLog.info(stdout);\n stderr && xctestLog.error(stderr);\n });\n\n subproc.on('exit', (code, signal) => {\n clearTimeout(xctestTimeout);\n if (code !== 0) {\n const err = new Error(mostRecentLogObject);\n err.code = code;\n if (signal != null) {\n err.signal = signal;\n }\n if (mostRecentLogObject) {\n err.result = mostRecentLogObject;\n }\n return reject(err);\n }\n resolve({\n code, signal, results: mostRecentLogObject, passed: true,\n });\n });\n });\n};\n\n/**\n * @typedef {Object} InstallXCTestBundleOpts\n *\n * @property {xctestApp} xctestBundle Path of the XCTest app (URL or .app)\n */\n\n/**\n * Install an XCTestBundle\n *\n * @param {InstallXCTestBundleOpts!} opts Install xctest bundle opts\n */\ncommands.mobileInstallXCTestBundle = async function installXCTestBundle (opts) {\n const { xctestApp } = opts;\n if (!_.isString(xctestApp)) {\n throw new errors.InvalidArgumentError(`'xctestApp' is a required parameter for 'installXCTestBundle' and ` +\n `must be a string. Found '${xctestApp}'`);\n }\n xctestLog.info(`Installing bundle '${xctestApp}'`);\n const idb = assertIDB(this.opts);\n const res = await this.helpers.configureApp(xctestApp, '.xctest');\n await idb.installXCTestBundle(res);\n};\n\n/**\n * List XCTest bundles that are installed on device\n *\n * @returns {Array<string>} List of XCTest bundles (e.g.: \"XCTesterAppUITests.XCTesterAppUITests/testLaunchPerformance\")\n */\ncommands.mobileListXCTestBundles = async function listXCTestsInTestBundle () {\n return await assertIDB(this.opts).listXCTestBundles();\n};\n\n/**\n * @typedef {Object} ListXCTestsOpts\n *\n * @property {!string} bundle Bundle ID of the XCTest\n */\n\n/**\n * List XCTests in a test bundle\n *\n * @param {!ListXCTestsOpts} opts XCTest list options\n *\n * @returns {Array<string>} The list of xctests in the test bundle\n * (e.g.: [ 'XCTesterAppUITests.XCTesterAppUITests/testExample',\n 'XCTesterAppUITests.XCTesterAppUITests/testLaunchPerformance' ] )\n */\ncommands.mobileListXCTestsInTestBundle = async function listXCTestsInTestBundle (opts) {\n const { bundle } = opts;\n if (!_.isString(bundle)) {\n throw new errors.InvalidArgumentError(`'bundle' is a required parameter for 'listXCTestsInTestBundle' and ` +\n `must be a string. Found '${bundle}'`);\n }\n const idb = assertIDB(this.opts);\n return await idb.listXCTestsInTestBundle(bundle);\n};\n\nObject.assign(commands);\nexport { commands };\nexport default commands;\n"],"mappings":";;;;;;;;;;AAAA;AACA;AACA;AACA;AAGA,MAAMA,QAAQ,GAAG,CAAC,CAAC;AAAC;AAEpB,MAAMC,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;AAErC,MAAMC,SAAS,GAAGC,eAAM,CAACC,SAAS,CAAC,QAAQ,CAAC;AAOrC,SAASC,SAAS,CAAEC,IAAI,EAAE;EAAA;EAC/B,IAAI,kBAACA,IAAI,CAACC,MAAM,yCAAX,aAAaC,GAAG,KAAI,CAACF,IAAI,CAACG,aAAa,EAAE;IAC5C,MAAM,IAAIC,KAAK,CAAE,gFAA+E,GAC7F,8DAA6D,CAAC;EACnE;EACA,OAAOJ,IAAI,CAACC,MAAM,CAACC,GAAG;AACxB;AAmBO,SAASG,iBAAiB,CAAEC,MAAM,EAAE;EAEzC,SAASC,QAAQ,CAAEC,IAAI,EAAE;IACvB,MAAMC,KAAK,GAAGD,IAAI,CAACE,KAAK,CAAC,GAAG,CAAC;IAC7B,IAAIC,GAAG,GAAG,EAAE;IACZ,KAAK,MAAMC,IAAI,IAAIH,KAAK,EAAE;MACxBE,GAAG,IAAIC,IAAI,CAACC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAACC,WAAW,EAAE,GAAGF,IAAI,CAACC,MAAM,CAAC,CAAC,CAAC;IACzD;IACA,OAAOF,GAAG,CAACE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAACE,WAAW,EAAE,GAAGJ,GAAG,CAACE,MAAM,CAAC,CAAC,CAAC;EACvD;EAGA,SAASG,UAAU,CAAEC,KAAK,EAAE;IAC1BA,KAAK,GAAGA,KAAK,IAAI,EAAE;IACnB,QAAQA,KAAK,CAACF,WAAW,EAAE;MACzB,KAAK,MAAM;QAAE,OAAO,IAAI;MACxB,KAAK,OAAO;QAAE,OAAO,KAAK;MAC1B,KAAK,EAAE;QAAE,OAAO,IAAI;MACpB;QAAS;IAAM;IAEjB,IAAI,CAACG,KAAK,CAACD,KAAK,CAAC,EAAE;MACjB,IAAI,CAACE,eAAC,CAACC,QAAQ,CAACH,KAAK,CAAC,EAAE;QACtB,OAAO,CAAC;MACV,CAAC,MAAM,IAAIA,KAAK,CAACI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACjC,OAAOC,UAAU,CAACL,KAAK,CAAC;MAC1B;MACA,OAAOM,QAAQ,CAACN,KAAK,EAAE,EAAE,CAAC;IAC5B;EACF;EACA,IAAI,CAACX,MAAM,EAAE;IACX,OAAO,EAAE;EACX;EAGA,MAAMkB,KAAK,GAAGlB,MAAM,CAACmB,IAAI,EAAE,CAACf,KAAK,CAAC,IAAI,CAAC;EAGvC,IAAIc,KAAK,CAACE,MAAM,KAAK,CAAC,IAAI,CAACF,KAAK,CAAC,CAAC,CAAC,CAACG,QAAQ,CAAC,GAAG,CAAC,EAAE;IACjD,OAAO,CAACH,KAAK,CAAC,CAAC,CAAC,CAAC;EACnB;EAEA,MAAMI,OAAO,GAAG,EAAE;EAClB,KAAK,MAAMC,IAAI,IAAIL,KAAK,EAAE;IAGxB,MAAMM,UAAU,GAAGD,IAAI,CAACnB,KAAK,CAAC,GAAG,CAAC;IAGlC,MAAMqB,MAAM,GAAG,CAAC,CAAC;IACjB,IAAIC,UAAU,GAAG,CAAC;IAClB,KAAK,MAAMC,IAAI,IAAIH,UAAU,EAAE;MAC7B,IAAIE,UAAU,KAAK,CAAC,EAAE;QAGpBD,MAAM,CAACG,QAAQ,GAAGD,IAAI,CAACR,IAAI,EAAE;MAC/B,CAAC,MAAM;QAEL,IAAI,CAACU,GAAG,EAAElB,KAAK,CAAC,GAAGgB,IAAI,CAACvB,KAAK,CAAC,GAAG,CAAC;QAClCqB,MAAM,CAACxB,QAAQ,CAAC4B,GAAG,CAACV,IAAI,EAAE,CAAC,CAAC,GAAGT,UAAU,CAACC,KAAK,GAAGA,KAAK,CAACQ,IAAI,EAAE,GAAG,EAAE,CAAC;MACtE;MACAO,UAAU,EAAE;IACd;IAEAJ,OAAO,CAACQ,IAAI,CAACL,MAAM,CAAC;EACtB;EACA,OAAOH,OAAO;AAChB;AA2CAlC,QAAQ,CAAC2C,eAAe,GAAG,eAAeC,SAAS,CAAE;EACnDC,kBAAkB;EAClBC,oBAAoB;EACpBC,cAAc;EACdC,QAAQ,GAAG,IAAI;EACfC,GAAG;EACHC,IAAI;EACJC,OAAO,GAAGlD;AACZ,CAAC,EAAE;EACD,MAAMmD,OAAO,GAAG,MAAM/C,SAAS,CAAC,IAAI,CAACC,IAAI,CAAC,CAAC+C,WAAW,CAChDR,kBAAkB,EAAEC,oBAAoB,EAAEC,cAAc,EAAE;IAACE,GAAG;IAAEC,IAAI;IAAEF;EAAQ,CAAC,CACpF;EACD,OAAO,MAAM,IAAIM,iBAAC,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;IACtC,IAAIC,mBAAmB,GAAG,IAAI;IAC9B,IAAIC,aAAa;IACjB,IAAIP,OAAO,GAAG,CAAC,EAAE;MACfO,aAAa,GAAGC,UAAU,CACxB,MAAMH,MAAM,CAAE,oBAAmBL,OAAQ,oCAAmC,CAAC,EAC7EA,OAAO,CACR;IACH;IAEAC,OAAO,CAACQ,EAAE,CAAC,QAAQ,EAAE,CAAChD,MAAM,EAAEiD,MAAM,KAAK;MACvC,IAAIjD,MAAM,EAAE;QACV,IAAI;UACF6C,mBAAmB,GAAG9C,iBAAiB,CAACC,MAAM,CAAC;QACjD,CAAC,CAAC,OAAOkD,GAAG,EAAE;UAKZ,IAAI,CAACC,GAAG,CAACC,IAAI,CAAE,2CAA0CpD,MAAO,GAAE,CAAC;UACnE,IAAI,CAACmD,GAAG,CAACE,KAAK,CAACH,GAAG,CAACI,KAAK,CAAC;QAC3B;MACF;MACAtD,MAAM,IAAIV,SAAS,CAACiE,IAAI,CAACvD,MAAM,CAAC;MAChCiD,MAAM,IAAI3D,SAAS,CAACkE,KAAK,CAACP,MAAM,CAAC;IACnC,CAAC,CAAC;IAEFT,OAAO,CAACQ,EAAE,CAAC,MAAM,EAAE,CAACS,IAAI,EAAEC,MAAM,KAAK;MACnCC,YAAY,CAACb,aAAa,CAAC;MAC3B,IAAIW,IAAI,KAAK,CAAC,EAAE;QACd,MAAMP,GAAG,GAAG,IAAIpD,KAAK,CAAC+C,mBAAmB,CAAC;QAC1CK,GAAG,CAACO,IAAI,GAAGA,IAAI;QACf,IAAIC,MAAM,IAAI,IAAI,EAAE;UAClBR,GAAG,CAACQ,MAAM,GAAGA,MAAM;QACrB;QACA,IAAIb,mBAAmB,EAAE;UACvBK,GAAG,CAACU,MAAM,GAAGf,mBAAmB;QAClC;QACA,OAAOD,MAAM,CAACM,GAAG,CAAC;MACpB;MACAP,OAAO,CAAC;QACNc,IAAI;QAAEC,MAAM;QAAEpC,OAAO,EAAEuB,mBAAmB;QAAEgB,MAAM,EAAE;MACtD,CAAC,CAAC;IACJ,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC;AAaDzE,QAAQ,CAAC0E,yBAAyB,GAAG,eAAeC,mBAAmB,CAAErE,IAAI,EAAE;EAC7E,MAAM;IAAEsE;EAAU,CAAC,GAAGtE,IAAI;EAC1B,IAAI,CAACmB,eAAC,CAACC,QAAQ,CAACkD,SAAS,CAAC,EAAE;IAC1B,MAAM,IAAIC,cAAM,CAACC,oBAAoB,CAAE,oEAAmE,GACvG,4BAA2BF,SAAU,GAAE,CAAC;EAC7C;EACA1E,SAAS,CAACiE,IAAI,CAAE,sBAAqBS,SAAU,GAAE,CAAC;EAClD,MAAMpE,GAAG,GAAGH,SAAS,CAAC,IAAI,CAACC,IAAI,CAAC;EAChC,MAAMyE,GAAG,GAAG,MAAM,IAAI,CAACC,OAAO,CAACC,YAAY,CAACL,SAAS,EAAE,SAAS,CAAC;EACjE,MAAMpE,GAAG,CAACmE,mBAAmB,CAACI,GAAG,CAAC;AACpC,CAAC;AAOD/E,QAAQ,CAACkF,uBAAuB,GAAG,eAAeC,uBAAuB,GAAI;EAC3E,OAAO,MAAM9E,SAAS,CAAC,IAAI,CAACC,IAAI,CAAC,CAAC8E,iBAAiB,EAAE;AACvD,CAAC;AAiBDpF,QAAQ,CAACqF,6BAA6B,GAAG,eAAeF,uBAAuB,CAAE7E,IAAI,EAAE;EACrF,MAAM;IAAEgF;EAAO,CAAC,GAAGhF,IAAI;EACvB,IAAI,CAACmB,eAAC,CAACC,QAAQ,CAAC4D,MAAM,CAAC,EAAE;IACvB,MAAM,IAAIT,cAAM,CAACC,oBAAoB,CAAE,qEAAoE,GACxG,4BAA2BQ,MAAO,GAAE,CAAC;EAC1C;EACA,MAAM9E,GAAG,GAAGH,SAAS,CAAC,IAAI,CAACC,IAAI,CAAC;EAChC,OAAO,MAAME,GAAG,CAAC2E,uBAAuB,CAACG,MAAM,CAAC;AAClD,CAAC;AAEDC,MAAM,CAACC,MAAM,CAACxF,QAAQ,CAAC;AAAC,eAETA,QAAQ;AAAA"}
|
|
1
|
+
{"version":3,"file":"xctest.js","names":["commands","XCTEST_TIMEOUT","xctestLog","logger","getLogger","assertIDB","opts","device","idb","launchWithIDB","Error","parseXCTestStdout","stdout","parseKey","name","words","split","out","word","substr","toUpperCase","toLowerCase","parseValue","value","isNaN","_","isString","indexOf","parseFloat","parseInt","lines","trim","length","includes","results","line","properties","output","entryIndex","prop","testName","startsWith","location","substring","key","passed","status","crashed","push","mobileRunXCTest","runXCTest","testRunnerBundleId","appUnderTestBundleId","xctestBundleId","testType","env","args","timeout","subproc","runXCUITest","B","resolve","reject","mostRecentLogObject","xctestTimeout","lastErrorMessage","setTimeout","errors","TimeoutError","on","stderr","err","log","warn","debug","stack","info","error","code","signal","clearTimeout","result","mobileInstallXCTestBundle","installXCTestBundle","xctestApp","InvalidArgumentError","res","helpers","configureApp","mobileListXCTestBundles","listXCTestsInTestBundle","listXCTestBundles","mobileListXCTestsInTestBundle","bundle","Object","assign"],"sources":["../../../lib/commands/xctest.js"],"sourcesContent":["import B from 'bluebird';\nimport { logger } from 'appium/support';\nimport _ from 'lodash';\nimport { errors } from 'appium/driver';\n\n\nconst commands = {};\n\nconst XCTEST_TIMEOUT = 60 * 60 * 1000; // 60 minute timeout\n\nconst xctestLog = logger.getLogger('XCTest');\n\n/**\n * Asserts that IDB is present and that launchWithIDB was used\n *\n * @param {object} opts Opts object from the driver instance\n */\nexport function assertIDB (opts) {\n if (!opts.device?.idb || !opts.launchWithIDB) {\n throw new Error(`To use XCTest runner, IDB (https://github.com/facebook/idb) must be installed ` +\n `and sessions must be run with the \"launchWithIDB\" capability`);\n }\n return opts.device.idb;\n}\n\n\n/**\n * @typedef {Object} XCTestResult\n *\n * @property {string} testName Name of the test (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')\n * @property {boolean} passed Did the tests pass?\n * @property {boolean} crashed Did the tests crash?\n * @property {string} status Test result status (e.g.: 'passed', 'failed', 'crashed')\n * @property {number} duration How long did the tests take (in seconds)\n * @property {string} failureMessage Failure message (if applicable)\n * @property {number} location The geolocation of the tests (if applicable)\n */\n\n/**\n * Parse the stdout of XC test log\n * @param {string} stdout A line of standard out from `idb xctest run ...`\n * @returns {Array<XCTestResult>} results The final output of the XCTest run\n */\nexport function parseXCTestStdout (stdout) {\n // Parses a 'key' into JSON format\n function parseKey (name) {\n const words = name.split(' ');\n let out = '';\n for (const word of words) {\n out += word.substr(0, 1).toUpperCase() + word.substr(1);\n }\n return out.substr(0, 1).toLowerCase() + out.substr(1);\n }\n\n // Parses a 'value' into JSON format\n function parseValue (value) {\n value = value || '';\n switch (value.toLowerCase()) {\n case 'true': return true;\n case 'false': return false;\n case '': return null;\n default: break;\n }\n if (!isNaN(value)) {\n if (!_.isString(value)) {\n return 0;\n } else if (value.indexOf('.') > 0) {\n return parseFloat(value);\n }\n return parseInt(value, 10);\n }\n return value;\n }\n if (!stdout) {\n return [];\n }\n\n // Parse each line into an array\n const lines = stdout.trim().split('\\n');\n\n // One single string, just return the string\n if (lines.length === 1 && !lines[0].includes('|')) {\n return [lines[0]];\n }\n\n const results = [];\n for (const line of lines) {\n // The properties are split up by pipes and each property\n // has the format \"Some Key : Some Value\"\n const properties = line.split('|');\n\n // Parse each property\n const output = {};\n let entryIndex = 0;\n for (const prop of properties) {\n if (entryIndex === 0) {\n // The first property only contains one string that contains\n // the test name (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')\n output.testName = prop.trim();\n } else if (prop.trim().startsWith('Location')) {\n // The Location property has a value that comes after 'Location' without colon.\n // e.g. Location /path/to/XCTesterAppUITests/XCTesterAppUITests.swift:36\n output.location = prop.substring(prop.indexOf('Location') + 8).trim();\n } else {\n let [key, value] = prop.split(':');\n output[parseKey(key.trim())] = parseValue(value ? value.trim() : '');\n }\n entryIndex++;\n }\n\n // keep backward compatibility\n // old pattern: XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample | Passed: True | Crashed: False | Duration: 1.485 | Failure message: | Location :0\n // latest pattern: XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample | Status: passed | Duration: 1.9255789518356323\n if (!output.passed) {\n output.passed = output.status === 'passed';\n output.crashed = output.status === 'crashed';\n } else if (!output.status) {\n if (output.passed) {\n output.status = 'passed';\n } else if (output.crashed) {\n output.status = 'crashed';\n } else {\n output.status = 'failed';\n }\n }\n\n // Add this line to the results\n results.push(output);\n }\n return results;\n}\n\n/**\n * @typedef {Object} RunXCUITestResponse\n *\n * @property {Array<XCTestResult>} results The results of all the tests with information\n * @property {number} code The exit code of the process\n * @property {string} signal The signal that terminated the process (or null) (e.g.: SIGTERM)\n *\n */\n\n/**\n * @typedef {Object} RunXCUITestOptions\n *\n * @property {!string} testRunnerBundleId Test app bundle (e.g.: 'io.appium.XCTesterAppUITests.xctrunner')\n * @property {!string} appUnderTestBundleId App-under-test bundle\n * @property {!string} xcTestBundleID xctest bundle id\n * @property {string} testType [ui] XC test type. 'app', 'ui', or 'logic'\n * @property {object} env Environment variables passed to test\n * @property {Array<String>} args Launch arguments to start the test with (see https://developer.apple.com/documentation/xctest/xcuiapplication/1500477-launcharguments for reference)\n * @property {number} timeout [360000] Timeout if session doesn't complete after given time (in milliseconds)\n */\n\n\n/**\n * @typedef {Error} XCUITestError\n *\n * @property {number} code Subprocess exit code\n * @property {string} signal The signal (SIG*) that caused the process to fail\n * @property {!Array<XCTestResult>} results The output of the failed test (if there is output)\n */\n\n/**\n * Run an XCTest. Launches a subprocess that runs the XC Test and blocks\n * until it is complete. Parses the stdout of the process and returns\n * result as an array\n *\n * See https://fbidb.io/docs/test_execution for reference\n *\n * @param {RunXCUITestOptions} runXCUITestOptions\n * @throws {XCUITestError} Error thrown if subprocess returns non-zero exit code\n * @returns {RunXCUITestResponse}\n */\ncommands.mobileRunXCTest = async function runXCTest ({\n testRunnerBundleId,\n appUnderTestBundleId,\n xctestBundleId,\n testType = 'ui',\n env,\n args,\n timeout = XCTEST_TIMEOUT,\n}) {\n const subproc = await assertIDB(this.opts).runXCUITest(\n testRunnerBundleId, appUnderTestBundleId, xctestBundleId, {env, args, testType},\n );\n return await new B((resolve, reject) => {\n let mostRecentLogObject = null;\n let xctestTimeout;\n let lastErrorMessage = null;\n if (timeout > 0) {\n xctestTimeout = setTimeout(\n () => reject(new errors.TimeoutError(`Timed out after '${timeout}ms' waiting for XCTest to complete`)),\n timeout\n );\n }\n\n subproc.on('output', (stdout, stderr) => {\n if (stdout) {\n try {\n mostRecentLogObject = parseXCTestStdout(stdout);\n } catch (err) {\n // Fails if log parsing fails.\n // This is in case IDB changes the way that logs are formatted and\n // it breaks 'parseXCTestStdout'. If that happens we still want the process\n // to finish\n this.log.warn(`Failed to parse logs from test output: '${stdout}'`);\n this.log.debug(err.stack);\n }\n }\n\n if (stderr) {\n lastErrorMessage = stderr;\n }\n\n stdout && xctestLog.info(stdout);\n stderr && xctestLog.error(stderr);\n });\n\n subproc.on('exit', (code, signal) => {\n clearTimeout(xctestTimeout);\n if (code !== 0) {\n const err = new Error(lastErrorMessage || mostRecentLogObject);\n err.code = code;\n if (signal != null) {\n err.signal = signal;\n }\n if (mostRecentLogObject) {\n err.result = mostRecentLogObject;\n }\n return reject(err);\n }\n resolve({\n code, signal, results: mostRecentLogObject, passed: true,\n });\n });\n });\n};\n\n/**\n * @typedef {Object} InstallXCTestBundleOpts\n *\n * @property {xctestApp} xctestBundle Path of the XCTest app (URL or .app)\n */\n\n/**\n * Install an XCTestBundle\n *\n * @param {InstallXCTestBundleOpts!} opts Install xctest bundle opts\n */\ncommands.mobileInstallXCTestBundle = async function installXCTestBundle (opts) {\n const { xctestApp } = opts;\n if (!_.isString(xctestApp)) {\n throw new errors.InvalidArgumentError(`'xctestApp' is a required parameter for 'installXCTestBundle' and ` +\n `must be a string. Found '${xctestApp}'`);\n }\n xctestLog.info(`Installing bundle '${xctestApp}'`);\n const idb = assertIDB(this.opts);\n const res = await this.helpers.configureApp(xctestApp, '.xctest');\n await idb.installXCTestBundle(res);\n};\n\n/**\n * List XCTest bundles that are installed on device\n *\n * @returns {Array<string>} List of XCTest bundles (e.g.: \"XCTesterAppUITests.XCTesterAppUITests/testLaunchPerformance\")\n */\ncommands.mobileListXCTestBundles = async function listXCTestsInTestBundle () {\n return await assertIDB(this.opts).listXCTestBundles();\n};\n\n/**\n * @typedef {Object} ListXCTestsOpts\n *\n * @property {!string} bundle Bundle ID of the XCTest\n */\n\n/**\n * List XCTests in a test bundle\n *\n * @param {!ListXCTestsOpts} opts XCTest list options\n *\n * @returns {Array<string>} The list of xctests in the test bundle\n * (e.g.: [ 'XCTesterAppUITests.XCTesterAppUITests/testExample',\n 'XCTesterAppUITests.XCTesterAppUITests/testLaunchPerformance' ] )\n */\ncommands.mobileListXCTestsInTestBundle = async function listXCTestsInTestBundle (opts) {\n const { bundle } = opts;\n if (!_.isString(bundle)) {\n throw new errors.InvalidArgumentError(`'bundle' is a required parameter for 'listXCTestsInTestBundle' and ` +\n `must be a string. Found '${bundle}'`);\n }\n const idb = assertIDB(this.opts);\n return await idb.listXCTestsInTestBundle(bundle);\n};\n\nObject.assign(commands);\nexport { commands };\nexport default commands;\n"],"mappings":"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"}
|
package/lib/commands/xctest.js
CHANGED
|
@@ -30,6 +30,7 @@ export function assertIDB (opts) {
|
|
|
30
30
|
* @property {string} testName Name of the test (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')
|
|
31
31
|
* @property {boolean} passed Did the tests pass?
|
|
32
32
|
* @property {boolean} crashed Did the tests crash?
|
|
33
|
+
* @property {string} status Test result status (e.g.: 'passed', 'failed', 'crashed')
|
|
33
34
|
* @property {number} duration How long did the tests take (in seconds)
|
|
34
35
|
* @property {string} failureMessage Failure message (if applicable)
|
|
35
36
|
* @property {number} location The geolocation of the tests (if applicable)
|
|
@@ -68,6 +69,7 @@ export function parseXCTestStdout (stdout) {
|
|
|
68
69
|
}
|
|
69
70
|
return parseInt(value, 10);
|
|
70
71
|
}
|
|
72
|
+
return value;
|
|
71
73
|
}
|
|
72
74
|
if (!stdout) {
|
|
73
75
|
return [];
|
|
@@ -95,13 +97,33 @@ export function parseXCTestStdout (stdout) {
|
|
|
95
97
|
// The first property only contains one string that contains
|
|
96
98
|
// the test name (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')
|
|
97
99
|
output.testName = prop.trim();
|
|
100
|
+
} else if (prop.trim().startsWith('Location')) {
|
|
101
|
+
// The Location property has a value that comes after 'Location' without colon.
|
|
102
|
+
// e.g. Location /path/to/XCTesterAppUITests/XCTesterAppUITests.swift:36
|
|
103
|
+
output.location = prop.substring(prop.indexOf('Location') + 8).trim();
|
|
98
104
|
} else {
|
|
99
|
-
|
|
100
105
|
let [key, value] = prop.split(':');
|
|
101
106
|
output[parseKey(key.trim())] = parseValue(value ? value.trim() : '');
|
|
102
107
|
}
|
|
103
108
|
entryIndex++;
|
|
104
109
|
}
|
|
110
|
+
|
|
111
|
+
// keep backward compatibility
|
|
112
|
+
// old pattern: XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample | Passed: True | Crashed: False | Duration: 1.485 | Failure message: | Location :0
|
|
113
|
+
// latest pattern: XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample | Status: passed | Duration: 1.9255789518356323
|
|
114
|
+
if (!output.passed) {
|
|
115
|
+
output.passed = output.status === 'passed';
|
|
116
|
+
output.crashed = output.status === 'crashed';
|
|
117
|
+
} else if (!output.status) {
|
|
118
|
+
if (output.passed) {
|
|
119
|
+
output.status = 'passed';
|
|
120
|
+
} else if (output.crashed) {
|
|
121
|
+
output.status = 'crashed';
|
|
122
|
+
} else {
|
|
123
|
+
output.status = 'failed';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
105
127
|
// Add this line to the results
|
|
106
128
|
results.push(output);
|
|
107
129
|
}
|
|
@@ -164,9 +186,10 @@ commands.mobileRunXCTest = async function runXCTest ({
|
|
|
164
186
|
return await new B((resolve, reject) => {
|
|
165
187
|
let mostRecentLogObject = null;
|
|
166
188
|
let xctestTimeout;
|
|
189
|
+
let lastErrorMessage = null;
|
|
167
190
|
if (timeout > 0) {
|
|
168
191
|
xctestTimeout = setTimeout(
|
|
169
|
-
() => reject(`Timed out after '${timeout}ms' waiting for XCTest to complete`),
|
|
192
|
+
() => reject(new errors.TimeoutError(`Timed out after '${timeout}ms' waiting for XCTest to complete`)),
|
|
170
193
|
timeout
|
|
171
194
|
);
|
|
172
195
|
}
|
|
@@ -184,6 +207,11 @@ commands.mobileRunXCTest = async function runXCTest ({
|
|
|
184
207
|
this.log.debug(err.stack);
|
|
185
208
|
}
|
|
186
209
|
}
|
|
210
|
+
|
|
211
|
+
if (stderr) {
|
|
212
|
+
lastErrorMessage = stderr;
|
|
213
|
+
}
|
|
214
|
+
|
|
187
215
|
stdout && xctestLog.info(stdout);
|
|
188
216
|
stderr && xctestLog.error(stderr);
|
|
189
217
|
});
|
|
@@ -191,7 +219,7 @@ commands.mobileRunXCTest = async function runXCTest ({
|
|
|
191
219
|
subproc.on('exit', (code, signal) => {
|
|
192
220
|
clearTimeout(xctestTimeout);
|
|
193
221
|
if (code !== 0) {
|
|
194
|
-
const err = new Error(mostRecentLogObject);
|
|
222
|
+
const err = new Error(lastErrorMessage || mostRecentLogObject);
|
|
195
223
|
err.code = code;
|
|
196
224
|
if (signal != null) {
|
|
197
225
|
err.signal = signal;
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-xcuitest-driver",
|
|
3
|
-
"version": "4.16.
|
|
3
|
+
"version": "4.16.3",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "appium-xcuitest-driver",
|
|
9
|
-
"version": "4.16.
|
|
9
|
+
"version": "4.16.3",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@babel/runtime": "^7.0.0",
|
|
13
13
|
"@xmldom/xmldom": "^0.x",
|
|
14
|
-
"appium-idb": "^1.
|
|
14
|
+
"appium-idb": "^1.6.6",
|
|
15
15
|
"appium-ios-device": "^2.4.0",
|
|
16
|
-
"appium-ios-simulator": "^5.0.
|
|
16
|
+
"appium-ios-simulator": "^5.0.2",
|
|
17
17
|
"appium-remote-debugger": "^9.1.1",
|
|
18
18
|
"appium-webdriveragent": "^4.10.12",
|
|
19
19
|
"appium-xcode": "^4.0.0",
|
|
@@ -924,7 +924,7 @@
|
|
|
924
924
|
}
|
|
925
925
|
},
|
|
926
926
|
"node_modules/@types/node": {
|
|
927
|
-
"version": "18.11.
|
|
927
|
+
"version": "18.11.17",
|
|
928
928
|
"license": "MIT"
|
|
929
929
|
},
|
|
930
930
|
"node_modules/@types/normalize-package-data": {
|
|
@@ -1119,7 +1119,7 @@
|
|
|
1119
1119
|
"license": "MIT"
|
|
1120
1120
|
},
|
|
1121
1121
|
"node_modules/appium-idb": {
|
|
1122
|
-
"version": "1.6.
|
|
1122
|
+
"version": "1.6.8",
|
|
1123
1123
|
"license": "Apache-2.0",
|
|
1124
1124
|
"dependencies": {
|
|
1125
1125
|
"@appium/support": "^3.0.0",
|
|
@@ -1156,7 +1156,7 @@
|
|
|
1156
1156
|
}
|
|
1157
1157
|
},
|
|
1158
1158
|
"node_modules/appium-ios-simulator": {
|
|
1159
|
-
"version": "5.0.
|
|
1159
|
+
"version": "5.0.2",
|
|
1160
1160
|
"license": "Apache-2.0",
|
|
1161
1161
|
"dependencies": {
|
|
1162
1162
|
"@appium/support": "^3.0.0",
|
|
@@ -5169,7 +5169,7 @@
|
|
|
5169
5169
|
}
|
|
5170
5170
|
},
|
|
5171
5171
|
"@types/node": {
|
|
5172
|
-
"version": "18.11.
|
|
5172
|
+
"version": "18.11.17"
|
|
5173
5173
|
},
|
|
5174
5174
|
"@types/normalize-package-data": {
|
|
5175
5175
|
"version": "2.4.1"
|
|
@@ -5299,7 +5299,7 @@
|
|
|
5299
5299
|
"version": "1.1.0"
|
|
5300
5300
|
},
|
|
5301
5301
|
"appium-idb": {
|
|
5302
|
-
"version": "1.6.
|
|
5302
|
+
"version": "1.6.8",
|
|
5303
5303
|
"requires": {
|
|
5304
5304
|
"@appium/support": "^3.0.0",
|
|
5305
5305
|
"@babel/runtime": "^7.0.0",
|
|
@@ -5326,7 +5326,7 @@
|
|
|
5326
5326
|
}
|
|
5327
5327
|
},
|
|
5328
5328
|
"appium-ios-simulator": {
|
|
5329
|
-
"version": "5.0.
|
|
5329
|
+
"version": "5.0.2",
|
|
5330
5330
|
"requires": {
|
|
5331
5331
|
"@appium/support": "^3.0.0",
|
|
5332
5332
|
"@babel/runtime": "^7.0.0",
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"xcuitest",
|
|
9
9
|
"xctest"
|
|
10
10
|
],
|
|
11
|
-
"version": "4.16.
|
|
11
|
+
"version": "4.16.3",
|
|
12
12
|
"author": "Appium Contributors",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"repository": {
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@babel/runtime": "^7.0.0",
|
|
70
70
|
"@xmldom/xmldom": "^0.x",
|
|
71
|
-
"appium-idb": "^1.
|
|
71
|
+
"appium-idb": "^1.6.6",
|
|
72
72
|
"appium-ios-device": "^2.4.0",
|
|
73
|
-
"appium-ios-simulator": "^5.0.
|
|
73
|
+
"appium-ios-simulator": "^5.0.2",
|
|
74
74
|
"appium-remote-debugger": "^9.1.1",
|
|
75
75
|
"appium-webdriveragent": "^4.10.12",
|
|
76
76
|
"appium-xcode": "^4.0.0",
|