doc-detective 4.28.0 → 4.29.1
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/dist/cli.js +69 -39
- package/dist/cli.js.map +1 -1
- package/dist/common/src/detectTests.d.ts +9 -0
- package/dist/common/src/detectTests.d.ts.map +1 -1
- package/dist/common/src/detectTests.js +22 -9
- package/dist/common/src/detectTests.js.map +1 -1
- package/dist/common/src/schemas/schemas.json +141 -57
- package/dist/common/src/types/generated/report_v3.d.ts +34 -0
- package/dist/common/src/types/generated/report_v3.d.ts.map +1 -1
- package/dist/common/src/validate.d.ts.map +1 -1
- package/dist/common/src/validate.js +95 -12
- package/dist/common/src/validate.js.map +1 -1
- package/dist/core/config.d.ts +66 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +121 -68
- package/dist/core/config.js.map +1 -1
- package/dist/core/detectTests.d.ts.map +1 -1
- package/dist/core/detectTests.js +142 -36
- package/dist/core/detectTests.js.map +1 -1
- package/dist/core/expressions.d.ts.map +1 -1
- package/dist/core/expressions.js +24 -1
- package/dist/core/expressions.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +55 -16
- package/dist/core/index.js.map +1 -1
- package/dist/core/openapi.d.ts.map +1 -1
- package/dist/core/openapi.js +22 -5
- package/dist/core/openapi.js.map +1 -1
- package/dist/core/resolveTests.d.ts.map +1 -1
- package/dist/core/resolveTests.js +56 -14
- package/dist/core/resolveTests.js.map +1 -1
- package/dist/core/telem.d.ts +2 -1
- package/dist/core/telem.d.ts.map +1 -1
- package/dist/core/telem.js +26 -2
- package/dist/core/telem.js.map +1 -1
- package/dist/core/tests/androidEmulator.d.ts.map +1 -1
- package/dist/core/tests/androidEmulator.js +13 -0
- package/dist/core/tests/androidEmulator.js.map +1 -1
- package/dist/core/tests/appSurface.d.ts +23 -0
- package/dist/core/tests/appSurface.d.ts.map +1 -1
- package/dist/core/tests/appSurface.js +3 -1
- package/dist/core/tests/appSurface.js.map +1 -1
- package/dist/core/tests/findStrategies.d.ts.map +1 -1
- package/dist/core/tests/findStrategies.js +83 -10
- package/dist/core/tests/findStrategies.js.map +1 -1
- package/dist/core/tests/iosSimulator.d.ts.map +1 -1
- package/dist/core/tests/iosSimulator.js +13 -0
- package/dist/core/tests/iosSimulator.js.map +1 -1
- package/dist/core/tests/mobileBrowser.d.ts +1 -0
- package/dist/core/tests/mobileBrowser.d.ts.map +1 -1
- package/dist/core/tests/mobileBrowser.js +8 -0
- package/dist/core/tests/mobileBrowser.js.map +1 -1
- package/dist/core/tests.d.ts +83 -2
- package/dist/core/tests.d.ts.map +1 -1
- package/dist/core/tests.js +572 -70
- package/dist/core/tests.js.map +1 -1
- package/dist/core/utils.d.ts +3 -2
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/core/utils.js +46 -29
- package/dist/core/utils.js.map +1 -1
- package/dist/core/warmPhase.d.ts +161 -0
- package/dist/core/warmPhase.d.ts.map +1 -0
- package/dist/core/warmPhase.js +341 -0
- package/dist/core/warmPhase.js.map +1 -0
- package/dist/index.cjs +1073 -246
- package/dist/utils.d.ts +2 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +41 -8
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -9324,7 +9324,7 @@ var init_schemas = __esm({
|
|
|
9324
9324
|
},
|
|
9325
9325
|
elementText: {
|
|
9326
9326
|
type: "string",
|
|
9327
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
9327
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
9328
9328
|
},
|
|
9329
9329
|
selector: {
|
|
9330
9330
|
type: "string",
|
|
@@ -13470,7 +13470,7 @@ var init_schemas = __esm({
|
|
|
13470
13470
|
},
|
|
13471
13471
|
elementText: {
|
|
13472
13472
|
type: "string",
|
|
13473
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
13473
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
13474
13474
|
},
|
|
13475
13475
|
selector: {
|
|
13476
13476
|
type: "string",
|
|
@@ -18701,7 +18701,7 @@ var init_schemas = __esm({
|
|
|
18701
18701
|
},
|
|
18702
18702
|
elementText: {
|
|
18703
18703
|
type: "string",
|
|
18704
|
-
description: "
|
|
18704
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
18705
18705
|
},
|
|
18706
18706
|
elementId: {
|
|
18707
18707
|
type: "string",
|
|
@@ -19233,7 +19233,7 @@ var init_schemas = __esm({
|
|
|
19233
19233
|
},
|
|
19234
19234
|
elementText: {
|
|
19235
19235
|
type: "string",
|
|
19236
|
-
description: "
|
|
19236
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
19237
19237
|
},
|
|
19238
19238
|
elementId: {
|
|
19239
19239
|
type: "string",
|
|
@@ -54963,7 +54963,7 @@ var init_schemas = __esm({
|
|
|
54963
54963
|
},
|
|
54964
54964
|
elementText: {
|
|
54965
54965
|
type: "string",
|
|
54966
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
54966
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
54967
54967
|
},
|
|
54968
54968
|
selector: {
|
|
54969
54969
|
type: "string",
|
|
@@ -59109,7 +59109,7 @@ var init_schemas = __esm({
|
|
|
59109
59109
|
},
|
|
59110
59110
|
elementText: {
|
|
59111
59111
|
type: "string",
|
|
59112
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
59112
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
59113
59113
|
},
|
|
59114
59114
|
selector: {
|
|
59115
59115
|
type: "string",
|
|
@@ -64340,7 +64340,7 @@ var init_schemas = __esm({
|
|
|
64340
64340
|
},
|
|
64341
64341
|
elementText: {
|
|
64342
64342
|
type: "string",
|
|
64343
|
-
description: "
|
|
64343
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
64344
64344
|
},
|
|
64345
64345
|
elementId: {
|
|
64346
64346
|
type: "string",
|
|
@@ -64872,7 +64872,7 @@ var init_schemas = __esm({
|
|
|
64872
64872
|
},
|
|
64873
64873
|
elementText: {
|
|
64874
64874
|
type: "string",
|
|
64875
|
-
description: "
|
|
64875
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
64876
64876
|
},
|
|
64877
64877
|
elementId: {
|
|
64878
64878
|
type: "string",
|
|
@@ -95536,7 +95536,7 @@ var init_schemas = __esm({
|
|
|
95536
95536
|
},
|
|
95537
95537
|
elementText: {
|
|
95538
95538
|
type: "string",
|
|
95539
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
95539
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
95540
95540
|
},
|
|
95541
95541
|
selector: {
|
|
95542
95542
|
type: "string",
|
|
@@ -99682,7 +99682,7 @@ var init_schemas = __esm({
|
|
|
99682
99682
|
},
|
|
99683
99683
|
elementText: {
|
|
99684
99684
|
type: "string",
|
|
99685
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
99685
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
99686
99686
|
},
|
|
99687
99687
|
selector: {
|
|
99688
99688
|
type: "string",
|
|
@@ -103964,7 +103964,7 @@ var init_schemas = __esm({
|
|
|
103964
103964
|
},
|
|
103965
103965
|
elementText: {
|
|
103966
103966
|
type: "string",
|
|
103967
|
-
description: "
|
|
103967
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
103968
103968
|
},
|
|
103969
103969
|
elementId: {
|
|
103970
103970
|
type: "string",
|
|
@@ -104496,7 +104496,7 @@ var init_schemas = __esm({
|
|
|
104496
104496
|
},
|
|
104497
104497
|
elementText: {
|
|
104498
104498
|
type: "string",
|
|
104499
|
-
description: "
|
|
104499
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
104500
104500
|
},
|
|
104501
104501
|
elementId: {
|
|
104502
104502
|
type: "string",
|
|
@@ -113889,7 +113889,7 @@ var init_schemas = __esm({
|
|
|
113889
113889
|
},
|
|
113890
113890
|
elementText: {
|
|
113891
113891
|
type: "string",
|
|
113892
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
113892
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
113893
113893
|
},
|
|
113894
113894
|
selector: {
|
|
113895
113895
|
type: "string",
|
|
@@ -118035,7 +118035,7 @@ var init_schemas = __esm({
|
|
|
118035
118035
|
},
|
|
118036
118036
|
elementText: {
|
|
118037
118037
|
type: "string",
|
|
118038
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
118038
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
118039
118039
|
},
|
|
118040
118040
|
selector: {
|
|
118041
118041
|
type: "string",
|
|
@@ -123266,7 +123266,7 @@ var init_schemas = __esm({
|
|
|
123266
123266
|
},
|
|
123267
123267
|
elementText: {
|
|
123268
123268
|
type: "string",
|
|
123269
|
-
description: "
|
|
123269
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
123270
123270
|
},
|
|
123271
123271
|
elementId: {
|
|
123272
123272
|
type: "string",
|
|
@@ -123798,7 +123798,7 @@ var init_schemas = __esm({
|
|
|
123798
123798
|
},
|
|
123799
123799
|
elementText: {
|
|
123800
123800
|
type: "string",
|
|
123801
|
-
description: "
|
|
123801
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
123802
123802
|
},
|
|
123803
123803
|
elementId: {
|
|
123804
123804
|
type: "string",
|
|
@@ -159528,7 +159528,7 @@ var init_schemas = __esm({
|
|
|
159528
159528
|
},
|
|
159529
159529
|
elementText: {
|
|
159530
159530
|
type: "string",
|
|
159531
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
159531
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
159532
159532
|
},
|
|
159533
159533
|
selector: {
|
|
159534
159534
|
type: "string",
|
|
@@ -163674,7 +163674,7 @@ var init_schemas = __esm({
|
|
|
163674
163674
|
},
|
|
163675
163675
|
elementText: {
|
|
163676
163676
|
type: "string",
|
|
163677
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
163677
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
163678
163678
|
},
|
|
163679
163679
|
selector: {
|
|
163680
163680
|
type: "string",
|
|
@@ -168905,7 +168905,7 @@ var init_schemas = __esm({
|
|
|
168905
168905
|
},
|
|
168906
168906
|
elementText: {
|
|
168907
168907
|
type: "string",
|
|
168908
|
-
description: "
|
|
168908
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
168909
168909
|
},
|
|
168910
168910
|
elementId: {
|
|
168911
168911
|
type: "string",
|
|
@@ -169437,7 +169437,7 @@ var init_schemas = __esm({
|
|
|
169437
169437
|
},
|
|
169438
169438
|
elementText: {
|
|
169439
169439
|
type: "string",
|
|
169440
|
-
description: "
|
|
169440
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
169441
169441
|
},
|
|
169442
169442
|
elementId: {
|
|
169443
169443
|
type: "string",
|
|
@@ -206906,7 +206906,7 @@ var init_schemas = __esm({
|
|
|
206906
206906
|
},
|
|
206907
206907
|
elementText: {
|
|
206908
206908
|
type: "string",
|
|
206909
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
206909
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
206910
206910
|
},
|
|
206911
206911
|
selector: {
|
|
206912
206912
|
type: "string",
|
|
@@ -211052,7 +211052,7 @@ var init_schemas = __esm({
|
|
|
211052
211052
|
},
|
|
211053
211053
|
elementText: {
|
|
211054
211054
|
type: "string",
|
|
211055
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
211055
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
211056
211056
|
},
|
|
211057
211057
|
selector: {
|
|
211058
211058
|
type: "string",
|
|
@@ -216283,7 +216283,7 @@ var init_schemas = __esm({
|
|
|
216283
216283
|
},
|
|
216284
216284
|
elementText: {
|
|
216285
216285
|
type: "string",
|
|
216286
|
-
description: "
|
|
216286
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
216287
216287
|
},
|
|
216288
216288
|
elementId: {
|
|
216289
216289
|
type: "string",
|
|
@@ -216815,7 +216815,7 @@ var init_schemas = __esm({
|
|
|
216815
216815
|
},
|
|
216816
216816
|
elementText: {
|
|
216817
216817
|
type: "string",
|
|
216818
|
-
description: "
|
|
216818
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
216819
216819
|
},
|
|
216820
216820
|
elementId: {
|
|
216821
216821
|
type: "string",
|
|
@@ -251807,7 +251807,7 @@ var init_schemas = __esm({
|
|
|
251807
251807
|
},
|
|
251808
251808
|
elementText: {
|
|
251809
251809
|
type: "string",
|
|
251810
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
251810
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
251811
251811
|
},
|
|
251812
251812
|
selector: {
|
|
251813
251813
|
type: "string",
|
|
@@ -255953,7 +255953,7 @@ var init_schemas = __esm({
|
|
|
255953
255953
|
},
|
|
255954
255954
|
elementText: {
|
|
255955
255955
|
type: "string",
|
|
255956
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
255956
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
255957
255957
|
},
|
|
255958
255958
|
selector: {
|
|
255959
255959
|
type: "string",
|
|
@@ -261184,7 +261184,7 @@ var init_schemas = __esm({
|
|
|
261184
261184
|
},
|
|
261185
261185
|
elementText: {
|
|
261186
261186
|
type: "string",
|
|
261187
|
-
description: "
|
|
261187
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
261188
261188
|
},
|
|
261189
261189
|
elementId: {
|
|
261190
261190
|
type: "string",
|
|
@@ -261716,7 +261716,7 @@ var init_schemas = __esm({
|
|
|
261716
261716
|
},
|
|
261717
261717
|
elementText: {
|
|
261718
261718
|
type: "string",
|
|
261719
|
-
description: "
|
|
261719
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
261720
261720
|
},
|
|
261721
261721
|
elementId: {
|
|
261722
261722
|
type: "string",
|
|
@@ -299669,7 +299669,7 @@ var init_schemas = __esm({
|
|
|
299669
299669
|
},
|
|
299670
299670
|
elementText: {
|
|
299671
299671
|
type: "string",
|
|
299672
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
299672
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
299673
299673
|
},
|
|
299674
299674
|
selector: {
|
|
299675
299675
|
type: "string",
|
|
@@ -303815,7 +303815,7 @@ var init_schemas = __esm({
|
|
|
303815
303815
|
},
|
|
303816
303816
|
elementText: {
|
|
303817
303817
|
type: "string",
|
|
303818
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
303818
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
303819
303819
|
},
|
|
303820
303820
|
selector: {
|
|
303821
303821
|
type: "string",
|
|
@@ -309046,7 +309046,7 @@ var init_schemas = __esm({
|
|
|
309046
309046
|
},
|
|
309047
309047
|
elementText: {
|
|
309048
309048
|
type: "string",
|
|
309049
|
-
description: "
|
|
309049
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
309050
309050
|
},
|
|
309051
309051
|
elementId: {
|
|
309052
309052
|
type: "string",
|
|
@@ -309578,7 +309578,7 @@ var init_schemas = __esm({
|
|
|
309578
309578
|
},
|
|
309579
309579
|
elementText: {
|
|
309580
309580
|
type: "string",
|
|
309581
|
-
description: "
|
|
309581
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
309582
309582
|
},
|
|
309583
309583
|
elementId: {
|
|
309584
309584
|
type: "string",
|
|
@@ -344570,7 +344570,7 @@ var init_schemas = __esm({
|
|
|
344570
344570
|
},
|
|
344571
344571
|
elementText: {
|
|
344572
344572
|
type: "string",
|
|
344573
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
344573
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
344574
344574
|
},
|
|
344575
344575
|
selector: {
|
|
344576
344576
|
type: "string",
|
|
@@ -348716,7 +348716,7 @@ var init_schemas = __esm({
|
|
|
348716
348716
|
},
|
|
348717
348717
|
elementText: {
|
|
348718
348718
|
type: "string",
|
|
348719
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
348719
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
348720
348720
|
},
|
|
348721
348721
|
selector: {
|
|
348722
348722
|
type: "string",
|
|
@@ -353947,7 +353947,7 @@ var init_schemas = __esm({
|
|
|
353947
353947
|
},
|
|
353948
353948
|
elementText: {
|
|
353949
353949
|
type: "string",
|
|
353950
|
-
description: "
|
|
353950
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
353951
353951
|
},
|
|
353952
353952
|
elementId: {
|
|
353953
353953
|
type: "string",
|
|
@@ -354479,7 +354479,7 @@ var init_schemas = __esm({
|
|
|
354479
354479
|
},
|
|
354480
354480
|
elementText: {
|
|
354481
354481
|
type: "string",
|
|
354482
|
-
description: "
|
|
354482
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
354483
354483
|
},
|
|
354484
354484
|
elementId: {
|
|
354485
354485
|
type: "string",
|
|
@@ -383844,6 +383844,71 @@ var init_schemas = __esm({
|
|
|
383844
383844
|
}
|
|
383845
383845
|
]
|
|
383846
383846
|
}
|
|
383847
|
+
},
|
|
383848
|
+
warm: {
|
|
383849
|
+
type: "object",
|
|
383850
|
+
description: "Results of the run's inline warm phase \u2014 the always-on, best-effort provisioning pass (dependency installs, device boots, session probes) performed between test resolution and test execution. A failed task never gates the run; the per-context paths retry or skip with their normal semantics. Absent when the run ended before the phase (for example, when no specs matched). System-populated.",
|
|
383851
|
+
readOnly: true,
|
|
383852
|
+
additionalProperties: false,
|
|
383853
|
+
required: [
|
|
383854
|
+
"durationMs",
|
|
383855
|
+
"tasks"
|
|
383856
|
+
],
|
|
383857
|
+
properties: {
|
|
383858
|
+
durationMs: {
|
|
383859
|
+
type: "number",
|
|
383860
|
+
description: "Wall-clock duration of the warm phase in milliseconds. Tasks overlap, so this is less than the sum of the per-task durations."
|
|
383861
|
+
},
|
|
383862
|
+
tasks: {
|
|
383863
|
+
type: "array",
|
|
383864
|
+
description: "One entry per executed warm task.",
|
|
383865
|
+
items: {
|
|
383866
|
+
type: "object",
|
|
383867
|
+
additionalProperties: false,
|
|
383868
|
+
required: [
|
|
383869
|
+
"name",
|
|
383870
|
+
"kind",
|
|
383871
|
+
"outcome",
|
|
383872
|
+
"durationMs"
|
|
383873
|
+
],
|
|
383874
|
+
properties: {
|
|
383875
|
+
name: {
|
|
383876
|
+
type: "string",
|
|
383877
|
+
description: "Task identity, e.g. `browser-install:chrome` or `device-boot:android:<default>:<latest>`."
|
|
383878
|
+
},
|
|
383879
|
+
kind: {
|
|
383880
|
+
type: "string",
|
|
383881
|
+
enum: [
|
|
383882
|
+
"driver-install",
|
|
383883
|
+
"browser-install",
|
|
383884
|
+
"device-boot",
|
|
383885
|
+
"wda-check",
|
|
383886
|
+
"session-probe",
|
|
383887
|
+
"chromedriver-prefetch"
|
|
383888
|
+
],
|
|
383889
|
+
description: "What the task pre-pays: a native app driver install, a browser install, a simulator/emulator boot, the managed WebDriverAgent availability check, the concurrent-run driver session probe, or the android mobile-web chromedriver download."
|
|
383890
|
+
},
|
|
383891
|
+
outcome: {
|
|
383892
|
+
type: "string",
|
|
383893
|
+
enum: [
|
|
383894
|
+
"warmed",
|
|
383895
|
+
"skipped",
|
|
383896
|
+
"failed"
|
|
383897
|
+
],
|
|
383898
|
+
description: "`warmed` \u2014 the work was performed (for device boots, the boot was initiated); `skipped` \u2014 nothing to do or the environment isn't ready (the consuming context handles it as usual); `failed` \u2014 the attempt failed (logged as a warning; never fails the run)."
|
|
383899
|
+
},
|
|
383900
|
+
durationMs: {
|
|
383901
|
+
type: "number",
|
|
383902
|
+
description: "Wall-clock duration of this task in milliseconds."
|
|
383903
|
+
},
|
|
383904
|
+
note: {
|
|
383905
|
+
type: "string",
|
|
383906
|
+
description: "Human-readable detail about the outcome."
|
|
383907
|
+
}
|
|
383908
|
+
}
|
|
383909
|
+
}
|
|
383910
|
+
}
|
|
383911
|
+
}
|
|
383847
383912
|
}
|
|
383848
383913
|
},
|
|
383849
383914
|
required: [
|
|
@@ -383865,7 +383930,26 @@ var init_schemas = __esm({
|
|
|
383865
383930
|
}
|
|
383866
383931
|
]
|
|
383867
383932
|
}
|
|
383868
|
-
]
|
|
383933
|
+
],
|
|
383934
|
+
warm: {
|
|
383935
|
+
durationMs: 4211,
|
|
383936
|
+
tasks: [
|
|
383937
|
+
{
|
|
383938
|
+
name: "browser-install:chrome",
|
|
383939
|
+
kind: "browser-install",
|
|
383940
|
+
outcome: "skipped",
|
|
383941
|
+
durationMs: 2,
|
|
383942
|
+
note: "'chrome' is already available"
|
|
383943
|
+
},
|
|
383944
|
+
{
|
|
383945
|
+
name: "session-probe",
|
|
383946
|
+
kind: "session-probe",
|
|
383947
|
+
outcome: "warmed",
|
|
383948
|
+
durationMs: 4205,
|
|
383949
|
+
note: "1 combination ok"
|
|
383950
|
+
}
|
|
383951
|
+
]
|
|
383952
|
+
}
|
|
383869
383953
|
},
|
|
383870
383954
|
{
|
|
383871
383955
|
specs: [
|
|
@@ -395672,7 +395756,7 @@ var init_schemas = __esm({
|
|
|
395672
395756
|
},
|
|
395673
395757
|
elementText: {
|
|
395674
395758
|
type: "string",
|
|
395675
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
395759
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
395676
395760
|
},
|
|
395677
395761
|
selector: {
|
|
395678
395762
|
type: "string",
|
|
@@ -399818,7 +399902,7 @@ var init_schemas = __esm({
|
|
|
399818
399902
|
},
|
|
399819
399903
|
elementText: {
|
|
399820
399904
|
type: "string",
|
|
399821
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
399905
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
399822
399906
|
},
|
|
399823
399907
|
selector: {
|
|
399824
399908
|
type: "string",
|
|
@@ -405049,7 +405133,7 @@ var init_schemas = __esm({
|
|
|
405049
405133
|
},
|
|
405050
405134
|
elementText: {
|
|
405051
405135
|
type: "string",
|
|
405052
|
-
description: "
|
|
405136
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
405053
405137
|
},
|
|
405054
405138
|
elementId: {
|
|
405055
405139
|
type: "string",
|
|
@@ -405581,7 +405665,7 @@ var init_schemas = __esm({
|
|
|
405581
405665
|
},
|
|
405582
405666
|
elementText: {
|
|
405583
405667
|
type: "string",
|
|
405584
|
-
description: "
|
|
405668
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
405585
405669
|
},
|
|
405586
405670
|
elementId: {
|
|
405587
405671
|
type: "string",
|
|
@@ -440573,7 +440657,7 @@ var init_schemas = __esm({
|
|
|
440573
440657
|
},
|
|
440574
440658
|
elementText: {
|
|
440575
440659
|
type: "string",
|
|
440576
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
440660
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
440577
440661
|
},
|
|
440578
440662
|
selector: {
|
|
440579
440663
|
type: "string",
|
|
@@ -444719,7 +444803,7 @@ var init_schemas = __esm({
|
|
|
444719
444803
|
},
|
|
444720
444804
|
elementText: {
|
|
444721
444805
|
type: "string",
|
|
444722
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
444806
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
444723
444807
|
},
|
|
444724
444808
|
selector: {
|
|
444725
444809
|
type: "string",
|
|
@@ -449950,7 +450034,7 @@ var init_schemas = __esm({
|
|
|
449950
450034
|
},
|
|
449951
450035
|
elementText: {
|
|
449952
450036
|
type: "string",
|
|
449953
|
-
description: "
|
|
450037
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
449954
450038
|
},
|
|
449955
450039
|
elementId: {
|
|
449956
450040
|
type: "string",
|
|
@@ -450482,7 +450566,7 @@ var init_schemas = __esm({
|
|
|
450482
450566
|
},
|
|
450483
450567
|
elementText: {
|
|
450484
450568
|
type: "string",
|
|
450485
|
-
description: "
|
|
450569
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
450486
450570
|
},
|
|
450487
450571
|
elementId: {
|
|
450488
450572
|
type: "string",
|
|
@@ -487166,7 +487250,7 @@ var init_schemas = __esm({
|
|
|
487166
487250
|
},
|
|
487167
487251
|
elementText: {
|
|
487168
487252
|
type: "string",
|
|
487169
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
487253
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
487170
487254
|
},
|
|
487171
487255
|
selector: {
|
|
487172
487256
|
type: "string",
|
|
@@ -491312,7 +491396,7 @@ var init_schemas = __esm({
|
|
|
491312
491396
|
},
|
|
491313
491397
|
elementText: {
|
|
491314
491398
|
type: "string",
|
|
491315
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
491399
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
491316
491400
|
},
|
|
491317
491401
|
selector: {
|
|
491318
491402
|
type: "string",
|
|
@@ -496543,7 +496627,7 @@ var init_schemas = __esm({
|
|
|
496543
496627
|
},
|
|
496544
496628
|
elementText: {
|
|
496545
496629
|
type: "string",
|
|
496546
|
-
description: "
|
|
496630
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
496547
496631
|
},
|
|
496548
496632
|
elementId: {
|
|
496549
496633
|
type: "string",
|
|
@@ -497075,7 +497159,7 @@ var init_schemas = __esm({
|
|
|
497075
497159
|
},
|
|
497076
497160
|
elementText: {
|
|
497077
497161
|
type: "string",
|
|
497078
|
-
description: "
|
|
497162
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
497079
497163
|
},
|
|
497080
497164
|
elementId: {
|
|
497081
497165
|
type: "string",
|
|
@@ -535412,7 +535496,7 @@ var init_schemas = __esm({
|
|
|
535412
535496
|
},
|
|
535413
535497
|
elementText: {
|
|
535414
535498
|
type: "string",
|
|
535415
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
535499
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
535416
535500
|
},
|
|
535417
535501
|
selector: {
|
|
535418
535502
|
type: "string",
|
|
@@ -539558,7 +539642,7 @@ var init_schemas = __esm({
|
|
|
539558
539642
|
},
|
|
539559
539643
|
elementText: {
|
|
539560
539644
|
type: "string",
|
|
539561
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
539645
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
539562
539646
|
},
|
|
539563
539647
|
selector: {
|
|
539564
539648
|
type: "string",
|
|
@@ -544789,7 +544873,7 @@ var init_schemas = __esm({
|
|
|
544789
544873
|
},
|
|
544790
544874
|
elementText: {
|
|
544791
544875
|
type: "string",
|
|
544792
|
-
description: "
|
|
544876
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
544793
544877
|
},
|
|
544794
544878
|
elementId: {
|
|
544795
544879
|
type: "string",
|
|
@@ -545321,7 +545405,7 @@ var init_schemas = __esm({
|
|
|
545321
545405
|
},
|
|
545322
545406
|
elementText: {
|
|
545323
545407
|
type: "string",
|
|
545324
|
-
description: "
|
|
545408
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
545325
545409
|
},
|
|
545326
545410
|
elementId: {
|
|
545327
545411
|
type: "string",
|
|
@@ -580313,7 +580397,7 @@ var init_schemas = __esm({
|
|
|
580313
580397
|
},
|
|
580314
580398
|
elementText: {
|
|
580315
580399
|
type: "string",
|
|
580316
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
580400
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
580317
580401
|
},
|
|
580318
580402
|
selector: {
|
|
580319
580403
|
type: "string",
|
|
@@ -584459,7 +584543,7 @@ var init_schemas = __esm({
|
|
|
584459
584543
|
},
|
|
584460
584544
|
elementText: {
|
|
584461
584545
|
type: "string",
|
|
584462
|
-
description: "Display text of the element to find. If combined with other element finding fields, the element must match all specified criteria."
|
|
584546
|
+
description: "Display text of the element to find. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed to single spaces), so text a framework splits across several nodes still matches and a driver's surrounding whitespace doesn't cause a miss. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text. If combined with other element finding fields, the element must match all specified criteria."
|
|
584463
584547
|
},
|
|
584464
584548
|
selector: {
|
|
584465
584549
|
type: "string",
|
|
@@ -589690,7 +589774,7 @@ var init_schemas = __esm({
|
|
|
589690
589774
|
},
|
|
589691
589775
|
elementText: {
|
|
589692
589776
|
type: "string",
|
|
589693
|
-
description: "
|
|
589777
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
589694
589778
|
},
|
|
589695
589779
|
elementId: {
|
|
589696
589780
|
type: "string",
|
|
@@ -590222,7 +590306,7 @@ var init_schemas = __esm({
|
|
|
590222
590306
|
},
|
|
590223
590307
|
elementText: {
|
|
590224
590308
|
type: "string",
|
|
590225
|
-
description: "
|
|
590309
|
+
description: "Display text of the element to wait for. Matched against the element's full visible text with whitespace normalized (leading/trailing trimmed, internal runs collapsed), so framework-fragmented text still matches. Wrap the value in slashes (`/pattern/`) to match a substring by regular expression instead of the whole normalized text."
|
|
590226
590310
|
},
|
|
590227
590311
|
elementId: {
|
|
590228
590312
|
type: "string",
|
|
@@ -631784,6 +631868,9 @@ function getRandomUUID() {
|
|
|
631784
631868
|
return v.toString(16);
|
|
631785
631869
|
});
|
|
631786
631870
|
}
|
|
631871
|
+
function cloneForValidation(object) {
|
|
631872
|
+
return JSON.parse(JSON.stringify(object));
|
|
631873
|
+
}
|
|
631787
631874
|
function escapeRegExp(string) {
|
|
631788
631875
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
631789
631876
|
}
|
|
@@ -631807,29 +631894,37 @@ function validate({ schemaKey, object, addDefaults = true }) {
|
|
|
631807
631894
|
result.object = object;
|
|
631808
631895
|
return result;
|
|
631809
631896
|
}
|
|
631810
|
-
validationObject =
|
|
631897
|
+
validationObject = cloneForValidation(object);
|
|
631811
631898
|
result.valid = check(validationObject);
|
|
631812
631899
|
result.errors = "";
|
|
631813
631900
|
if (check.errors) {
|
|
631901
|
+
const targetErrors = check.errors;
|
|
631814
631902
|
const compatibleSchemasList = compatibleSchemas[schemaKey];
|
|
631815
631903
|
if (!compatibleSchemasList) {
|
|
631816
|
-
result.errors =
|
|
631904
|
+
result.errors = targetErrors.map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`).join(", ");
|
|
631817
631905
|
result.object = object;
|
|
631818
631906
|
result.valid = false;
|
|
631819
631907
|
return result;
|
|
631820
631908
|
}
|
|
631821
|
-
|
|
631822
|
-
|
|
631823
|
-
|
|
631824
|
-
if (check2 && check2(validationObject))
|
|
631825
|
-
return key;
|
|
631909
|
+
let matchedSchemaKey = compatibleSchemasList.find((key) => {
|
|
631910
|
+
const probe = ajvCheck.getSchema(key);
|
|
631911
|
+
return probe(object);
|
|
631826
631912
|
});
|
|
631827
631913
|
if (!matchedSchemaKey) {
|
|
631828
|
-
|
|
631914
|
+
matchedSchemaKey = compatibleSchemasList.find((key) => {
|
|
631915
|
+
const mutatingCheck = ajv.getSchema(key);
|
|
631916
|
+
return mutatingCheck(cloneForValidation(object));
|
|
631917
|
+
});
|
|
631918
|
+
}
|
|
631919
|
+
if (!matchedSchemaKey) {
|
|
631920
|
+
result.errors = targetErrors.map((error) => `${error.instancePath} ${error.message} (${JSON.stringify(error.params)})`).join(", ");
|
|
631829
631921
|
result.object = object;
|
|
631830
631922
|
result.valid = false;
|
|
631831
631923
|
return result;
|
|
631832
631924
|
} else {
|
|
631925
|
+
validationObject = cloneForValidation(object);
|
|
631926
|
+
const matchedCheck = ajv.getSchema(matchedSchemaKey);
|
|
631927
|
+
matchedCheck(validationObject);
|
|
631833
631928
|
const transformedObject = transformToSchemaKey({
|
|
631834
631929
|
currentSchema: matchedSchemaKey,
|
|
631835
631930
|
targetSchema: schemaKey,
|
|
@@ -632186,7 +632281,7 @@ Errors: ${result.errors}`);
|
|
|
632186
632281
|
}
|
|
632187
632282
|
return null;
|
|
632188
632283
|
}
|
|
632189
|
-
var import_ajv, import_ajv_formats, import_ajv_keywords, import_ajv_errors, import_dynamicDefaults, ajv, compatibleSchemas;
|
|
632284
|
+
var import_ajv, import_ajv_formats, import_ajv_keywords, import_ajv_errors, import_dynamicDefaults, ajv, ajvCheck, compatibleSchemas;
|
|
632190
632285
|
var init_validate = __esm({
|
|
632191
632286
|
"dist/common/src/validate.js"() {
|
|
632192
632287
|
"use strict";
|
|
@@ -632203,12 +632298,23 @@ var init_validate = __esm({
|
|
|
632203
632298
|
allowUnionTypes: true,
|
|
632204
632299
|
coerceTypes: true
|
|
632205
632300
|
});
|
|
632301
|
+
ajvCheck = new import_ajv.default({
|
|
632302
|
+
strictSchema: false,
|
|
632303
|
+
useDefaults: false,
|
|
632304
|
+
allErrors: true,
|
|
632305
|
+
allowUnionTypes: true,
|
|
632306
|
+
coerceTypes: false
|
|
632307
|
+
});
|
|
632206
632308
|
import_dynamicDefaults.default.DEFAULTS.uuid = (_args) => getRandomUUID;
|
|
632207
632309
|
(0, import_ajv_formats.default)(ajv);
|
|
632208
632310
|
(0, import_ajv_keywords.default)(ajv);
|
|
632209
632311
|
(0, import_ajv_errors.default)(ajv);
|
|
632312
|
+
(0, import_ajv_formats.default)(ajvCheck);
|
|
632313
|
+
(0, import_ajv_keywords.default)(ajvCheck);
|
|
632314
|
+
(0, import_ajv_errors.default)(ajvCheck);
|
|
632210
632315
|
for (const [key, value] of Object.entries(schemas)) {
|
|
632211
632316
|
ajv.addSchema(value, key);
|
|
632317
|
+
ajvCheck.addSchema(value, key);
|
|
632212
632318
|
}
|
|
632213
632319
|
compatibleSchemas = {
|
|
632214
632320
|
config_v3: ["config_v2"],
|
|
@@ -633638,8 +633744,8 @@ function waitForStdio(bg, expected, { deadline }) {
|
|
|
633638
633744
|
return Promise.reject(new Error(`waitUntil.stdio: invalid regular expression ${expected}: ${error.message}`));
|
|
633639
633745
|
}
|
|
633640
633746
|
}
|
|
633641
|
-
const
|
|
633642
|
-
const matched = () =>
|
|
633747
|
+
const matchesText2 = (text) => regex ? regex.test(text) : text.includes(expected);
|
|
633748
|
+
const matched = () => matchesText2(bg.getStdout()) || matchesText2(bg.getStderr());
|
|
633643
633749
|
return new Promise((resolve, reject) => {
|
|
633644
633750
|
if (matched())
|
|
633645
633751
|
return resolve();
|
|
@@ -633977,21 +634083,24 @@ async function loadEnvs(envsFile) {
|
|
|
633977
634083
|
return { status: "FAIL", description: "Invalid file." };
|
|
633978
634084
|
}
|
|
633979
634085
|
}
|
|
634086
|
+
function logLevelEnabled(config, level) {
|
|
634087
|
+
const currentLevel = config.logLevel || "info";
|
|
634088
|
+
if (currentLevel === "error" && level === "error")
|
|
634089
|
+
return true;
|
|
634090
|
+
if (currentLevel === "warning" && (level === "error" || level === "warning"))
|
|
634091
|
+
return true;
|
|
634092
|
+
if (currentLevel === "info" && (level === "error" || level === "warning" || level === "info"))
|
|
634093
|
+
return true;
|
|
634094
|
+
if (currentLevel === "debug" && (level === "error" || level === "warning" || level === "info" || level === "debug"))
|
|
634095
|
+
return true;
|
|
634096
|
+
return false;
|
|
634097
|
+
}
|
|
633980
634098
|
async function log(config, level, message) {
|
|
633981
634099
|
if (message === void 0) {
|
|
633982
634100
|
message = config;
|
|
633983
634101
|
config = {};
|
|
633984
634102
|
}
|
|
633985
|
-
|
|
633986
|
-
if (config.logLevel === "error" && level === "error") {
|
|
633987
|
-
logLevelMatch = true;
|
|
633988
|
-
} else if (config.logLevel === "warning" && (level === "error" || level === "warning")) {
|
|
633989
|
-
logLevelMatch = true;
|
|
633990
|
-
} else if (config.logLevel === "info" && (level === "error" || level === "warning" || level === "info")) {
|
|
633991
|
-
logLevelMatch = true;
|
|
633992
|
-
} else if (config.logLevel === "debug" && (level === "error" || level === "warning" || level === "info" || level === "debug")) {
|
|
633993
|
-
logLevelMatch = true;
|
|
633994
|
-
}
|
|
634103
|
+
const logLevelMatch = logLevelEnabled(config, level);
|
|
633995
634104
|
if (logLevelMatch) {
|
|
633996
634105
|
if (typeof message === "string") {
|
|
633997
634106
|
let logMessage = `(${level.toUpperCase()}) ${message}`;
|
|
@@ -634076,8 +634185,7 @@ function replaceEnvs(stringOrObject) {
|
|
|
634076
634185
|
stringOrObject[key] = replaceEnvs(stringOrObject[key]);
|
|
634077
634186
|
});
|
|
634078
634187
|
} else if (typeof stringOrObject === "string") {
|
|
634079
|
-
const
|
|
634080
|
-
const matches = stringOrObject.match(variableRegex);
|
|
634188
|
+
const matches = stringOrObject.match(ENV_VAR_REGEX);
|
|
634081
634189
|
if (!matches)
|
|
634082
634190
|
return stringOrObject;
|
|
634083
634191
|
matches.forEach((match) => {
|
|
@@ -634321,7 +634429,7 @@ function llevenshteinDistance(s, t) {
|
|
|
634321
634429
|
}
|
|
634322
634430
|
return arr[t.length][s.length];
|
|
634323
634431
|
}
|
|
634324
|
-
var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, posixBashProbe;
|
|
634432
|
+
var import_node_fs7, import_node_os2, import_node_path5, import_node_crypto2, import_promises, import_node_net, import_axios, import_node_child_process4, BACKGROUND_BUFFER_LIMIT, PTY_PACKAGE, READY_POLL_INTERVAL_MS, TRANSIENT_SESSION_ERROR, SESSION_TIMEOUT_ABORT, TRANSIENT_PROCESS_INIT_EXIT_CODES, SETTLE_CEILING_MAX_MS, PRESERVED_TEMP_ENTRIES, FETCH_BINARY_DEFAULTS, ENV_VAR_REGEX, posixBashProbe;
|
|
634325
634433
|
var init_utils = __esm({
|
|
634326
634434
|
"dist/core/utils.js"() {
|
|
634327
634435
|
"use strict";
|
|
@@ -634363,6 +634471,7 @@ var init_utils = __esm({
|
|
|
634363
634471
|
maxBodyLength: 50 * 1024 * 1024,
|
|
634364
634472
|
maxRedirects: 5
|
|
634365
634473
|
};
|
|
634474
|
+
ENV_VAR_REGEX = /\$[a-zA-Z0-9_]+(?![a-zA-Z0-9_$])/g;
|
|
634366
634475
|
}
|
|
634367
634476
|
});
|
|
634368
634477
|
|
|
@@ -635014,12 +635123,19 @@ var init_files = __esm({
|
|
|
635014
635123
|
});
|
|
635015
635124
|
|
|
635016
635125
|
// dist/core/openapi.js
|
|
635126
|
+
function getGenerator() {
|
|
635127
|
+
if (!jsfPromise) {
|
|
635128
|
+
jsfPromise = import("json-schema-faker").then(({ createGenerator }) => createGenerator({ optionalsProbability: 0 }));
|
|
635129
|
+
}
|
|
635130
|
+
return jsfPromise;
|
|
635131
|
+
}
|
|
635017
635132
|
async function loadDescription(descriptionPath = "") {
|
|
635018
635133
|
if (!descriptionPath) {
|
|
635019
635134
|
throw new Error("Description is required.");
|
|
635020
635135
|
}
|
|
635021
635136
|
const definition = await readFile({ fileURLOrPath: descriptionPath });
|
|
635022
|
-
const
|
|
635137
|
+
const parser = (await import("@apidevtools/json-schema-ref-parser")).default;
|
|
635138
|
+
const dereferencedDefinition = await parser.dereference(definition);
|
|
635023
635139
|
return dereferencedDefinition;
|
|
635024
635140
|
}
|
|
635025
635141
|
async function getOperation(definition = {}, operationId = "", responseCode = "", exampleKey = "", server = "") {
|
|
@@ -635143,7 +635259,8 @@ async function getExample(definition = {}, exampleKey = "", generateFromSchema =
|
|
|
635143
635259
|
}
|
|
635144
635260
|
if (generateFromSchema && definition.type) {
|
|
635145
635261
|
try {
|
|
635146
|
-
|
|
635262
|
+
const generator = await getGenerator();
|
|
635263
|
+
example = await generator.generate(definition);
|
|
635147
635264
|
if (example)
|
|
635148
635265
|
return example;
|
|
635149
635266
|
} catch (error) {
|
|
@@ -635218,15 +635335,12 @@ function checkForExamples(definition = {}, exampleKey = "") {
|
|
|
635218
635335
|
return true;
|
|
635219
635336
|
return false;
|
|
635220
635337
|
}
|
|
635221
|
-
var
|
|
635338
|
+
var jsfPromise;
|
|
635222
635339
|
var init_openapi = __esm({
|
|
635223
635340
|
"dist/core/openapi.js"() {
|
|
635224
635341
|
"use strict";
|
|
635225
635342
|
init_utils();
|
|
635226
|
-
import_json_schema_faker = require("json-schema-faker");
|
|
635227
635343
|
init_files();
|
|
635228
|
-
import_json_schema_ref_parser = __toESM(require("@apidevtools/json-schema-ref-parser"), 1);
|
|
635229
|
-
jsf = (0, import_json_schema_faker.createGenerator)({ optionalsProbability: 0 });
|
|
635230
635344
|
}
|
|
635231
635345
|
});
|
|
635232
635346
|
|
|
@@ -635234,9 +635348,11 @@ var init_openapi = __esm({
|
|
|
635234
635348
|
var config_exports = {};
|
|
635235
635349
|
__export(config_exports, {
|
|
635236
635350
|
clearAppCache: () => clearAppCache,
|
|
635351
|
+
detectInstalledBrowserDrivers: () => detectInstalledBrowserDrivers,
|
|
635237
635352
|
getAvailableApps: () => getAvailableApps,
|
|
635238
635353
|
getBrowserDiagnostics: () => getBrowserDiagnostics,
|
|
635239
635354
|
getEnvironment: () => getEnvironment,
|
|
635355
|
+
patchAppCache: () => patchAppCache,
|
|
635240
635356
|
resolveConcurrentRunners: () => resolveConcurrentRunners,
|
|
635241
635357
|
setConfig: () => setConfig,
|
|
635242
635358
|
verifyAppDrivers: () => verifyAppDrivers
|
|
@@ -635447,13 +635563,62 @@ function clearAppCache(config) {
|
|
|
635447
635563
|
}
|
|
635448
635564
|
cachedAppsByDir.delete(cacheKeyFor(config));
|
|
635449
635565
|
}
|
|
635566
|
+
async function patchAppCache(config, installed, deps = {}) {
|
|
635567
|
+
const key = cacheKeyFor(config);
|
|
635568
|
+
try {
|
|
635569
|
+
const verify = deps.verify ?? verifyDriverBinary;
|
|
635570
|
+
const drivers = (deps.detectDrivers ?? detectInstalledBrowserDrivers)(config);
|
|
635571
|
+
const descriptors = [];
|
|
635572
|
+
for (const b of installed ?? []) {
|
|
635573
|
+
if (b.name === "chrome" && b.path && b.driverPath && drivers.chromium) {
|
|
635574
|
+
descriptors.push({
|
|
635575
|
+
app: {
|
|
635576
|
+
name: "chrome",
|
|
635577
|
+
version: b.version,
|
|
635578
|
+
path: b.path,
|
|
635579
|
+
driver: b.driverPath
|
|
635580
|
+
},
|
|
635581
|
+
driverName: "chromedriver",
|
|
635582
|
+
driverPath: b.driverPath
|
|
635583
|
+
});
|
|
635584
|
+
} else if (b.name === "firefox" && b.path && drivers.gecko) {
|
|
635585
|
+
descriptors.push({
|
|
635586
|
+
app: { name: "firefox", version: b.version, path: b.path },
|
|
635587
|
+
driverName: b.driverPath ? "geckodriver" : void 0,
|
|
635588
|
+
driverPath: b.driverPath
|
|
635589
|
+
});
|
|
635590
|
+
}
|
|
635591
|
+
}
|
|
635592
|
+
if (descriptors.length === 0) {
|
|
635593
|
+
cachedAppsByDir.delete(key);
|
|
635594
|
+
return;
|
|
635595
|
+
}
|
|
635596
|
+
const verifiedApps = await verifyAppDrivers(descriptors, {
|
|
635597
|
+
verify: (driverName, driverPath) => verify(driverName, driverPath),
|
|
635598
|
+
logger: (msg, level) => log(config, level ?? "warning", msg)
|
|
635599
|
+
});
|
|
635600
|
+
const existing = cachedAppsByDir.get(key) ?? [];
|
|
635601
|
+
const existingNames = new Set(existing.map((a) => a?.name));
|
|
635602
|
+
const additions = verifiedApps.filter((a) => !existingNames.has(a?.name));
|
|
635603
|
+
cachedAppsByDir.set(key, [...existing, ...additions]);
|
|
635604
|
+
} catch {
|
|
635605
|
+
cachedAppsByDir.delete(key);
|
|
635606
|
+
}
|
|
635607
|
+
}
|
|
635608
|
+
function detectInstalledBrowserDrivers(config, isInstalled = (name) => Boolean(resolveHeavyDepPath(name, { cacheDir: config?.cacheDir }))) {
|
|
635609
|
+
return {
|
|
635610
|
+
chromium: isInstalled("appium-chromium-driver"),
|
|
635611
|
+
gecko: isInstalled("appium-geckodriver"),
|
|
635612
|
+
safari: isInstalled("appium-safari-driver")
|
|
635613
|
+
};
|
|
635614
|
+
}
|
|
635450
635615
|
async function probeBrowserEnvironment({ config, browsersDir }) {
|
|
635451
635616
|
setAppiumHome({ cacheDir: config?.cacheDir });
|
|
635452
635617
|
const cwd = process.cwd();
|
|
635453
635618
|
process.chdir(import_node_path9.default.join(__dirname4, "../.."));
|
|
635454
635619
|
let installedBrowsers = [];
|
|
635455
635620
|
let browserDetectionFailed = false;
|
|
635456
|
-
let
|
|
635621
|
+
let installedDrivers = { chromium: false, gecko: false, safari: false };
|
|
635457
635622
|
try {
|
|
635458
635623
|
const browsersInstalled = resolveHeavyDepPath("@puppeteer/browsers", {
|
|
635459
635624
|
cacheDir: config?.cacheDir
|
|
@@ -635473,47 +635638,11 @@ async function probeBrowserEnvironment({ config, browsersDir }) {
|
|
|
635473
635638
|
installedBrowsers = [];
|
|
635474
635639
|
}
|
|
635475
635640
|
}
|
|
635476
|
-
|
|
635477
|
-
cacheDir: config?.cacheDir
|
|
635478
|
-
});
|
|
635479
|
-
const installedAppiumDrivers = await new Promise((resolve) => {
|
|
635480
|
-
if (!appiumEntry) {
|
|
635481
|
-
resolve({
|
|
635482
|
-
stdout: "",
|
|
635483
|
-
stderr: "appium is not installed; driver list unavailable",
|
|
635484
|
-
exitCode: 1
|
|
635485
|
-
});
|
|
635486
|
-
return;
|
|
635487
|
-
}
|
|
635488
|
-
const child = (0, import_node_child_process6.spawn)(process.execPath, [appiumEntry, "driver", "list"], { env: process.env });
|
|
635489
|
-
let stdout = "";
|
|
635490
|
-
let stderr = "";
|
|
635491
|
-
child.stdout?.on("data", (c) => {
|
|
635492
|
-
stdout += typeof c === "string" ? c : c.toString("utf8");
|
|
635493
|
-
});
|
|
635494
|
-
child.stderr?.on("data", (c) => {
|
|
635495
|
-
stderr += typeof c === "string" ? c : c.toString("utf8");
|
|
635496
|
-
});
|
|
635497
|
-
child.on("error", (err) => {
|
|
635498
|
-
resolve({
|
|
635499
|
-
stdout: stdout.replace(/\n$/, ""),
|
|
635500
|
-
stderr: (stderr + String(err)).replace(/\n$/, ""),
|
|
635501
|
-
exitCode: 1
|
|
635502
|
-
});
|
|
635503
|
-
});
|
|
635504
|
-
child.on("close", (code) => {
|
|
635505
|
-
resolve({
|
|
635506
|
-
stdout: stdout.replace(/\n$/, ""),
|
|
635507
|
-
stderr: stderr.replace(/\n$/, ""),
|
|
635508
|
-
exitCode: code ?? 1
|
|
635509
|
-
});
|
|
635510
|
-
});
|
|
635511
|
-
});
|
|
635512
|
-
appiumDriverOutput = installedAppiumDrivers.stdout + "\n" + installedAppiumDrivers.stderr;
|
|
635641
|
+
installedDrivers = detectInstalledBrowserDrivers(config);
|
|
635513
635642
|
} finally {
|
|
635514
635643
|
process.chdir(cwd);
|
|
635515
635644
|
}
|
|
635516
|
-
return { installedBrowsers,
|
|
635645
|
+
return { installedBrowsers, installedDrivers, browserDetectionFailed };
|
|
635517
635646
|
}
|
|
635518
635647
|
async function getAvailableApps({ config }) {
|
|
635519
635648
|
const browsersDir = getBrowsersDir({ cacheDir: config?.cacheDir });
|
|
@@ -635521,12 +635650,12 @@ async function getAvailableApps({ config }) {
|
|
|
635521
635650
|
const hit = cachedAppsByDir.get(key);
|
|
635522
635651
|
if (hit)
|
|
635523
635652
|
return hit;
|
|
635524
|
-
const { installedBrowsers,
|
|
635653
|
+
const { installedBrowsers, installedDrivers, browserDetectionFailed } = await probeBrowserEnvironment({ config, browsersDir });
|
|
635525
635654
|
const descriptors = [];
|
|
635526
635655
|
const chrome = installedBrowsers.find((browser) => browser.browser === "chrome");
|
|
635527
635656
|
const chromeVersion = chrome?.buildId;
|
|
635528
635657
|
const chromedriver = installedBrowsers.find((browser) => browser.browser === "chromedriver");
|
|
635529
|
-
const appiumChromium =
|
|
635658
|
+
const appiumChromium = installedDrivers.chromium;
|
|
635530
635659
|
if (chrome && chromedriver && appiumChromium) {
|
|
635531
635660
|
descriptors.push({
|
|
635532
635661
|
app: {
|
|
@@ -635540,7 +635669,7 @@ async function getAvailableApps({ config }) {
|
|
|
635540
635669
|
});
|
|
635541
635670
|
}
|
|
635542
635671
|
const firefox = installedBrowsers.find((browser) => browser.browser === "firefox");
|
|
635543
|
-
const appiumFirefox =
|
|
635672
|
+
const appiumFirefox = installedDrivers.gecko;
|
|
635544
635673
|
if (firefox && appiumFirefox) {
|
|
635545
635674
|
const geckodriverPath = resolveGeckodriverBinaryPath(config, browsersDir);
|
|
635546
635675
|
descriptors.push({
|
|
@@ -635556,7 +635685,7 @@ async function getAvailableApps({ config }) {
|
|
|
635556
635685
|
const currentPlatform = config?.environment?.platform ?? getEnvironment().platform;
|
|
635557
635686
|
if (currentPlatform === "mac") {
|
|
635558
635687
|
const safariVersion = await spawnCommand("defaults read /Applications/Safari.app/Contents/Info.plist CFBundleShortVersionString");
|
|
635559
|
-
const appiumSafari =
|
|
635688
|
+
const appiumSafari = installedDrivers.safari;
|
|
635560
635689
|
if (safariVersion.exitCode === 0 && appiumSafari) {
|
|
635561
635690
|
descriptors.push({
|
|
635562
635691
|
app: { name: "safari", version: safariVersion.stdout.trim(), path: "" },
|
|
@@ -636496,17 +636625,24 @@ function detectFileTypeFromContent(content) {
|
|
|
636496
636625
|
}
|
|
636497
636626
|
|
|
636498
636627
|
// dist/common/src/detectTests.js
|
|
636628
|
+
var compiledRegExpCache = /* @__PURE__ */ new Map();
|
|
636499
636629
|
function safeRegExp(pattern, flags) {
|
|
636500
636630
|
if (typeof pattern !== "string" || pattern.length === 0)
|
|
636501
636631
|
return null;
|
|
636502
636632
|
if (pattern.length > 1500)
|
|
636503
636633
|
return null;
|
|
636504
|
-
const
|
|
636634
|
+
const cacheKey = pattern + " " + flags;
|
|
636635
|
+
const cached = compiledRegExpCache.get(cacheKey);
|
|
636636
|
+
if (cached !== void 0)
|
|
636637
|
+
return cached;
|
|
636638
|
+
let compiled;
|
|
636505
636639
|
try {
|
|
636506
|
-
|
|
636640
|
+
compiled = new RegExp(pattern, flags);
|
|
636507
636641
|
} catch {
|
|
636508
|
-
|
|
636642
|
+
compiled = null;
|
|
636509
636643
|
}
|
|
636644
|
+
compiledRegExpCache.set(cacheKey, compiled);
|
|
636645
|
+
return compiled;
|
|
636510
636646
|
}
|
|
636511
636647
|
var HASH_EXCLUDED_KEYS = /* @__PURE__ */ new Set([
|
|
636512
636648
|
"location",
|
|
@@ -638201,6 +638337,7 @@ async function loadHerettoContent(herettoConfig, log3, config, deps) {
|
|
|
638201
638337
|
}
|
|
638202
638338
|
|
|
638203
638339
|
// dist/core/detectTests.js
|
|
638340
|
+
var DETECTION_PARSE_CONCURRENCY = 8;
|
|
638204
638341
|
async function detectTests2({ config }) {
|
|
638205
638342
|
const files = await qualifyFiles({ config });
|
|
638206
638343
|
log(config, "debug", `FILES:`);
|
|
@@ -638219,16 +638356,33 @@ function generateSpecId(filePath) {
|
|
|
638219
638356
|
const normalizedPath = relativePath.split(import_node_path11.default.sep).join("/").replace(/^\.\//, "").replace(/[^a-zA-Z0-9._\-\/]/g, "_");
|
|
638220
638357
|
return normalizedPath;
|
|
638221
638358
|
}
|
|
638222
|
-
|
|
638223
|
-
|
|
638224
|
-
|
|
638225
|
-
|
|
638226
|
-
allowedExtensions = allowedExtensions.concat(fileType.extensions);
|
|
638359
|
+
function buildAllowedExtensions(config) {
|
|
638360
|
+
const allowed = /* @__PURE__ */ new Set(["json", "yaml", "yml"]);
|
|
638361
|
+
(config.fileTypes || []).forEach((fileType) => {
|
|
638362
|
+
fileType.extensions.forEach((ext) => allowed.add(ext));
|
|
638227
638363
|
});
|
|
638364
|
+
return allowed;
|
|
638365
|
+
}
|
|
638366
|
+
async function isValidSourceFile({ config, files, source, allowedExtensions }) {
|
|
638367
|
+
log(config, "debug", `validation: ${source}`);
|
|
638368
|
+
const allowed = allowedExtensions;
|
|
638228
638369
|
if (files.indexOf(source) >= 0)
|
|
638229
638370
|
return false;
|
|
638230
638371
|
if (import_node_path11.default.extname(source) === ".json" || import_node_path11.default.extname(source) === ".yaml" || import_node_path11.default.extname(source) === ".yml") {
|
|
638231
|
-
const
|
|
638372
|
+
const ext = import_node_path11.default.extname(source).slice(1).toLowerCase();
|
|
638373
|
+
let rawContent;
|
|
638374
|
+
try {
|
|
638375
|
+
rawContent = await import_node_fs13.default.promises.readFile(source, "utf8");
|
|
638376
|
+
} catch {
|
|
638377
|
+
log(config, "debug", `${source} couldn't be read. Skipping.`);
|
|
638378
|
+
return false;
|
|
638379
|
+
}
|
|
638380
|
+
let content;
|
|
638381
|
+
try {
|
|
638382
|
+
content = ext === "json" ? JSON.parse(rawContent) : import_yaml3.default.parse(rawContent);
|
|
638383
|
+
} catch {
|
|
638384
|
+
content = rawContent;
|
|
638385
|
+
}
|
|
638232
638386
|
if (typeof content !== "object") {
|
|
638233
638387
|
log(config, "debug", `${source} isn't a valid test specification. Skipping.`);
|
|
638234
638388
|
return false;
|
|
@@ -638269,9 +638423,10 @@ async function isValidSourceFile({ config, files, source }) {
|
|
|
638269
638423
|
}
|
|
638270
638424
|
}
|
|
638271
638425
|
}
|
|
638426
|
+
config._parsedFileCache?.set(source, { rawContent, content });
|
|
638272
638427
|
}
|
|
638273
638428
|
const extension = import_node_path11.default.extname(source).substring(1);
|
|
638274
|
-
if (!
|
|
638429
|
+
if (!allowed.has(extension)) {
|
|
638275
638430
|
log(config, "debug", `${source} extension isn't specified in a \`config.fileTypes\` object. Skipping.`);
|
|
638276
638431
|
return false;
|
|
638277
638432
|
}
|
|
@@ -638311,6 +638466,8 @@ async function qualifyFiles({ config }) {
|
|
|
638311
638466
|
let sequence = [];
|
|
638312
638467
|
const phaseByFile = /* @__PURE__ */ new Map();
|
|
638313
638468
|
config._phaseByFile = phaseByFile;
|
|
638469
|
+
const parsedFileCache = /* @__PURE__ */ new Map();
|
|
638470
|
+
config._parsedFileCache = parsedFileCache;
|
|
638314
638471
|
const toEntries = (value, phase) => (value == null ? [] : [].concat(value)).map((source) => ({
|
|
638315
638472
|
source,
|
|
638316
638473
|
phase
|
|
@@ -638323,6 +638480,7 @@ async function qualifyFiles({ config }) {
|
|
|
638323
638480
|
return [];
|
|
638324
638481
|
}
|
|
638325
638482
|
const ignoredDitaMaps = [];
|
|
638483
|
+
const allowedExtensions = buildAllowedExtensions(config);
|
|
638326
638484
|
if (!config._herettoPathMapping) {
|
|
638327
638485
|
config._herettoPathMapping = {};
|
|
638328
638486
|
}
|
|
@@ -638390,8 +638548,9 @@ async function qualifyFiles({ config }) {
|
|
|
638390
638548
|
let isFile = false;
|
|
638391
638549
|
let isDir = false;
|
|
638392
638550
|
try {
|
|
638393
|
-
|
|
638394
|
-
|
|
638551
|
+
const stat = import_node_fs13.default.statSync(source);
|
|
638552
|
+
isFile = stat.isFile();
|
|
638553
|
+
isDir = stat.isDirectory();
|
|
638395
638554
|
} catch {
|
|
638396
638555
|
log(config, "warning", `Cannot access path: ${source}. Skipping.`);
|
|
638397
638556
|
continue;
|
|
@@ -638406,7 +638565,7 @@ async function qualifyFiles({ config }) {
|
|
|
638406
638565
|
continue;
|
|
638407
638566
|
}
|
|
638408
638567
|
const resolved = import_node_path11.default.resolve(source);
|
|
638409
|
-
if (isFile && await isValidSourceFile({ config, files, source: resolved })) {
|
|
638568
|
+
if (isFile && await isValidSourceFile({ config, files, allowedExtensions, source: resolved })) {
|
|
638410
638569
|
files.push(resolved);
|
|
638411
638570
|
if (!phaseByFile.has(resolved))
|
|
638412
638571
|
phaseByFile.set(resolved, phase);
|
|
@@ -638419,9 +638578,10 @@ async function qualifyFiles({ config }) {
|
|
|
638419
638578
|
const content = import_node_path11.default.resolve(dir + "/" + object);
|
|
638420
638579
|
if (content.includes("node_modules"))
|
|
638421
638580
|
continue;
|
|
638422
|
-
const
|
|
638423
|
-
const
|
|
638424
|
-
|
|
638581
|
+
const stat = import_node_fs13.default.statSync(content);
|
|
638582
|
+
const isFile2 = stat.isFile();
|
|
638583
|
+
const isDir2 = stat.isDirectory();
|
|
638584
|
+
if (isFile2 && await isValidSourceFile({ config, files, allowedExtensions, source: content })) {
|
|
638425
638585
|
const resolved2 = import_node_path11.default.resolve(content);
|
|
638426
638586
|
files.push(resolved2);
|
|
638427
638587
|
if (!phaseByFile.has(resolved2))
|
|
@@ -638436,27 +638596,34 @@ async function qualifyFiles({ config }) {
|
|
|
638436
638596
|
return files;
|
|
638437
638597
|
}
|
|
638438
638598
|
async function parseTests({ config, files }) {
|
|
638439
|
-
|
|
638440
|
-
for (const file of files) {
|
|
638599
|
+
const parseOneFile = async (file) => {
|
|
638441
638600
|
log(config, "debug", `file: ${file}`);
|
|
638442
638601
|
const extension = import_node_path11.default.extname(file).slice(1);
|
|
638443
638602
|
let content = "";
|
|
638444
638603
|
let rawContent;
|
|
638445
638604
|
if (extension === "json" || extension === "yaml" || extension === "yml") {
|
|
638446
|
-
|
|
638447
|
-
|
|
638448
|
-
|
|
638449
|
-
|
|
638450
|
-
|
|
638451
|
-
|
|
638605
|
+
const cached = config._parsedFileCache?.get(file);
|
|
638606
|
+
if (cached) {
|
|
638607
|
+
rawContent = cached.rawContent;
|
|
638608
|
+
content = cached.content;
|
|
638609
|
+
} else {
|
|
638610
|
+
try {
|
|
638611
|
+
rawContent = await import_node_fs13.default.promises.readFile(file, "utf8");
|
|
638612
|
+
if (extension === "json") {
|
|
638613
|
+
content = JSON.parse(rawContent);
|
|
638614
|
+
} else {
|
|
638615
|
+
content = import_yaml3.default.parse(rawContent);
|
|
638616
|
+
}
|
|
638617
|
+
} catch (err) {
|
|
638618
|
+
console.warn(`Failed to read/parse ${file}: ${err.message}`);
|
|
638619
|
+
content = await readFile({ fileURLOrPath: file });
|
|
638452
638620
|
}
|
|
638453
|
-
} catch (err) {
|
|
638454
|
-
console.warn(`Failed to read/parse ${file}: ${err.message}`);
|
|
638455
|
-
content = await readFile({ fileURLOrPath: file });
|
|
638456
638621
|
}
|
|
638457
638622
|
} else {
|
|
638458
638623
|
content = await readFile({ fileURLOrPath: file });
|
|
638459
638624
|
}
|
|
638625
|
+
if (content === null)
|
|
638626
|
+
return null;
|
|
638460
638627
|
if (typeof content === "object") {
|
|
638461
638628
|
if (!content.specId)
|
|
638462
638629
|
content.specId = generateSpecId(file);
|
|
@@ -638520,7 +638687,10 @@ async function parseTests({ config, files }) {
|
|
|
638520
638687
|
content = await resolvePaths({
|
|
638521
638688
|
config,
|
|
638522
638689
|
object: content,
|
|
638523
|
-
filePath: file
|
|
638690
|
+
filePath: file,
|
|
638691
|
+
// Detection only ever resolves specs; passing the known objectType skips
|
|
638692
|
+
// resolvePaths' config_v3-then-spec_v3 discovery probe (item 3.1).
|
|
638693
|
+
objectType: "spec"
|
|
638524
638694
|
});
|
|
638525
638695
|
for (let t = 0; t < content.tests.length; t++) {
|
|
638526
638696
|
const test = content.tests[t];
|
|
@@ -638585,13 +638755,16 @@ async function parseTests({ config, files }) {
|
|
|
638585
638755
|
if (!validation.valid) {
|
|
638586
638756
|
log(config, "warning", validation);
|
|
638587
638757
|
log(config, "warning", `After applying setup and cleanup steps, ${file} isn't a valid test specification. Skipping.`);
|
|
638588
|
-
|
|
638758
|
+
return null;
|
|
638589
638759
|
}
|
|
638590
638760
|
content = validation.object;
|
|
638591
638761
|
content = await resolvePaths({
|
|
638592
638762
|
config,
|
|
638593
638763
|
object: content,
|
|
638594
|
-
filePath: file
|
|
638764
|
+
filePath: file,
|
|
638765
|
+
// Detection only ever resolves specs; passing the known objectType skips
|
|
638766
|
+
// resolvePaths' config_v3-then-spec_v3 discovery probe (item 3.1).
|
|
638767
|
+
objectType: "spec"
|
|
638595
638768
|
});
|
|
638596
638769
|
content._phase = specPhase;
|
|
638597
638770
|
for (const [testIdx, testMap] of stepLocations) {
|
|
@@ -638624,7 +638797,7 @@ async function parseTests({ config, files }) {
|
|
|
638624
638797
|
}
|
|
638625
638798
|
}
|
|
638626
638799
|
}
|
|
638627
|
-
|
|
638800
|
+
return content;
|
|
638628
638801
|
} else {
|
|
638629
638802
|
let id = generateSpecId(file);
|
|
638630
638803
|
let spec = {
|
|
@@ -638652,7 +638825,7 @@ async function parseTests({ config, files }) {
|
|
|
638652
638825
|
});
|
|
638653
638826
|
if (!validation2.valid) {
|
|
638654
638827
|
log(config, "warning", `Failed to convert ${file} to a runShell step: ${validation2.errors}. Skipping.`);
|
|
638655
|
-
|
|
638828
|
+
return null;
|
|
638656
638829
|
}
|
|
638657
638830
|
spec.tests.push(test);
|
|
638658
638831
|
const specValidation = validate({
|
|
@@ -638666,12 +638839,14 @@ async function parseTests({ config, files }) {
|
|
|
638666
638839
|
spec = await resolvePaths({
|
|
638667
638840
|
config,
|
|
638668
638841
|
object: spec,
|
|
638669
|
-
filePath: file
|
|
638842
|
+
filePath: file,
|
|
638843
|
+
// Detection only resolves specs — skip the discovery probe (3.1).
|
|
638844
|
+
objectType: "spec"
|
|
638670
638845
|
});
|
|
638671
638846
|
spec._phase = config._phaseByFile?.get(import_node_path11.default.resolve(file)) ?? "main";
|
|
638672
|
-
|
|
638847
|
+
return spec;
|
|
638673
638848
|
}
|
|
638674
|
-
|
|
638849
|
+
return null;
|
|
638675
638850
|
}
|
|
638676
638851
|
const tests = await detectTests({
|
|
638677
638852
|
config,
|
|
@@ -638693,14 +638868,21 @@ async function parseTests({ config, files }) {
|
|
|
638693
638868
|
spec = await resolvePaths({
|
|
638694
638869
|
config,
|
|
638695
638870
|
object: spec,
|
|
638696
|
-
filePath: file
|
|
638871
|
+
filePath: file,
|
|
638872
|
+
// Detection only resolves specs — skip the discovery probe (3.1).
|
|
638873
|
+
objectType: "spec"
|
|
638697
638874
|
});
|
|
638698
638875
|
spec._phase = config._phaseByFile?.get(import_node_path11.default.resolve(file)) ?? "main";
|
|
638699
|
-
|
|
638876
|
+
return spec;
|
|
638700
638877
|
}
|
|
638701
638878
|
}
|
|
638702
|
-
|
|
638703
|
-
|
|
638879
|
+
return null;
|
|
638880
|
+
};
|
|
638881
|
+
const slots = new Array(files.length).fill(null);
|
|
638882
|
+
await runConcurrent(files.map((_, i) => i), DETECTION_PARSE_CONCURRENCY, async (i) => {
|
|
638883
|
+
slots[i] = await parseOneFile(files[i]);
|
|
638884
|
+
});
|
|
638885
|
+
return slots.filter((spec) => spec != null);
|
|
638704
638886
|
}
|
|
638705
638887
|
|
|
638706
638888
|
// dist/core/resolveTests.js
|
|
@@ -638785,21 +638967,34 @@ function resolveContexts({ contexts, test, config }) {
|
|
|
638785
638967
|
if (resolvedContexts.length === 0) {
|
|
638786
638968
|
resolvedContexts.push({});
|
|
638787
638969
|
}
|
|
638788
|
-
|
|
638970
|
+
if (logLevelEnabled(config, "debug"))
|
|
638971
|
+
log(config, "debug", `Resolved contexts for test ${test.testId}:
|
|
638789
638972
|
${JSON.stringify(resolvedContexts, null, 2)}`);
|
|
638790
638973
|
return resolvedContexts;
|
|
638791
638974
|
}
|
|
638792
638975
|
async function fetchOpenApiDocuments({ config, documentArray }) {
|
|
638793
|
-
|
|
638976
|
+
if (logLevelEnabled(config, "debug"))
|
|
638977
|
+
log(config, "debug", `Fetching OpenAPI documents:
|
|
638794
638978
|
${JSON.stringify(documentArray, null, 2)}`);
|
|
638795
638979
|
const openApiDocuments = [];
|
|
638796
638980
|
if (config?.integrations?.openApi?.length > 0)
|
|
638797
638981
|
openApiDocuments.push(...config.integrations.openApi);
|
|
638982
|
+
const descriptionCache = config._openApiDescriptionCache || (config._openApiDescriptionCache = /* @__PURE__ */ new Map());
|
|
638798
638983
|
if (documentArray?.length > 0) {
|
|
638799
638984
|
for (const definition of documentArray) {
|
|
638800
638985
|
try {
|
|
638801
|
-
|
|
638802
|
-
|
|
638986
|
+
if (!definition.definition) {
|
|
638987
|
+
const key = definition.descriptionPath;
|
|
638988
|
+
let pending = descriptionCache.get(key);
|
|
638989
|
+
if (!pending) {
|
|
638990
|
+
pending = loadDescription(key).catch((err) => {
|
|
638991
|
+
descriptionCache.delete(key);
|
|
638992
|
+
throw err;
|
|
638993
|
+
});
|
|
638994
|
+
descriptionCache.set(key, pending);
|
|
638995
|
+
}
|
|
638996
|
+
definition.definition = await pending;
|
|
638997
|
+
}
|
|
638803
638998
|
} catch (error) {
|
|
638804
638999
|
log(config, "error", `Failed to load OpenAPI definition from ${definition.descriptionPath}: ${error.message}`);
|
|
638805
639000
|
continue;
|
|
@@ -638811,7 +639006,8 @@ ${JSON.stringify(documentArray, null, 2)}`);
|
|
|
638811
639006
|
openApiDocuments.push(definition);
|
|
638812
639007
|
}
|
|
638813
639008
|
}
|
|
638814
|
-
|
|
639009
|
+
if (logLevelEnabled(config, "debug"))
|
|
639010
|
+
log(config, "debug", `Fetched OpenAPI documents:
|
|
638815
639011
|
${JSON.stringify(openApiDocuments, null, 2)}`);
|
|
638816
639012
|
return openApiDocuments;
|
|
638817
639013
|
}
|
|
@@ -638831,7 +639027,8 @@ async function resolveContext({ config, test, context, usedContextIds, openApi }
|
|
|
638831
639027
|
context.contextId = context.contextId ? uniqueId(context.contextId, usedContextIds) : deriveContextId({ context, usedIds: usedContextIds });
|
|
638832
639028
|
const contextId = context.contextId;
|
|
638833
639029
|
usedContextIds.add(contextId);
|
|
638834
|
-
|
|
639030
|
+
if (logLevelEnabled(config, "debug"))
|
|
639031
|
+
log(config, "debug", `RESOLVING CONTEXT ID ${contextId}:
|
|
638835
639032
|
${JSON.stringify(context, null, 2)}`);
|
|
638836
639033
|
const resolvedContext = {
|
|
638837
639034
|
...context,
|
|
@@ -638844,13 +639041,15 @@ ${JSON.stringify(context, null, 2)}`);
|
|
|
638844
639041
|
steps: [...test.steps],
|
|
638845
639042
|
contextId
|
|
638846
639043
|
};
|
|
638847
|
-
|
|
639044
|
+
if (logLevelEnabled(config, "debug"))
|
|
639045
|
+
log(config, "debug", `RESOLVED CONTEXT ${contextId}:
|
|
638848
639046
|
${JSON.stringify(resolvedContext, null, 2)}`);
|
|
638849
639047
|
return resolvedContext;
|
|
638850
639048
|
}
|
|
638851
639049
|
async function resolveTest({ config, spec, test }) {
|
|
638852
639050
|
const testId = test.testId || `${spec.specId}~${contentHash(test)}`;
|
|
638853
|
-
|
|
639051
|
+
if (logLevelEnabled(config, "debug"))
|
|
639052
|
+
log(config, "debug", `RESOLVING TEST ID ${testId}:
|
|
638854
639053
|
${JSON.stringify(test, null, 2)}`);
|
|
638855
639054
|
const resolvedTest = {
|
|
638856
639055
|
...test,
|
|
@@ -638880,13 +639079,15 @@ ${JSON.stringify(test, null, 2)}`);
|
|
|
638880
639079
|
});
|
|
638881
639080
|
resolvedTest.contexts.push(resolvedContext);
|
|
638882
639081
|
}
|
|
638883
|
-
|
|
639082
|
+
if (logLevelEnabled(config, "debug"))
|
|
639083
|
+
log(config, "debug", `RESOLVED TEST ${testId}:
|
|
638884
639084
|
${JSON.stringify(resolvedTest, null, 2)}`);
|
|
638885
639085
|
return resolvedTest;
|
|
638886
639086
|
}
|
|
638887
639087
|
async function resolveSpec({ config, spec }) {
|
|
638888
639088
|
const specId = spec.specId || (spec.contentPath ? generateSpecId(spec.contentPath) : import_node_crypto5.default.randomUUID());
|
|
638889
|
-
|
|
639089
|
+
if (logLevelEnabled(config, "debug"))
|
|
639090
|
+
log(config, "debug", `RESOLVING SPEC ID ${specId}:
|
|
638890
639091
|
${JSON.stringify(spec, null, 2)}`);
|
|
638891
639092
|
const resolvedSpec = {
|
|
638892
639093
|
...spec,
|
|
@@ -638906,24 +639107,28 @@ ${JSON.stringify(spec, null, 2)}`);
|
|
|
638906
639107
|
});
|
|
638907
639108
|
resolvedSpec.tests.push(resolvedTest);
|
|
638908
639109
|
}
|
|
638909
|
-
|
|
639110
|
+
if (logLevelEnabled(config, "debug"))
|
|
639111
|
+
log(config, "debug", `RESOLVED SPEC ${specId}:
|
|
638910
639112
|
${JSON.stringify(resolvedSpec, null, 2)}`);
|
|
638911
639113
|
return resolvedSpec;
|
|
638912
639114
|
}
|
|
638913
639115
|
async function resolveTests({ config, detectedTests }) {
|
|
638914
|
-
|
|
639116
|
+
if (logLevelEnabled(config, "debug"))
|
|
639117
|
+
log(config, "debug", `RESOLVING DETECTED TEST SPECS:
|
|
638915
639118
|
${JSON.stringify(detectedTests, null, 2)}`);
|
|
638916
639119
|
const resolvedTests = {
|
|
638917
639120
|
resolvedTestsId: import_node_crypto5.default.randomUUID(),
|
|
638918
639121
|
config,
|
|
638919
639122
|
specs: []
|
|
638920
639123
|
};
|
|
639124
|
+
config._openApiDescriptionCache = /* @__PURE__ */ new Map();
|
|
638921
639125
|
log(config, "info", "Resolving test specs.");
|
|
638922
639126
|
for (const spec of detectedTests) {
|
|
638923
639127
|
const resolvedSpec = await resolveSpec({ config, spec });
|
|
638924
639128
|
resolvedTests.specs.push(resolvedSpec);
|
|
638925
639129
|
}
|
|
638926
|
-
|
|
639130
|
+
if (logLevelEnabled(config, "debug"))
|
|
639131
|
+
log(config, "debug", `RESOLVED TEST SPECS:
|
|
638927
639132
|
${JSON.stringify(resolvedTests, null, 2)}`);
|
|
638928
639133
|
return resolvedTests;
|
|
638929
639134
|
}
|
|
@@ -641084,6 +641289,13 @@ async function teardownDeviceRegistry(registry, kill4) {
|
|
|
641084
641289
|
for (const entry of registry.values()) {
|
|
641085
641290
|
if (!entry.bootedByUs)
|
|
641086
641291
|
continue;
|
|
641292
|
+
if (entry.ready) {
|
|
641293
|
+
try {
|
|
641294
|
+
await entry.ready;
|
|
641295
|
+
} catch {
|
|
641296
|
+
continue;
|
|
641297
|
+
}
|
|
641298
|
+
}
|
|
641087
641299
|
try {
|
|
641088
641300
|
await kill4(entry);
|
|
641089
641301
|
} catch {
|
|
@@ -642579,7 +642791,7 @@ async function setElementOutputs({ element }) {
|
|
|
642579
642791
|
}
|
|
642580
642792
|
async function findElementByRegex({ pattern, timeout, driver }) {
|
|
642581
642793
|
await driver.pause(timeout);
|
|
642582
|
-
const elements = await driver.$$("//*[normalize-space(
|
|
642794
|
+
const elements = await driver.$$("//*[text()[normalize-space()]]");
|
|
642583
642795
|
for (const element of elements) {
|
|
642584
642796
|
const text = await element.getText();
|
|
642585
642797
|
if (text.match(pattern)) {
|
|
@@ -642666,7 +642878,8 @@ async function findElementByShorthand({ string, timeout = 5e3, driver }) {
|
|
|
642666
642878
|
await el.waitForExist({ timeout });
|
|
642667
642879
|
return el;
|
|
642668
642880
|
}).catch(() => null);
|
|
642669
|
-
const
|
|
642881
|
+
const textLiteral = xpathLiteral2(normalizeText(string));
|
|
642882
|
+
const textPromise = driver.$(`//*[normalize-space(.)=${textLiteral} and not(.//*[normalize-space(.)=${textLiteral}])]`).then(async (el) => {
|
|
642670
642883
|
await el.waitForExist({ timeout });
|
|
642671
642884
|
return el;
|
|
642672
642885
|
}).catch(() => null);
|
|
@@ -642714,6 +642927,24 @@ async function findElementByShorthand({ string, timeout = 5e3, driver }) {
|
|
|
642714
642927
|
function isRegexPattern(str) {
|
|
642715
642928
|
return typeof str === "string" && str.startsWith("/") && str.endsWith("/");
|
|
642716
642929
|
}
|
|
642930
|
+
function normalizeText(value) {
|
|
642931
|
+
return String(value ?? "").replace(/\s+/g, " ").trim();
|
|
642932
|
+
}
|
|
642933
|
+
function xpathLiteral2(value) {
|
|
642934
|
+
if (!value.includes('"'))
|
|
642935
|
+
return `"${value}"`;
|
|
642936
|
+
if (!value.includes("'"))
|
|
642937
|
+
return `'${value}'`;
|
|
642938
|
+
const parts = value.split('"').map((p) => `"${p}"`);
|
|
642939
|
+
return `concat(${parts.join(`, '"', `)})`;
|
|
642940
|
+
}
|
|
642941
|
+
function matchesText(value, pattern) {
|
|
642942
|
+
if (isRegexPattern(pattern)) {
|
|
642943
|
+
const regex = new RegExp(pattern.slice(1, -1));
|
|
642944
|
+
return regex.test(String(value ?? ""));
|
|
642945
|
+
}
|
|
642946
|
+
return normalizeText(value) === normalizeText(pattern);
|
|
642947
|
+
}
|
|
642717
642948
|
function matchesPattern(value, pattern) {
|
|
642718
642949
|
if (isRegexPattern(pattern)) {
|
|
642719
642950
|
const regex = new RegExp(pattern.slice(1, -1));
|
|
@@ -642815,8 +643046,11 @@ async function findElementByCriteria({ selector, elementText, elementId, element
|
|
|
642815
643046
|
}
|
|
642816
643047
|
}
|
|
642817
643048
|
}
|
|
642818
|
-
if (elementText) {
|
|
642819
|
-
|
|
643049
|
+
if (elementText && !isRegexPattern(elementText)) {
|
|
643050
|
+
const lit = xpathLiteral2(normalizeText(elementText));
|
|
643051
|
+
xpathConditions.push(`(normalize-space(.)=${lit} and not(.//*[normalize-space(.)=${lit}]))`);
|
|
643052
|
+
} else if (elementText) {
|
|
643053
|
+
xpathConditions.push(`text()[normalize-space()]`);
|
|
642820
643054
|
}
|
|
642821
643055
|
let xpath;
|
|
642822
643056
|
if (xpathConditions.length > 0) {
|
|
@@ -642893,7 +643127,9 @@ async function findElementByCriteria({ selector, elementText, elementId, element
|
|
|
642893
643127
|
}
|
|
642894
643128
|
elementCriteriaUsed.push(checkType.type);
|
|
642895
643129
|
} else {
|
|
642896
|
-
|
|
643130
|
+
const isTextCriterion = checkType.type === "elementText" || checkType.type === "elementAria";
|
|
643131
|
+
const matched = isTextCriterion ? matchesText(actualValue, checkType.value) : matchesPattern(actualValue, checkType.value);
|
|
643132
|
+
if (!actualValue || !matched) {
|
|
642897
643133
|
allChecksPassed = false;
|
|
642898
643134
|
break;
|
|
642899
643135
|
}
|
|
@@ -643777,6 +644013,7 @@ function containsOperators(expression, allowOperators = false) {
|
|
|
643777
644013
|
}
|
|
643778
644014
|
return false;
|
|
643779
644015
|
}
|
|
644016
|
+
var compiledEvaluatorCache = /* @__PURE__ */ new Map();
|
|
643780
644017
|
async function evaluateExpression(expression, context) {
|
|
643781
644018
|
try {
|
|
643782
644019
|
expression = preprocessExpression(expression);
|
|
@@ -643850,7 +644087,13 @@ async function evaluateExpression(expression, context) {
|
|
|
643850
644087
|
}
|
|
643851
644088
|
})
|
|
643852
644089
|
};
|
|
643853
|
-
const
|
|
644090
|
+
const argNames = Object.keys(evalContext);
|
|
644091
|
+
const cacheKey = `${argNames.join(",")}\0${expression}`;
|
|
644092
|
+
let evaluator = compiledEvaluatorCache.get(cacheKey);
|
|
644093
|
+
if (!evaluator) {
|
|
644094
|
+
evaluator = new Function(...argNames, `return ${expression};`);
|
|
644095
|
+
compiledEvaluatorCache.set(cacheKey, evaluator);
|
|
644096
|
+
}
|
|
643854
644097
|
return evaluator(...Object.values(evalContext));
|
|
643855
644098
|
} catch (error) {
|
|
643856
644099
|
log(`Error evaluating expression '${expression}': ${error.message}`, "error");
|
|
@@ -648672,6 +648915,10 @@ function mobileBrowserConfigError(browser) {
|
|
|
648672
648915
|
}
|
|
648673
648916
|
return null;
|
|
648674
648917
|
}
|
|
648918
|
+
var CHROMEDRIVER_AUTODOWNLOAD_ARGS = [
|
|
648919
|
+
"--allow-insecure",
|
|
648920
|
+
"uiautomator2:chromedriver_autodownload"
|
|
648921
|
+
];
|
|
648675
648922
|
function mobileBrowserGate({ platform, browser, hasBrowserStep, hasAppStep }) {
|
|
648676
648923
|
if (!hasBrowserStep)
|
|
648677
648924
|
return { action: "proceed", browserName: null };
|
|
@@ -648732,6 +648979,216 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout, loc
|
|
|
648732
648979
|
return capabilities;
|
|
648733
648980
|
}
|
|
648734
648981
|
|
|
648982
|
+
// dist/core/warmPhase.js
|
|
648983
|
+
init_utils();
|
|
648984
|
+
var WARM_POOL_LIMIT = 4;
|
|
648985
|
+
var RUNTIME_INSTALL_RESOURCE = "runtime-install";
|
|
648986
|
+
function deviceIdentity(platform, desc) {
|
|
648987
|
+
if (desc?.name)
|
|
648988
|
+
return `${platform}:name:${desc.name}`;
|
|
648989
|
+
return `${platform}:default:${desc?.deviceType ?? "<any>"}:${desc?.osVersion ?? "<latest>"}`;
|
|
648990
|
+
}
|
|
648991
|
+
function deviceResourceTag(platform, desc) {
|
|
648992
|
+
return `warm-device:${deviceIdentity(platform, desc)}`;
|
|
648993
|
+
}
|
|
648994
|
+
function wrapInitiationEffects(deps, keys, signal) {
|
|
648995
|
+
const wrapped = { ...deps };
|
|
648996
|
+
for (const key of keys) {
|
|
648997
|
+
const original = deps[key];
|
|
648998
|
+
if (typeof original !== "function")
|
|
648999
|
+
continue;
|
|
649000
|
+
wrapped[key] = (...args) => {
|
|
649001
|
+
const result = original(...args);
|
|
649002
|
+
signal();
|
|
649003
|
+
return result;
|
|
649004
|
+
};
|
|
649005
|
+
}
|
|
649006
|
+
return wrapped;
|
|
649007
|
+
}
|
|
649008
|
+
function planWarmTasks({ sizingJobs, runnerDetails, limit, hasAppiumPool, deps }) {
|
|
649009
|
+
const hostPlatform = runnerDetails?.environment?.platform;
|
|
649010
|
+
const tasks = [];
|
|
649011
|
+
const seen = /* @__PURE__ */ new Set();
|
|
649012
|
+
const addTask = (task) => {
|
|
649013
|
+
if (seen.has(task.name))
|
|
649014
|
+
return;
|
|
649015
|
+
seen.add(task.name);
|
|
649016
|
+
tasks.push(task);
|
|
649017
|
+
};
|
|
649018
|
+
let probeEligible = false;
|
|
649019
|
+
let defaultBrowser;
|
|
649020
|
+
const getDefaultBrowser2 = () => defaultBrowser ??= deps.getDefaultBrowser({ runnerDetails });
|
|
649021
|
+
const bootPlannedFor = /* @__PURE__ */ new Set();
|
|
649022
|
+
for (const job of sizingJobs ?? []) {
|
|
649023
|
+
const context = job?.context;
|
|
649024
|
+
if (!context)
|
|
649025
|
+
continue;
|
|
649026
|
+
if (deps.contextRequirementsSkipMessage({ context }))
|
|
649027
|
+
continue;
|
|
649028
|
+
const effPlatform = context.platform || hostPlatform;
|
|
649029
|
+
const mobileTarget = deps.isMobileTargetPlatform(effPlatform);
|
|
649030
|
+
if (mobileTarget) {
|
|
649031
|
+
if (mobileTarget === "ios" && hostPlatform !== "mac")
|
|
649032
|
+
continue;
|
|
649033
|
+
const hasAppStep = deps.isAppDriverRequired({ test: context });
|
|
649034
|
+
const gate = deps.mobileBrowserGate({
|
|
649035
|
+
platform: mobileTarget,
|
|
649036
|
+
browser: context.browser,
|
|
649037
|
+
hasBrowserStep: deps.isBrowserRequired({ test: context }),
|
|
649038
|
+
hasAppStep
|
|
649039
|
+
});
|
|
649040
|
+
if (gate.action !== "proceed")
|
|
649041
|
+
continue;
|
|
649042
|
+
const isMobileWeb = typeof gate.browserName === "string";
|
|
649043
|
+
if (!isMobileWeb && !hasAppStep)
|
|
649044
|
+
continue;
|
|
649045
|
+
const driverPackage = deps.appDriverPlatforms[mobileTarget]?.driverPackage;
|
|
649046
|
+
if (driverPackage) {
|
|
649047
|
+
addTask({
|
|
649048
|
+
name: `driver-install:${driverPackage}`,
|
|
649049
|
+
kind: "driver-install",
|
|
649050
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
649051
|
+
payload: { driverPackage, platform: mobileTarget }
|
|
649052
|
+
});
|
|
649053
|
+
}
|
|
649054
|
+
for (const stepDevice of deps.collectDeviceDescriptors(context)) {
|
|
649055
|
+
const desc = deps.normalizeDeviceDescriptor({
|
|
649056
|
+
contextDevice: context.device,
|
|
649057
|
+
stepDevice,
|
|
649058
|
+
platform: mobileTarget
|
|
649059
|
+
});
|
|
649060
|
+
const identity = deviceIdentity(mobileTarget, desc);
|
|
649061
|
+
const tag = deviceResourceTag(mobileTarget, desc);
|
|
649062
|
+
if (!bootPlannedFor.has(mobileTarget)) {
|
|
649063
|
+
bootPlannedFor.add(mobileTarget);
|
|
649064
|
+
addTask({
|
|
649065
|
+
name: `device-boot:${identity}`,
|
|
649066
|
+
kind: "device-boot",
|
|
649067
|
+
exclusiveResources: [tag],
|
|
649068
|
+
payload: { platform: mobileTarget, desc }
|
|
649069
|
+
});
|
|
649070
|
+
}
|
|
649071
|
+
if (mobileTarget === "android" && isMobileWeb) {
|
|
649072
|
+
addTask({
|
|
649073
|
+
name: `chromedriver-prefetch:${identity}`,
|
|
649074
|
+
kind: "chromedriver-prefetch",
|
|
649075
|
+
exclusiveResources: [tag],
|
|
649076
|
+
payload: { platform: mobileTarget, desc }
|
|
649077
|
+
});
|
|
649078
|
+
}
|
|
649079
|
+
}
|
|
649080
|
+
if (mobileTarget === "ios") {
|
|
649081
|
+
addTask({
|
|
649082
|
+
name: "wda-check",
|
|
649083
|
+
kind: "wda-check",
|
|
649084
|
+
// Read-only (plus the last-used stamp) — contends with nothing.
|
|
649085
|
+
exclusiveResources: [],
|
|
649086
|
+
payload: {}
|
|
649087
|
+
});
|
|
649088
|
+
}
|
|
649089
|
+
continue;
|
|
649090
|
+
}
|
|
649091
|
+
if (deps.isBrowserRequired({ test: context })) {
|
|
649092
|
+
const effBrowser = context.browser ?? getDefaultBrowser2();
|
|
649093
|
+
const browserName = effBrowser?.name;
|
|
649094
|
+
if (browserName && effPlatform === hostPlatform) {
|
|
649095
|
+
probeEligible = true;
|
|
649096
|
+
if (deps.requiredBrowserAssets(browserName).length > 0) {
|
|
649097
|
+
addTask({
|
|
649098
|
+
name: `browser-install:${browserName.toLowerCase()}`,
|
|
649099
|
+
kind: "browser-install",
|
|
649100
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
649101
|
+
payload: { browserName }
|
|
649102
|
+
});
|
|
649103
|
+
}
|
|
649104
|
+
}
|
|
649105
|
+
}
|
|
649106
|
+
if ((effPlatform === "windows" || effPlatform === "mac") && effPlatform === hostPlatform && deps.isAppDriverRequired({ test: context })) {
|
|
649107
|
+
const driverPackage = deps.appDriverPlatforms[effPlatform]?.driverPackage;
|
|
649108
|
+
if (driverPackage) {
|
|
649109
|
+
addTask({
|
|
649110
|
+
name: `driver-install:${driverPackage}`,
|
|
649111
|
+
kind: "driver-install",
|
|
649112
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
649113
|
+
payload: { driverPackage, platform: effPlatform }
|
|
649114
|
+
});
|
|
649115
|
+
}
|
|
649116
|
+
}
|
|
649117
|
+
}
|
|
649118
|
+
if (limit > 1 && hasAppiumPool && probeEligible) {
|
|
649119
|
+
addTask({
|
|
649120
|
+
name: "session-probe",
|
|
649121
|
+
kind: "session-probe",
|
|
649122
|
+
// Its install half mutates the shared caches, exactly like the
|
|
649123
|
+
// dedicated install tasks (usually a memo hit by the time it runs).
|
|
649124
|
+
exclusiveResources: [RUNTIME_INSTALL_RESOURCE],
|
|
649125
|
+
payload: {}
|
|
649126
|
+
});
|
|
649127
|
+
}
|
|
649128
|
+
return tasks;
|
|
649129
|
+
}
|
|
649130
|
+
async function executeWarmTasks({ tasks, registry, runTask, log: log3, now = Date.now }) {
|
|
649131
|
+
const results = [];
|
|
649132
|
+
const start = now();
|
|
649133
|
+
await runResourceAware(tasks, WARM_POOL_LIMIT, registry, async (task) => {
|
|
649134
|
+
const taskStart = now();
|
|
649135
|
+
try {
|
|
649136
|
+
const { outcome, note } = await runTask(task);
|
|
649137
|
+
results.push({
|
|
649138
|
+
name: task.name,
|
|
649139
|
+
kind: task.kind,
|
|
649140
|
+
outcome,
|
|
649141
|
+
durationMs: now() - taskStart,
|
|
649142
|
+
...note ? { note } : {}
|
|
649143
|
+
});
|
|
649144
|
+
if (outcome === "failed") {
|
|
649145
|
+
log3("warning", `Warm task '${task.name}' failed (continuing)${note ? `: ${note}` : "."}`);
|
|
649146
|
+
} else {
|
|
649147
|
+
log3("debug", `Warm task '${task.name}': ${outcome}${note ? ` (${note})` : ""}.`);
|
|
649148
|
+
}
|
|
649149
|
+
} catch (error) {
|
|
649150
|
+
const note = error?.message ?? String(error);
|
|
649151
|
+
results.push({
|
|
649152
|
+
name: task.name,
|
|
649153
|
+
kind: task.kind,
|
|
649154
|
+
outcome: "failed",
|
|
649155
|
+
durationMs: now() - taskStart,
|
|
649156
|
+
note
|
|
649157
|
+
});
|
|
649158
|
+
log3("warning", `Warm task '${task.name}' failed (continuing): ${note}`);
|
|
649159
|
+
}
|
|
649160
|
+
});
|
|
649161
|
+
return { durationMs: now() - start, tasks: results };
|
|
649162
|
+
}
|
|
649163
|
+
function raceBootInitiation({ startAcquire, onError }) {
|
|
649164
|
+
let initiatedResolve;
|
|
649165
|
+
const initiated = new Promise((resolve) => {
|
|
649166
|
+
initiatedResolve = resolve;
|
|
649167
|
+
});
|
|
649168
|
+
const acquired = (async () => {
|
|
649169
|
+
try {
|
|
649170
|
+
const result = await startAcquire(() => initiatedResolve());
|
|
649171
|
+
if (result && typeof result === "object" && "skip" in result) {
|
|
649172
|
+
return { outcome: "skipped", note: result.skip };
|
|
649173
|
+
}
|
|
649174
|
+
return { outcome: "warmed", note: "device ready" };
|
|
649175
|
+
} catch (error) {
|
|
649176
|
+
onError(error);
|
|
649177
|
+
return {
|
|
649178
|
+
outcome: "failed",
|
|
649179
|
+
note: error?.message ?? String(error)
|
|
649180
|
+
};
|
|
649181
|
+
}
|
|
649182
|
+
})();
|
|
649183
|
+
return Promise.race([
|
|
649184
|
+
initiated.then(() => ({
|
|
649185
|
+
outcome: "warmed",
|
|
649186
|
+
note: "boot initiated"
|
|
649187
|
+
})),
|
|
649188
|
+
acquired
|
|
649189
|
+
]);
|
|
649190
|
+
}
|
|
649191
|
+
|
|
648735
649192
|
// dist/core/tests.js
|
|
648736
649193
|
init_cacheDir();
|
|
648737
649194
|
|
|
@@ -649001,6 +649458,13 @@ async function teardownSimulatorRegistry(registry, shutdown) {
|
|
|
649001
649458
|
for (const entry of registry.values()) {
|
|
649002
649459
|
if (!entry.bootedByUs)
|
|
649003
649460
|
continue;
|
|
649461
|
+
if (entry.ready) {
|
|
649462
|
+
try {
|
|
649463
|
+
await entry.ready;
|
|
649464
|
+
} catch {
|
|
649465
|
+
continue;
|
|
649466
|
+
}
|
|
649467
|
+
}
|
|
649004
649468
|
try {
|
|
649005
649469
|
await shutdown(entry);
|
|
649006
649470
|
} catch {
|
|
@@ -649537,6 +650001,20 @@ function combinationKey(context) {
|
|
|
649537
650001
|
function warmUpDecision(prev) {
|
|
649538
650002
|
return prev === "failed" ? "skip" : "attempt";
|
|
649539
650003
|
}
|
|
650004
|
+
function buildWarmPlanDeps() {
|
|
650005
|
+
return {
|
|
650006
|
+
isBrowserRequired,
|
|
650007
|
+
isAppDriverRequired,
|
|
650008
|
+
isMobileTargetPlatform,
|
|
650009
|
+
getDefaultBrowser,
|
|
650010
|
+
requiredBrowserAssets,
|
|
650011
|
+
collectDeviceDescriptors,
|
|
650012
|
+
normalizeDeviceDescriptor,
|
|
650013
|
+
mobileBrowserGate,
|
|
650014
|
+
contextRequirementsSkipMessage,
|
|
650015
|
+
appDriverPlatforms: APP_DRIVER_PLATFORMS
|
|
650016
|
+
};
|
|
650017
|
+
}
|
|
649540
650018
|
function getDriverCapabilities({ runnerDetails, name, options }) {
|
|
649541
650019
|
let capabilities = {};
|
|
649542
650020
|
let args = [];
|
|
@@ -650146,7 +650624,12 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650146
650624
|
skipped: 0
|
|
650147
650625
|
}
|
|
650148
650626
|
},
|
|
650149
|
-
specs: []
|
|
650627
|
+
specs: [],
|
|
650628
|
+
// Inline warm phase results (docs/design/warm-phase.md). Present on the
|
|
650629
|
+
// skeleton so a run that plans nothing (or whose planning fails —
|
|
650630
|
+
// best-effort) still reports the structural empty block; the phase
|
|
650631
|
+
// overwrites it with real task results below.
|
|
650632
|
+
warm: { durationMs: 0, tasks: [] }
|
|
650150
650633
|
};
|
|
650151
650634
|
let limit = resolveConcurrentRunners(config);
|
|
650152
650635
|
log(config, "info", "Running test specs.");
|
|
@@ -650301,6 +650784,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650301
650784
|
const serverCount = Math.min(limit, browserPoolJobCount);
|
|
650302
650785
|
log(config, "debug", `Starting ${serverCount} Appium server(s).`);
|
|
650303
650786
|
try {
|
|
650787
|
+
const readinessWaits = [];
|
|
650304
650788
|
for (let i = 0; i < serverCount; i++) {
|
|
650305
650789
|
let display;
|
|
650306
650790
|
if (useXvfbDisplays) {
|
|
@@ -650308,7 +650792,16 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650308
650792
|
xvfbProcesses.push(await startXvfb(display));
|
|
650309
650793
|
log(config, "debug", `Started Xvfb on ${display} for recording.`);
|
|
650310
650794
|
}
|
|
650311
|
-
|
|
650795
|
+
const server = await spawnAppiumServer(appiumEntry, config, display);
|
|
650796
|
+
appiumServers.push(server);
|
|
650797
|
+
const wait2 = appiumIsReady(server.port);
|
|
650798
|
+
wait2.catch(() => {
|
|
650799
|
+
});
|
|
650800
|
+
readinessWaits.push(wait2);
|
|
650801
|
+
}
|
|
650802
|
+
await Promise.all(readinessWaits);
|
|
650803
|
+
for (const server of appiumServers) {
|
|
650804
|
+
log(config, "debug", `Appium is ready on port ${server.port}.`);
|
|
650312
650805
|
}
|
|
650313
650806
|
} catch (error) {
|
|
650314
650807
|
await Promise.all(appiumServers.map((server) => {
|
|
@@ -650331,6 +650824,7 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650331
650824
|
const processRegistry = /* @__PURE__ */ new Map();
|
|
650332
650825
|
const deviceRegistry = createDeviceRegistry();
|
|
650333
650826
|
const simulatorRegistry = createSimulatorRegistry();
|
|
650827
|
+
const resourceRegistry = createResourceRegistry();
|
|
650334
650828
|
const killAllRegistered = async () => {
|
|
650335
650829
|
const entries = [...processRegistry.entries()];
|
|
650336
650830
|
processRegistry.clear();
|
|
@@ -650367,15 +650861,35 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650367
650861
|
process.on("SIGINT", onSignal);
|
|
650368
650862
|
process.on("SIGTERM", onSignal);
|
|
650369
650863
|
try {
|
|
650370
|
-
|
|
650371
|
-
|
|
650372
|
-
|
|
650373
|
-
config,
|
|
650864
|
+
try {
|
|
650865
|
+
const warmTasks = planWarmTasks({
|
|
650866
|
+
sizingJobs,
|
|
650374
650867
|
runnerDetails,
|
|
650375
|
-
|
|
650376
|
-
|
|
650377
|
-
|
|
650868
|
+
limit,
|
|
650869
|
+
hasAppiumPool: !!appiumPool,
|
|
650870
|
+
deps: buildWarmPlanDeps()
|
|
650378
650871
|
});
|
|
650872
|
+
if (warmTasks.length > 0) {
|
|
650873
|
+
log(config, "debug", `Warm phase: ${warmTasks.length} task(s).`);
|
|
650874
|
+
report.warm = await executeWarmTasks({
|
|
650875
|
+
tasks: warmTasks,
|
|
650876
|
+
registry: resourceRegistry,
|
|
650877
|
+
runTask: buildWarmTaskRunner({
|
|
650878
|
+
config,
|
|
650879
|
+
runnerDetails,
|
|
650880
|
+
sizingJobs,
|
|
650881
|
+
appiumPool,
|
|
650882
|
+
installAttempts,
|
|
650883
|
+
warmUpResults,
|
|
650884
|
+
deviceRegistry,
|
|
650885
|
+
simulatorRegistry,
|
|
650886
|
+
resourceRegistry
|
|
650887
|
+
}),
|
|
650888
|
+
log: (level, message) => log(config, level, message)
|
|
650889
|
+
});
|
|
650890
|
+
}
|
|
650891
|
+
} catch (error) {
|
|
650892
|
+
log(config, "warning", `Warm phase skipped (planning failed; the run proceeds with on-demand provisioning): ${error?.message ?? error}`);
|
|
650379
650893
|
}
|
|
650380
650894
|
const runJob = async (job) => {
|
|
650381
650895
|
try {
|
|
@@ -650427,7 +650941,6 @@ async function runSpecs({ resolvedTests }) {
|
|
|
650427
650941
|
const phase = PHASES.includes(entry.spec?._phase) ? entry.spec._phase : "main";
|
|
650428
650942
|
routedByPhase[phase].push(entry);
|
|
650429
650943
|
}
|
|
650430
|
-
const resourceRegistry = createResourceRegistry();
|
|
650431
650944
|
for (const phase of PHASES) {
|
|
650432
650945
|
if (limit > 1) {
|
|
650433
650946
|
await runResourceAware(jobsByPhase[phase], limit, resourceRegistry, runJob);
|
|
@@ -650741,27 +651254,17 @@ async function warmUpContexts({ jobs, config, runnerDetails, appiumPool, install
|
|
|
650741
651254
|
platform
|
|
650742
651255
|
});
|
|
650743
651256
|
if (!supported && context.platform === platform && Array.isArray(context?.steps) && requiredBrowserAssets(context.browser?.name).length > 0) {
|
|
650744
|
-
|
|
650745
|
-
const outcome = await ensureContextBrowserInstalled({
|
|
651257
|
+
await warmBrowserInstall({
|
|
650746
651258
|
browserName: context.browser?.name,
|
|
650747
651259
|
config,
|
|
650748
|
-
|
|
650749
|
-
|
|
650750
|
-
|
|
650751
|
-
|
|
650752
|
-
|
|
650753
|
-
|
|
650754
|
-
|
|
651260
|
+
runnerDetails,
|
|
651261
|
+
installAttempts
|
|
651262
|
+
});
|
|
651263
|
+
supported = isSupportedContext({
|
|
651264
|
+
context,
|
|
651265
|
+
apps: runnerDetails.availableApps,
|
|
651266
|
+
platform
|
|
650755
651267
|
});
|
|
650756
|
-
if (firstAttempt && (outcome === "installed" || outcome === "failed")) {
|
|
650757
|
-
clearAppCache(config);
|
|
650758
|
-
runnerDetails.availableApps = await getAvailableApps({ config });
|
|
650759
|
-
supported = isSupportedContext({
|
|
650760
|
-
context,
|
|
650761
|
-
apps: runnerDetails.availableApps,
|
|
650762
|
-
platform
|
|
650763
|
-
});
|
|
650764
|
-
}
|
|
650765
651268
|
}
|
|
650766
651269
|
if (!supported)
|
|
650767
651270
|
continue;
|
|
@@ -650803,6 +651306,292 @@ async function warmUpContexts({ jobs, config, runnerDetails, appiumPool, install
|
|
|
650803
651306
|
}
|
|
650804
651307
|
}
|
|
650805
651308
|
}
|
|
651309
|
+
async function warmBrowserInstall({ browserName, config, runnerDetails, installAttempts, deps = {} }) {
|
|
651310
|
+
const appName = normalizeBrowserName(browserName);
|
|
651311
|
+
if (runnerDetails.availableApps?.find((app) => app.name === appName)) {
|
|
651312
|
+
return {
|
|
651313
|
+
outcome: "skipped",
|
|
651314
|
+
note: `'${browserName}' is already available`
|
|
651315
|
+
};
|
|
651316
|
+
}
|
|
651317
|
+
const firstAttempt = !installAttempts.has((browserName ?? "<none>").toLowerCase());
|
|
651318
|
+
const outcome = await ensureContextBrowserInstalled({
|
|
651319
|
+
browserName,
|
|
651320
|
+
config,
|
|
651321
|
+
installAttempts,
|
|
651322
|
+
deps: {
|
|
651323
|
+
ensureBrowser: deps.ensureBrowser ?? ((asset, options) => ensureBrowserInstalled(asset, options)),
|
|
651324
|
+
log
|
|
651325
|
+
},
|
|
651326
|
+
// Repair a present-but-broken driver, not just install-if-missing.
|
|
651327
|
+
repair: true
|
|
651328
|
+
});
|
|
651329
|
+
if (firstAttempt && (outcome === "installed" || outcome === "failed")) {
|
|
651330
|
+
(deps.clearAppCache ?? clearAppCache)(config);
|
|
651331
|
+
runnerDetails.availableApps = await (deps.getAvailableApps ?? getAvailableApps)({ config });
|
|
651332
|
+
}
|
|
651333
|
+
if (outcome === "installed")
|
|
651334
|
+
return { outcome: "warmed" };
|
|
651335
|
+
if (outcome === "failed") {
|
|
651336
|
+
return { outcome: "failed", note: `couldn't install '${browserName}'` };
|
|
651337
|
+
}
|
|
651338
|
+
return {
|
|
651339
|
+
outcome: "skipped",
|
|
651340
|
+
note: `'${browserName}' has no installable assets`
|
|
651341
|
+
};
|
|
651342
|
+
}
|
|
651343
|
+
async function resolveAndroidWarmEnv(config) {
|
|
651344
|
+
try {
|
|
651345
|
+
const abi = hostAbi();
|
|
651346
|
+
const sdk = detectAndroidSdk({ cacheDir: config?.cacheDir });
|
|
651347
|
+
if (!sdk?.emulator)
|
|
651348
|
+
return null;
|
|
651349
|
+
const deviceDeps = buildAcquireDeviceDeps(sdk, abi, (m) => log(config, "debug", m));
|
|
651350
|
+
const running = await deviceDeps.listRunning();
|
|
651351
|
+
const capable = running.length > 0 || await checkEmulatorAcceleration(sdk.emulator);
|
|
651352
|
+
if (!capable)
|
|
651353
|
+
return null;
|
|
651354
|
+
return { sdkRoot: sdk.sdkRoot, deviceDeps };
|
|
651355
|
+
} catch {
|
|
651356
|
+
return null;
|
|
651357
|
+
}
|
|
651358
|
+
}
|
|
651359
|
+
async function probeIosToolchainWarm() {
|
|
651360
|
+
if (process.platform !== "darwin")
|
|
651361
|
+
return probeIosToolchain();
|
|
651362
|
+
const runAsync = (command, args, timeout) => new Promise((resolve) => {
|
|
651363
|
+
let stdout = "";
|
|
651364
|
+
let stderr = "";
|
|
651365
|
+
try {
|
|
651366
|
+
const child = (0, import_node_child_process15.spawn)(command, args, { windowsHide: true, timeout });
|
|
651367
|
+
child.stdout?.on("data", (d) => stdout += String(d));
|
|
651368
|
+
child.stderr?.on("data", (d) => stderr += String(d));
|
|
651369
|
+
child.on("error", () => resolve({ status: null, stdout, stderr }));
|
|
651370
|
+
child.on("close", (status) => resolve({ status, stdout, stderr }));
|
|
651371
|
+
} catch {
|
|
651372
|
+
resolve({ status: null, stdout, stderr });
|
|
651373
|
+
}
|
|
651374
|
+
});
|
|
651375
|
+
const [xcodeSelect, simctl] = await Promise.all([
|
|
651376
|
+
runAsync("xcode-select", ["-p"], 15e3),
|
|
651377
|
+
// Same generous ceiling as the sync probe's xcrun spawn: the first cold
|
|
651378
|
+
// simctl call launches CoreSimulatorService.
|
|
651379
|
+
runAsync("xcrun", ["simctl", "list", "devices", "available"], 12e4)
|
|
651380
|
+
]);
|
|
651381
|
+
return probeIosToolchain({
|
|
651382
|
+
run: (command) => command === "xcrun" ? simctl : xcodeSelect
|
|
651383
|
+
});
|
|
651384
|
+
}
|
|
651385
|
+
function buildWarmTaskRunner({ config, runnerDetails, sizingJobs, appiumPool, installAttempts, warmUpResults, deviceRegistry, simulatorRegistry, resourceRegistry }) {
|
|
651386
|
+
let androidEnv;
|
|
651387
|
+
const getAndroidEnv = () => androidEnv ??= resolveAndroidWarmEnv(config);
|
|
651388
|
+
let iosToolchain;
|
|
651389
|
+
const getIosToolchain = () => iosToolchain ??= probeIosToolchainWarm();
|
|
651390
|
+
const acquireLease = async (names) => {
|
|
651391
|
+
while (!resourceRegistry.tryAcquire(names)) {
|
|
651392
|
+
await resourceRegistry.waitForFree();
|
|
651393
|
+
}
|
|
651394
|
+
let released = false;
|
|
651395
|
+
return () => {
|
|
651396
|
+
if (released)
|
|
651397
|
+
return;
|
|
651398
|
+
released = true;
|
|
651399
|
+
resourceRegistry.release(names);
|
|
651400
|
+
};
|
|
651401
|
+
};
|
|
651402
|
+
const withRuntimeInstallLock = async (fn) => {
|
|
651403
|
+
const release = await acquireLease([RUNTIME_INSTALL_RESOURCE]);
|
|
651404
|
+
try {
|
|
651405
|
+
return await fn();
|
|
651406
|
+
} finally {
|
|
651407
|
+
release();
|
|
651408
|
+
}
|
|
651409
|
+
};
|
|
651410
|
+
let androidPreflight;
|
|
651411
|
+
const getAndroidPreflight = () => androidPreflight ??= withRuntimeInstallLock(() => appSurfacePreflight({ config, platform: "android" }));
|
|
651412
|
+
return async (task) => {
|
|
651413
|
+
switch (task.kind) {
|
|
651414
|
+
case "browser-install":
|
|
651415
|
+
return warmBrowserInstall({
|
|
651416
|
+
browserName: task.payload.browserName,
|
|
651417
|
+
config,
|
|
651418
|
+
runnerDetails,
|
|
651419
|
+
installAttempts
|
|
651420
|
+
});
|
|
651421
|
+
case "driver-install": {
|
|
651422
|
+
if (task.payload.platform === "android") {
|
|
651423
|
+
const env = await getAndroidEnv();
|
|
651424
|
+
if (!env) {
|
|
651425
|
+
return {
|
|
651426
|
+
outcome: "skipped",
|
|
651427
|
+
note: "Android toolchain not ready; the driver install stays with the consuming context"
|
|
651428
|
+
};
|
|
651429
|
+
}
|
|
651430
|
+
}
|
|
651431
|
+
if (task.payload.platform === "ios") {
|
|
651432
|
+
const toolchain = await getIosToolchain();
|
|
651433
|
+
if (!toolchain.ok) {
|
|
651434
|
+
return { outcome: "skipped", note: toolchain.reason };
|
|
651435
|
+
}
|
|
651436
|
+
}
|
|
651437
|
+
const { ensureRuntimeInstalled: ensureRuntimeInstalled2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
|
|
651438
|
+
await ensureRuntimeInstalled2([task.payload.driverPackage], {
|
|
651439
|
+
ctx: { cacheDir: config?.cacheDir },
|
|
651440
|
+
deps: { logger: (m) => log(config, "debug", m) }
|
|
651441
|
+
});
|
|
651442
|
+
return { outcome: "warmed" };
|
|
651443
|
+
}
|
|
651444
|
+
case "device-boot": {
|
|
651445
|
+
const desc = task.payload.desc;
|
|
651446
|
+
const onError = (error) => log(config, "warning", `Warm boot of '${task.name}' failed (a consuming context will retry): ${error?.message ?? String(error)}`);
|
|
651447
|
+
if (task.payload.platform === "android") {
|
|
651448
|
+
const env = await getAndroidEnv();
|
|
651449
|
+
if (!env) {
|
|
651450
|
+
return {
|
|
651451
|
+
outcome: "skipped",
|
|
651452
|
+
note: "Android toolchain not ready; device setup stays with the consuming context"
|
|
651453
|
+
};
|
|
651454
|
+
}
|
|
651455
|
+
const releaseEmulatorLease = await acquireLease([
|
|
651456
|
+
"android-emulator"
|
|
651457
|
+
]);
|
|
651458
|
+
return raceBootInitiation({
|
|
651459
|
+
onError,
|
|
651460
|
+
startAcquire: (signalInitiated) => {
|
|
651461
|
+
const acquiring = acquireDevice({
|
|
651462
|
+
desc,
|
|
651463
|
+
registry: deviceRegistry,
|
|
651464
|
+
sdkRoot: env.sdkRoot,
|
|
651465
|
+
deps: wrapInitiationEffects(env.deviceDeps, ["createAvd", "boot"], signalInitiated)
|
|
651466
|
+
});
|
|
651467
|
+
acquiring.then(() => releaseEmulatorLease(), () => releaseEmulatorLease());
|
|
651468
|
+
return acquiring;
|
|
651469
|
+
}
|
|
651470
|
+
});
|
|
651471
|
+
}
|
|
651472
|
+
const toolchain = await getIosToolchain();
|
|
651473
|
+
if (!toolchain.ok) {
|
|
651474
|
+
return { outcome: "skipped", note: toolchain.reason };
|
|
651475
|
+
}
|
|
651476
|
+
const simDeps = buildAcquireSimulatorDeps((m) => log(config, "debug", m));
|
|
651477
|
+
return raceBootInitiation({
|
|
651478
|
+
onError,
|
|
651479
|
+
startAcquire: (signalInitiated) => acquireSimulator({
|
|
651480
|
+
desc,
|
|
651481
|
+
registry: simulatorRegistry,
|
|
651482
|
+
deps: wrapInitiationEffects(simDeps, ["create", "boot"], signalInitiated)
|
|
651483
|
+
})
|
|
651484
|
+
});
|
|
651485
|
+
}
|
|
651486
|
+
case "wda-check": {
|
|
651487
|
+
const hit = locateManagedWda({ ctx: { cacheDir: config?.cacheDir } });
|
|
651488
|
+
if (hit) {
|
|
651489
|
+
return {
|
|
651490
|
+
outcome: "warmed",
|
|
651491
|
+
note: `prebuilt WebDriverAgent available (${hit.key})`
|
|
651492
|
+
};
|
|
651493
|
+
}
|
|
651494
|
+
return {
|
|
651495
|
+
outcome: "skipped",
|
|
651496
|
+
note: "no prebuilt WebDriverAgent for the current toolchain \u2014 `doc-detective install ios` prebuilds it"
|
|
651497
|
+
};
|
|
651498
|
+
}
|
|
651499
|
+
case "session-probe": {
|
|
651500
|
+
if (!appiumPool) {
|
|
651501
|
+
return { outcome: "skipped", note: "no browser Appium pool" };
|
|
651502
|
+
}
|
|
651503
|
+
await warmUpContexts({
|
|
651504
|
+
jobs: sizingJobs,
|
|
651505
|
+
config,
|
|
651506
|
+
runnerDetails,
|
|
651507
|
+
appiumPool,
|
|
651508
|
+
installAttempts,
|
|
651509
|
+
warmUpResults
|
|
651510
|
+
});
|
|
651511
|
+
const ok = [...warmUpResults.values()].filter((v) => v === "ok").length;
|
|
651512
|
+
const failed = warmUpResults.size - ok;
|
|
651513
|
+
return {
|
|
651514
|
+
outcome: "warmed",
|
|
651515
|
+
note: `${ok} combination${ok === 1 ? "" : "s"} ok${failed ? `, ${failed} failed` : ""}`
|
|
651516
|
+
};
|
|
651517
|
+
}
|
|
651518
|
+
case "chromedriver-prefetch":
|
|
651519
|
+
return prefetchMobileChromedriver({
|
|
651520
|
+
config,
|
|
651521
|
+
desc: task.payload.desc,
|
|
651522
|
+
deviceRegistry,
|
|
651523
|
+
getAndroidEnv,
|
|
651524
|
+
deps: {
|
|
651525
|
+
// The cache-mutating half (driver install + Appium co-homing)
|
|
651526
|
+
// runs once per run under the manual runtime-install lease, so
|
|
651527
|
+
// the prefetch task itself only holds its device tag while it
|
|
651528
|
+
// awaits readiness and runs the throwaway session.
|
|
651529
|
+
appSurfacePreflight: () => getAndroidPreflight(),
|
|
651530
|
+
acquireEmulatorLease: () => acquireLease(["android-emulator"])
|
|
651531
|
+
}
|
|
651532
|
+
});
|
|
651533
|
+
}
|
|
651534
|
+
};
|
|
651535
|
+
}
|
|
651536
|
+
async function prefetchMobileChromedriver({ config, desc, deviceRegistry, getAndroidEnv, deps = {} }) {
|
|
651537
|
+
const preflight = deps.appSurfacePreflight ?? appSurfacePreflight;
|
|
651538
|
+
const acquire = deps.acquireDevice ?? acquireDevice;
|
|
651539
|
+
const startServer = deps.startAppiumServer ?? startAppiumServer;
|
|
651540
|
+
const startDriver = deps.driverStart ?? driverStart;
|
|
651541
|
+
const kill4 = deps.killTree ?? killTree;
|
|
651542
|
+
const env = await getAndroidEnv();
|
|
651543
|
+
if (!env) {
|
|
651544
|
+
return {
|
|
651545
|
+
outcome: "skipped",
|
|
651546
|
+
note: "Android toolchain not ready; the first mobile-web session downloads chromedriver as needed"
|
|
651547
|
+
};
|
|
651548
|
+
}
|
|
651549
|
+
const pre = await preflight({ config, platform: "android" });
|
|
651550
|
+
if (!pre.ok)
|
|
651551
|
+
return { outcome: "skipped", note: pre.reason };
|
|
651552
|
+
const releaseLease = deps.acquireEmulatorLease ? await deps.acquireEmulatorLease() : void 0;
|
|
651553
|
+
let acquired;
|
|
651554
|
+
try {
|
|
651555
|
+
acquired = await acquire({
|
|
651556
|
+
desc,
|
|
651557
|
+
registry: deviceRegistry,
|
|
651558
|
+
sdkRoot: env.sdkRoot,
|
|
651559
|
+
deps: env.deviceDeps
|
|
651560
|
+
});
|
|
651561
|
+
} finally {
|
|
651562
|
+
releaseLease?.();
|
|
651563
|
+
}
|
|
651564
|
+
if ("skip" in acquired)
|
|
651565
|
+
return { outcome: "skipped", note: acquired.skip };
|
|
651566
|
+
let server;
|
|
651567
|
+
let driver;
|
|
651568
|
+
try {
|
|
651569
|
+
server = await startServer(pre.appiumEntry, config, void 0, {
|
|
651570
|
+
APPIUM_HOME: pre.appiumHome,
|
|
651571
|
+
ANDROID_HOME: env.sdkRoot,
|
|
651572
|
+
ANDROID_SDK_ROOT: env.sdkRoot
|
|
651573
|
+
}, CHROMEDRIVER_AUTODOWNLOAD_ARGS);
|
|
651574
|
+
driver = await startDriver(buildMobileBrowserCapabilities({
|
|
651575
|
+
platform: "android",
|
|
651576
|
+
udid: acquired.entry.udid,
|
|
651577
|
+
cacheDir: getCacheDir({ cacheDir: config?.cacheDir })
|
|
651578
|
+
}), server.port, 2, { cacheDir: config?.cacheDir });
|
|
651579
|
+
return {
|
|
651580
|
+
outcome: "warmed",
|
|
651581
|
+
note: `chromedriver ready for device '${acquired.entry.name}'`
|
|
651582
|
+
};
|
|
651583
|
+
} finally {
|
|
651584
|
+
if (driver) {
|
|
651585
|
+
try {
|
|
651586
|
+
await driver.deleteSession();
|
|
651587
|
+
} catch {
|
|
651588
|
+
}
|
|
651589
|
+
}
|
|
651590
|
+
if (server) {
|
|
651591
|
+
await kill4(server.process?.pid);
|
|
651592
|
+
}
|
|
651593
|
+
}
|
|
651594
|
+
}
|
|
650806
651595
|
function specIsRouted(spec) {
|
|
650807
651596
|
if (!spec || !Array.isArray(spec.tests))
|
|
650808
651597
|
return false;
|
|
@@ -651150,7 +651939,8 @@ async function runContext({ config, spec, test, context, runnerDetails, appiumPo
|
|
|
651150
651939
|
contextReport.resultDescription = errorMessage;
|
|
651151
651940
|
return contextReport;
|
|
651152
651941
|
}
|
|
651153
|
-
|
|
651942
|
+
if (logLevelEnabled(config, "debug"))
|
|
651943
|
+
clog("debug", `CONTEXT:
|
|
651154
651944
|
${JSON.stringify(context, null, 2)}`);
|
|
651155
651945
|
let driver;
|
|
651156
651946
|
let appiumPort;
|
|
@@ -651169,7 +651959,7 @@ ${JSON.stringify(context, null, 2)}`);
|
|
|
651169
651959
|
env.ANDROID_HOME = appSession.androidSdkRoot;
|
|
651170
651960
|
env.ANDROID_SDK_ROOT = appSession.androidSdkRoot;
|
|
651171
651961
|
}
|
|
651172
|
-
const extraArgs = mobileTarget === "android" ?
|
|
651962
|
+
const extraArgs = mobileTarget === "android" ? CHROMEDRIVER_AUTODOWNLOAD_ARGS : [];
|
|
651173
651963
|
let acquired;
|
|
651174
651964
|
try {
|
|
651175
651965
|
const server = await startAppiumServer(appSession.appiumEntry, config, void 0, env, extraArgs);
|
|
@@ -651462,7 +652252,8 @@ ${JSON.stringify(context, null, 2)}`);
|
|
|
651462
652252
|
stepExecutionFailed = true;
|
|
651463
652253
|
break;
|
|
651464
652254
|
}
|
|
651465
|
-
|
|
652255
|
+
if (logLevelEnabled(config, "debug"))
|
|
652256
|
+
clog("debug", `STEP:
|
|
651466
652257
|
${JSON.stringify(step, null, 2)}`);
|
|
651467
652258
|
if (step.unsafe && runnerDetails.allowUnsafeSteps === false) {
|
|
651468
652259
|
clog("warning", `Skipping unsafe step: ${step.description} in test ${test.testId} context ${context.contextId}`);
|
|
@@ -651528,7 +652319,8 @@ ${JSON.stringify(step, null, 2)}`);
|
|
|
651528
652319
|
processRegistry,
|
|
651529
652320
|
appSession
|
|
651530
652321
|
});
|
|
651531
|
-
|
|
652322
|
+
if (logLevelEnabled(config, "debug"))
|
|
652323
|
+
clog("debug", `RESULT: ${r.status}
|
|
651532
652324
|
${JSON.stringify(r, null, 2)}`);
|
|
651533
652325
|
r.result = r.status;
|
|
651534
652326
|
r.resultDescription = r.description;
|
|
@@ -651925,7 +652717,7 @@ async function runStep({ config = {}, context = {}, step, driver, metaValues = {
|
|
|
651925
652717
|
}
|
|
651926
652718
|
return actionResult;
|
|
651927
652719
|
}
|
|
651928
|
-
async function
|
|
652720
|
+
async function spawnAppiumServer(appiumEntry, config, display, extraEnv, extraArgs) {
|
|
651929
652721
|
const port = await findFreePort();
|
|
651930
652722
|
log(config, "debug", `Starting Appium on port ${port}`);
|
|
651931
652723
|
const env = display || extraEnv ? {
|
|
@@ -651945,31 +652737,41 @@ async function startAppiumServer(appiumEntry, config, display, extraEnv, extraAr
|
|
|
651945
652737
|
});
|
|
651946
652738
|
proc.stderr.on("data", () => {
|
|
651947
652739
|
});
|
|
652740
|
+
return { port, process: proc, display };
|
|
652741
|
+
}
|
|
652742
|
+
async function startAppiumServer(appiumEntry, config, display, extraEnv, extraArgs) {
|
|
652743
|
+
const server = await spawnAppiumServer(appiumEntry, config, display, extraEnv, extraArgs);
|
|
651948
652744
|
try {
|
|
651949
|
-
await appiumIsReady(port);
|
|
652745
|
+
await appiumIsReady(server.port);
|
|
651950
652746
|
} catch (error) {
|
|
651951
|
-
await killTree(
|
|
652747
|
+
await killTree(server.process?.pid);
|
|
651952
652748
|
throw error;
|
|
651953
652749
|
}
|
|
651954
|
-
log(config, "debug", `Appium is ready on port ${port}.`);
|
|
651955
|
-
return
|
|
652750
|
+
log(config, "debug", `Appium is ready on port ${server.port}.`);
|
|
652751
|
+
return server;
|
|
651956
652752
|
}
|
|
651957
|
-
|
|
651958
|
-
|
|
652753
|
+
var STATUS_PROBE_TIMEOUT_MS = 1e4;
|
|
652754
|
+
async function appiumIsReady(port, timeoutMs = 12e4, deps = {}) {
|
|
652755
|
+
const probe = deps.probe ?? (async (p) => {
|
|
652756
|
+
try {
|
|
652757
|
+
const resp = await import_axios6.default.get(`http://127.0.0.1:${p}/status`, {
|
|
652758
|
+
timeout: STATUS_PROBE_TIMEOUT_MS
|
|
652759
|
+
});
|
|
652760
|
+
return resp.status === 200;
|
|
652761
|
+
} catch {
|
|
652762
|
+
return false;
|
|
652763
|
+
}
|
|
652764
|
+
});
|
|
652765
|
+
const sleep4 = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
651959
652766
|
const start = Date.now();
|
|
651960
|
-
while (
|
|
652767
|
+
while (true) {
|
|
652768
|
+
if (await probe(port))
|
|
652769
|
+
return true;
|
|
651961
652770
|
if (Date.now() - start > timeoutMs) {
|
|
651962
652771
|
throw new Error(`Appium server on port ${port} failed to start within ${timeoutMs / 1e3} seconds`);
|
|
651963
652772
|
}
|
|
651964
|
-
await
|
|
651965
|
-
try {
|
|
651966
|
-
let resp = await import_axios6.default.get(`http://127.0.0.1:${port}/status`);
|
|
651967
|
-
if (resp.status === 200)
|
|
651968
|
-
isReady = true;
|
|
651969
|
-
} catch {
|
|
651970
|
-
}
|
|
652773
|
+
await sleep4(250);
|
|
651971
652774
|
}
|
|
651972
|
-
return isReady;
|
|
651973
652775
|
}
|
|
651974
652776
|
async function driverStart(capabilities, port, maxAttempts = 4, ctx = {}) {
|
|
651975
652777
|
const wdio = await loadHeavyDep("webdriverio", { ctx });
|
|
@@ -652159,6 +652961,8 @@ function telemetryNotice(config) {
|
|
|
652159
652961
|
log(config, "info", "Doc Detective collects basic anonymous telemetry to understand product issues and usage. To disable telemetry, set 'telemetry.send' to 'false' in your .doc-detective.json config file.");
|
|
652160
652962
|
}
|
|
652161
652963
|
}
|
|
652964
|
+
var TELEMETRY_FLUSH_TIMEOUT_MS = 2e3;
|
|
652965
|
+
var pendingTelemetryFlush = null;
|
|
652162
652966
|
function sendTelemetry(config, command, results) {
|
|
652163
652967
|
if (config?.telemetry?.send === false)
|
|
652164
652968
|
return;
|
|
@@ -652199,7 +653003,7 @@ function sendTelemetry(config, command, results) {
|
|
|
652199
653003
|
const event = { distinctId, event: command, properties: telemetryData };
|
|
652200
653004
|
const client = new import_posthog_node.PostHog("phc_rjV0MH3nsAd45zFISLgaKAdAXbgDeXt2mOBV2EBHomB", { host: "https://app.posthog.com" });
|
|
652201
653005
|
client.capture(event);
|
|
652202
|
-
client.shutdown();
|
|
653006
|
+
pendingTelemetryFlush = Promise.resolve(client.shutdown(TELEMETRY_FLUSH_TIMEOUT_MS)).then(() => void 0).catch(() => void 0);
|
|
652203
653007
|
}
|
|
652204
653008
|
|
|
652205
653009
|
// dist/core/index.js
|
|
@@ -652243,6 +653047,9 @@ async function runTests(config, options = {}) {
|
|
|
652243
653047
|
return null;
|
|
652244
653048
|
}
|
|
652245
653049
|
}
|
|
653050
|
+
if (typeof options.updateJoin === "function") {
|
|
653051
|
+
await options.updateJoin();
|
|
653052
|
+
}
|
|
652246
653053
|
if (config.dryRun) {
|
|
652247
653054
|
console.log(JSON.stringify(resolvedTests, null, 2));
|
|
652248
653055
|
cleanTemp();
|
|
@@ -652274,23 +653081,43 @@ async function runTests(config, options = {}) {
|
|
|
652274
653081
|
}
|
|
652275
653082
|
if (needs.browsers.size > 0) {
|
|
652276
653083
|
try {
|
|
652277
|
-
const { getAvailableApps: getAvailableApps2,
|
|
653084
|
+
const { getAvailableApps: getAvailableApps2, patchAppCache: patchAppCache2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
652278
653085
|
const { ensureBrowserInstalled: ensureBrowserInstalled2, requiredBrowserAssets: requiredBrowserAssets2 } = await Promise.resolve().then(() => (init_browsers(), browsers_exports));
|
|
652279
653086
|
const available = await getAvailableApps2({ config });
|
|
652280
653087
|
const availableNames = new Set(available.map((a) => a.name));
|
|
652281
|
-
|
|
653088
|
+
const installedDescriptors = [];
|
|
652282
653089
|
for (const browser of needs.browsers) {
|
|
652283
653090
|
if (availableNames.has(browser))
|
|
652284
653091
|
continue;
|
|
652285
653092
|
const assets = requiredBrowserAssets2(browser);
|
|
653093
|
+
const assetResults = {};
|
|
652286
653094
|
for (const asset of assets) {
|
|
652287
|
-
await ensureBrowserInstalled2(asset, {
|
|
653095
|
+
assetResults[asset] = await ensureBrowserInstalled2(asset, {
|
|
653096
|
+
ctx,
|
|
653097
|
+
deps: { logger: preflightLogger }
|
|
653098
|
+
});
|
|
653099
|
+
}
|
|
653100
|
+
if (assets.length === 0)
|
|
653101
|
+
continue;
|
|
653102
|
+
if (browser === "chrome") {
|
|
653103
|
+
installedDescriptors.push({
|
|
653104
|
+
name: "chrome",
|
|
653105
|
+
version: assetResults.chrome?.version,
|
|
653106
|
+
path: assetResults.chrome?.path,
|
|
653107
|
+
driverPath: assetResults.chromedriver?.path
|
|
653108
|
+
});
|
|
653109
|
+
} else if (browser === "firefox") {
|
|
653110
|
+
installedDescriptors.push({
|
|
653111
|
+
name: "firefox",
|
|
653112
|
+
version: assetResults.firefox?.version,
|
|
653113
|
+
path: assetResults.firefox?.path,
|
|
653114
|
+
driverPath: assetResults.geckodriver?.path
|
|
653115
|
+
});
|
|
652288
653116
|
}
|
|
652289
|
-
if (assets.length > 0)
|
|
652290
|
-
installedAnything = true;
|
|
652291
653117
|
}
|
|
652292
|
-
if (
|
|
652293
|
-
|
|
653118
|
+
if (installedDescriptors.length > 0) {
|
|
653119
|
+
await patchAppCache2(config, installedDescriptors);
|
|
653120
|
+
}
|
|
652294
653121
|
} catch (browserErr) {
|
|
652295
653122
|
log(config, "debug", `Browser pre-flight check skipped: ${browserErr?.message ?? browserErr}`);
|
|
652296
653123
|
}
|
|
@@ -652317,8 +653144,8 @@ async function runTests(config, options = {}) {
|
|
|
652317
653144
|
} else {
|
|
652318
653145
|
results = await runSpecs({ resolvedTests });
|
|
652319
653146
|
}
|
|
652320
|
-
log(config, "
|
|
652321
|
-
log(config, "
|
|
653147
|
+
log(config, "debug", "RESULTS:");
|
|
653148
|
+
log(config, "debug", results);
|
|
652322
653149
|
log(config, "info", "Cleaning up and finishing post-processing.");
|
|
652323
653150
|
cleanTemp();
|
|
652324
653151
|
sendTelemetry(config, "runTests", results);
|