codeceptjs 4.2.1-beta.2 → 4.2.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.
@@ -256,6 +256,10 @@ I.dontSee('#add-to-cart-btn');
256
256
 
257
257
  Returns **void** automatically synchronized promise through #recorder
258
258
 
259
+ ### capabilities
260
+
261
+ Type: CodeceptJS.HelperCapabilities
262
+
259
263
  ### checkIfAppIsInstalled
260
264
 
261
265
  Returns app installation status.
@@ -79,7 +79,7 @@ Type: [object][4]
79
79
  * `apiBase` **[string][3]?** Cloudflare API base URL
80
80
  * `input` **[string][3]?** how actions are dispatched: `cdp` (real mouse and keyboard events) or `synthetic` (DOM events).
81
81
  * `capabilities` **[object][4]?** browser capabilities; Kitesurf sets `{ layout: 'real', screenshot: true }`.
82
- * `xpathPolyfill` **([string][3] | [boolean][17])?** inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
82
+ * `xpathPolyfill` **([string][3] | [boolean][18])?** inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
83
83
  * `waitForTimeout` **[number][8]?** default timeout for wait* actions, in seconds.
84
84
  * `waitForAction` **[number][8]?** fixed delay after each action, in milliseconds. When unset, actions wait only for the navigation they trigger.
85
85
  * `pollInterval` **[number][8]?** interval between checks while waiting, in milliseconds.
@@ -190,6 +190,10 @@ I.dontSee('#add-to-cart-btn');
190
190
 
191
191
  Returns **void** automatically synchronized promise through #recorder
192
192
 
193
+ ### capabilities
194
+
195
+ Type: CodeceptJS.HelperCapabilities
196
+
193
197
  ### checkOption
194
198
 
195
199
  Selects a checkbox or radio button.
@@ -683,6 +687,22 @@ I.forceClick({css: 'nav a.login'});
683
687
 
684
688
  Returns **void** automatically synchronized promise through #recorder
685
689
 
690
+ ### grabAriaSnapshot
691
+
692
+ Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
693
+ The format matches Playwright's [ARIA snapshots][14].
694
+
695
+ ```js
696
+ const snapshot = await I.grabAriaSnapshot();
697
+ const formSnapshot = await I.grabAriaSnapshot('#login-form');
698
+ ```
699
+
700
+ #### Parameters
701
+
702
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator. Defaults to body element.
703
+
704
+ Returns **[Promise][12]<[string][3]>** YAML representation of the accessibility tree
705
+
686
706
  ### grabAttributeFrom
687
707
 
688
708
  Retrieves an attribute from an element located by CSS or XPath and returns it to test.
@@ -714,7 +734,7 @@ let hints = await I.grabAttributeFromAll('.tooltip', 'title');
714
734
  * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
715
735
  * `attr` **[string][3]** attribute name.
716
736
 
717
- Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
737
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** attribute value
718
738
 
719
739
  ### grabCookie
720
740
 
@@ -742,7 +762,7 @@ Resumes test execution, so **should be used inside async function with `await`**
742
762
  let cookies = await I.grabCookies();
743
763
  ```
744
764
 
745
- Returns **[Promise][12]<[Array][14]<CodeceptJS.Cookie>>** array of cookie objects.
765
+ Returns **[Promise][12]<[Array][15]<CodeceptJS.Cookie>>** array of cookie objects.
746
766
 
747
767
  ### grabCssPropertyFrom
748
768
 
@@ -775,7 +795,7 @@ const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
775
795
  * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
776
796
  * `cssProperty` **[string][3]** CSS property name.
777
797
 
778
- Returns **[Promise][12]<[Array][14]<[string][3]>>** CSS value
798
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** CSS value
779
799
 
780
800
  ### grabCurrentUrl
781
801
 
@@ -835,7 +855,7 @@ let postHTMLs = await I.grabHTMLFromAll('.post');
835
855
  * `locator` &#x20;
836
856
  * `element` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
837
857
 
838
- Returns **[Promise][12]<[Array][14]<[string][3]>>** HTML code for an element
858
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** HTML code for an element
839
859
 
840
860
  ### grabNumberOfElements
841
861
 
@@ -889,7 +909,7 @@ expect(traffics[0].response.status).to.equal(200);
889
909
  expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
890
910
  ```
891
911
 
892
- Returns **[Array][14]** recorded network traffics
912
+ Returns **[Array][15]** recorded network traffics
893
913
 
894
914
  ### grabSource
895
915
 
@@ -932,7 +952,7 @@ let pins = await I.grabTextFromAll('#pin li');
932
952
 
933
953
  * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
934
954
 
935
- Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
955
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** attribute value
936
956
 
937
957
  ### grabTitle
938
958
 
@@ -974,7 +994,7 @@ let inputs = await I.grabValueFromAll('//form/input');
974
994
 
975
995
  * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
976
996
 
977
- Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
997
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** attribute value
978
998
 
979
999
  ### grabWebElement
980
1000
 
@@ -1017,7 +1037,7 @@ I.pressKey(['Control', 'a']);
1017
1037
 
1018
1038
  #### Parameters
1019
1039
 
1020
- * `key` **([string][3] | [Array][14]<[string][3]>)** a key or an array of keys to combine (modifiers first).
1040
+ * `key` **([string][3] | [Array][15]<[string][3]>)** a key or an array of keys to combine (modifiers first).
1021
1041
 
1022
1042
  Returns **void** automatically synchronized promise through #recorder
1023
1043
 
@@ -1471,7 +1491,7 @@ I.selectOption('Which OS do you use?', ['Android', 'iOS']);
1471
1491
  #### Parameters
1472
1492
 
1473
1493
  * `select` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
1474
- * `option` **([string][3] | [Array][14]<any>)** visible text or value of option.
1494
+ * `option` **([string][3] | [Array][15]<any>)** visible text or value of option.
1475
1495
  * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1476
1496
 
1477
1497
  Returns **void** automatically synchronized promise through #recorder
@@ -1494,7 +1514,7 @@ I.setCookie([
1494
1514
 
1495
1515
  #### Parameters
1496
1516
 
1497
- * `cookie` **(Cookie | [Array][14]<Cookie>)** a cookie object or array of cookie objects.
1517
+ * `cookie` **(Cookie | [Array][15]<Cookie>)** a cookie object or array of cookie objects.
1498
1518
 
1499
1519
  Returns **void** automatically synchronized promise through #recorder
1500
1520
 
@@ -1544,13 +1564,13 @@ const video = await I.stopScreencast();
1544
1564
 
1545
1565
  * `options` **[object][4]?** `{ lastFrameDelayMs }`: how long the last frame is shown, in milliseconds (1000 by default).
1546
1566
 
1547
- Returns **[Promise][12]<([Buffer][15] | null)>** APNG data, or `null` if no frames were recorded.
1567
+ Returns **[Promise][12]<([Buffer][16] | null)>** APNG data, or `null` if no frames were recorded.
1548
1568
 
1549
1569
  ### type
1550
1570
 
1551
1571
  Types out the given text into an active field.
1552
1572
  To slow down typing use a second parameter, to set interval between key presses.
1553
- *Note:* Should be used when [`fillField`][16] is not an option.
1573
+ *Note:* Should be used when [`fillField`][17] is not an option.
1554
1574
 
1555
1575
  ```js
1556
1576
  // passing in a string
@@ -1570,7 +1590,7 @@ I.type(secret('123456'));
1570
1590
 
1571
1591
  * `keys` &#x20;
1572
1592
  * `delay` **[number][8]?** (optional) delay in ms between key presses
1573
- * `key` **([string][3] | [Array][14]<[string][3]>)** or array of keys to type.
1593
+ * `key` **([string][3] | [Array][15]<[string][3]>)** or array of keys to type.
1574
1594
 
1575
1595
  Returns **void** automatically synchronized promise through #recorder
1576
1596
 
@@ -1690,7 +1710,7 @@ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and
1690
1710
  #### Parameters
1691
1711
 
1692
1712
  * `fn` **([string][3] | [function][11])** to be executed in browser context.
1693
- * `argsOrSec` **([Array][14]<any> | [number][8])?** (optional, `1` by default) arguments for function or seconds.
1713
+ * `argsOrSec` **([Array][15]<any> | [number][8])?** (optional, `1` by default) arguments for function or seconds.
1694
1714
  * `sec` **[number][8]?** (optional, `1` by default) time in seconds to wait
1695
1715
 
1696
1716
  Returns **void** automatically synchronized promise through #recorder
@@ -1835,7 +1855,7 @@ Probes a `/json/version`-style URL with a short timeout, used for the courtesy-a
1835
1855
 
1836
1856
  * `url` **[string][3]**&#x20;
1837
1857
 
1838
- Returns **[Promise][12]<[boolean][17]>** true if the URL answered.
1858
+ Returns **[Promise][12]<[boolean][18]>** true if the URL answered.
1839
1859
 
1840
1860
  ### _resolveBinary
1841
1861
 
@@ -1892,10 +1912,12 @@ per run and counts directly toward real-world startup latency.
1892
1912
 
1893
1913
  [13]: https://playwright.dev/docs/api/class-locator#locator-focus
1894
1914
 
1895
- [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
1915
+ [14]: https://playwright.dev/docs/aria-snapshots
1916
+
1917
+ [15]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
1896
1918
 
1897
- [15]: https://nodejs.org/api/buffer.html
1919
+ [16]: https://nodejs.org/api/buffer.html
1898
1920
 
1899
- [16]: #fillfield
1921
+ [17]: #fillfield
1900
1922
 
1901
- [17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
1923
+ [18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
@@ -111,8 +111,8 @@ Type: [object][4]
111
111
  * `url` **[string][3]?** base url of website to be tested.
112
112
  * `headers` **[object][4]?** headers sent when connecting to the endpoint, e.g. for authenticated remote browsers.
113
113
  * `input` **[string][3]?** how actions are dispatched: `cdp` (real mouse and keyboard events) or `synthetic` (DOM events). `auto` picks `cdp` when the browser renders layout.
114
- * `xpathPolyfill` **([string][3] | [boolean][17])?** inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
115
- * `capabilities` **[object][4]?** browser capabilities (`layout`, `xpath`, `screenshot`, `innerText`) to use instead of detecting them at runtime.
114
+ * `xpathPolyfill` **([string][3] | [boolean][18])?** inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
115
+ * `capabilities` **[object][4]?** browser capabilities (`layout`, `xpath`, `screenshot`, `video`, `innerText`, `aria`) to use instead of detecting them at runtime.
116
116
  * `waitForTimeout` **[number][8]?** default timeout for wait* actions, in seconds.
117
117
  * `waitForAction` **[number][8]?** fixed delay after each action, in milliseconds. When unset, actions wait only for the navigation they trigger.
118
118
  * `pollInterval` **[number][8]?** interval between checks while waiting, in milliseconds.
@@ -250,6 +250,10 @@ I.dontSee('#add-to-cart-btn');
250
250
 
251
251
  Returns **void** automatically synchronized promise through #recorder
252
252
 
253
+ ### capabilities
254
+
255
+ Type: CodeceptJS.HelperCapabilities
256
+
253
257
  ### checkOption
254
258
 
255
259
  Selects a checkbox or radio button.
@@ -743,6 +747,22 @@ I.forceClick({css: 'nav a.login'});
743
747
 
744
748
  Returns **void** automatically synchronized promise through #recorder
745
749
 
750
+ ### grabAriaSnapshot
751
+
752
+ Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
753
+ The format matches Playwright's [ARIA snapshots][14].
754
+
755
+ ```js
756
+ const snapshot = await I.grabAriaSnapshot();
757
+ const formSnapshot = await I.grabAriaSnapshot('#login-form');
758
+ ```
759
+
760
+ #### Parameters
761
+
762
+ * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator. Defaults to body element.
763
+
764
+ Returns **[Promise][12]<[string][3]>** YAML representation of the accessibility tree
765
+
746
766
  ### grabAttributeFrom
747
767
 
748
768
  Retrieves an attribute from an element located by CSS or XPath and returns it to test.
@@ -774,7 +794,7 @@ let hints = await I.grabAttributeFromAll('.tooltip', 'title');
774
794
  * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
775
795
  * `attr` **[string][3]** attribute name.
776
796
 
777
- Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
797
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** attribute value
778
798
 
779
799
  ### grabCookie
780
800
 
@@ -802,7 +822,7 @@ Resumes test execution, so **should be used inside async function with `await`**
802
822
  let cookies = await I.grabCookies();
803
823
  ```
804
824
 
805
- Returns **[Promise][12]<[Array][14]<CodeceptJS.Cookie>>** array of cookie objects.
825
+ Returns **[Promise][12]<[Array][15]<CodeceptJS.Cookie>>** array of cookie objects.
806
826
 
807
827
  ### grabCssPropertyFrom
808
828
 
@@ -835,7 +855,7 @@ const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
835
855
  * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
836
856
  * `cssProperty` **[string][3]** CSS property name.
837
857
 
838
- Returns **[Promise][12]<[Array][14]<[string][3]>>** CSS value
858
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** CSS value
839
859
 
840
860
  ### grabCurrentUrl
841
861
 
@@ -895,7 +915,7 @@ let postHTMLs = await I.grabHTMLFromAll('.post');
895
915
  * `locator` &#x20;
896
916
  * `element` **([string][3] | [object][4])** located by CSS|XPath|strict locator.
897
917
 
898
- Returns **[Promise][12]<[Array][14]<[string][3]>>** HTML code for an element
918
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** HTML code for an element
899
919
 
900
920
  ### grabNumberOfElements
901
921
 
@@ -949,7 +969,7 @@ expect(traffics[0].response.status).to.equal(200);
949
969
  expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
950
970
  ```
951
971
 
952
- Returns **[Array][14]** recorded network traffics
972
+ Returns **[Array][15]** recorded network traffics
953
973
 
954
974
  ### grabSource
955
975
 
@@ -992,7 +1012,7 @@ let pins = await I.grabTextFromAll('#pin li');
992
1012
 
993
1013
  * `locator` **([string][3] | [object][4])** element located by CSS|XPath|strict locator.
994
1014
 
995
- Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
1015
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** attribute value
996
1016
 
997
1017
  ### grabTitle
998
1018
 
@@ -1034,7 +1054,7 @@ let inputs = await I.grabValueFromAll('//form/input');
1034
1054
 
1035
1055
  * `locator` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
1036
1056
 
1037
- Returns **[Promise][12]<[Array][14]<[string][3]>>** attribute value
1057
+ Returns **[Promise][12]<[Array][15]<[string][3]>>** attribute value
1038
1058
 
1039
1059
  ### grabWebElement
1040
1060
 
@@ -1077,7 +1097,7 @@ I.pressKey(['Control', 'a']);
1077
1097
 
1078
1098
  #### Parameters
1079
1099
 
1080
- * `key` **([string][3] | [Array][14]<[string][3]>)** a key or an array of keys to combine (modifiers first).
1100
+ * `key` **([string][3] | [Array][15]<[string][3]>)** a key or an array of keys to combine (modifiers first).
1081
1101
 
1082
1102
  Returns **void** automatically synchronized promise through #recorder
1083
1103
 
@@ -1531,7 +1551,7 @@ I.selectOption('Which OS do you use?', ['Android', 'iOS']);
1531
1551
  #### Parameters
1532
1552
 
1533
1553
  * `select` **([string][3] | [object][4])** field located by label|name|CSS|XPath|strict locator.
1534
- * `option` **([string][3] | [Array][14]<any>)** visible text or value of option.
1554
+ * `option` **([string][3] | [Array][15]<any>)** visible text or value of option.
1535
1555
  * `context` **([string][3]? | [object][4])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1536
1556
 
1537
1557
  Returns **void** automatically synchronized promise through #recorder
@@ -1554,7 +1574,7 @@ I.setCookie([
1554
1574
 
1555
1575
  #### Parameters
1556
1576
 
1557
- * `cookie` **(Cookie | [Array][14]<Cookie>)** a cookie object or array of cookie objects.
1577
+ * `cookie` **(Cookie | [Array][15]<Cookie>)** a cookie object or array of cookie objects.
1558
1578
 
1559
1579
  Returns **void** automatically synchronized promise through #recorder
1560
1580
 
@@ -1604,13 +1624,13 @@ const video = await I.stopScreencast();
1604
1624
 
1605
1625
  * `options` **[object][4]?** `{ lastFrameDelayMs }`: how long the last frame is shown, in milliseconds (1000 by default).
1606
1626
 
1607
- Returns **[Promise][12]<([Buffer][15] | null)>** APNG data, or `null` if no frames were recorded.
1627
+ Returns **[Promise][12]<([Buffer][16] | null)>** APNG data, or `null` if no frames were recorded.
1608
1628
 
1609
1629
  ### type
1610
1630
 
1611
1631
  Types out the given text into an active field.
1612
1632
  To slow down typing use a second parameter, to set interval between key presses.
1613
- *Note:* Should be used when [`fillField`][16] is not an option.
1633
+ *Note:* Should be used when [`fillField`][17] is not an option.
1614
1634
 
1615
1635
  ```js
1616
1636
  // passing in a string
@@ -1630,7 +1650,7 @@ I.type(secret('123456'));
1630
1650
 
1631
1651
  * `keys` &#x20;
1632
1652
  * `delay` **[number][8]?** (optional) delay in ms between key presses
1633
- * `key` **([string][3] | [Array][14]<[string][3]>)** or array of keys to type.
1653
+ * `key` **([string][3] | [Array][15]<[string][3]>)** or array of keys to type.
1634
1654
 
1635
1655
  Returns **void** automatically synchronized promise through #recorder
1636
1656
 
@@ -1750,7 +1770,7 @@ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and
1750
1770
  #### Parameters
1751
1771
 
1752
1772
  * `fn` **([string][3] | [function][11])** to be executed in browser context.
1753
- * `argsOrSec` **([Array][14]<any> | [number][8])?** (optional, `1` by default) arguments for function or seconds.
1773
+ * `argsOrSec` **([Array][15]<any> | [number][8])?** (optional, `1` by default) arguments for function or seconds.
1754
1774
  * `sec` **[number][8]?** (optional, `1` by default) time in seconds to wait
1755
1775
 
1756
1776
  Returns **void** automatically synchronized promise through #recorder
@@ -1895,7 +1915,7 @@ Probes a `/json/version`-style URL with a short timeout, used for the courtesy-a
1895
1915
 
1896
1916
  * `url` **[string][3]**&#x20;
1897
1917
 
1898
- Returns **[Promise][12]<[boolean][17]>** true if the URL answered.
1918
+ Returns **[Promise][12]<[boolean][18]>** true if the URL answered.
1899
1919
 
1900
1920
  ### _resolveBinary
1901
1921
 
@@ -1952,10 +1972,12 @@ per run and counts directly toward real-world startup latency.
1952
1972
 
1953
1973
  [13]: https://playwright.dev/docs/api/class-locator#locator-focus
1954
1974
 
1955
- [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
1975
+ [14]: https://playwright.dev/docs/aria-snapshots
1976
+
1977
+ [15]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
1956
1978
 
1957
- [15]: https://nodejs.org/api/buffer.html
1979
+ [16]: https://nodejs.org/api/buffer.html
1958
1980
 
1959
- [16]: #fillfield
1981
+ [17]: #fillfield
1960
1982
 
1961
- [17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
1983
+ [18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
@@ -440,6 +440,10 @@ Returns **void** automatically synchronized promise through #recorder
440
440
 
441
441
  Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt.
442
442
 
443
+ ### capabilities
444
+
445
+ Type: CodeceptJS.HelperCapabilities
446
+
443
447
  ### checkOption
444
448
 
445
449
  [Additional options][14] for check available as 3rd argument.
@@ -39,26 +39,26 @@ Type: [object][6]
39
39
 
40
40
  * `url` **[string][5]** base url of website to be tested
41
41
  * `basicAuth` **[object][6]?** (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
42
- * `show` **[boolean][24]?** show Google Chrome window for debug.
43
- * `restart` **[boolean][24]?** restart browser between tests.
44
- * `disableScreenshots` **[boolean][24]?** don't save screenshot on failure.
45
- * `fullPageScreenshots` **[boolean][24]?** make full page screenshots on failure.
46
- * `uniqueScreenshotNames` **[boolean][24]?** option to prevent screenshot override if you have scenarios with the same name in different suites.
47
- * `trace` **[boolean][24]?** record [tracing information][28] with screenshots.
48
- * `keepTraceForPassedTests` **[boolean][24]?** save trace for passed tests.
49
- * `keepBrowserState` **[boolean][24]?** keep browser state between tests when `restart` is set to false.
50
- * `keepCookies` **[boolean][24]?** keep cookies between tests when `restart` is set to false.
42
+ * `show` **[boolean][25]?** show Google Chrome window for debug.
43
+ * `restart` **[boolean][25]?** restart browser between tests.
44
+ * `disableScreenshots` **[boolean][25]?** don't save screenshot on failure.
45
+ * `fullPageScreenshots` **[boolean][25]?** make full page screenshots on failure.
46
+ * `uniqueScreenshotNames` **[boolean][25]?** option to prevent screenshot override if you have scenarios with the same name in different suites.
47
+ * `trace` **[boolean][25]?** record [tracing information][29] with screenshots.
48
+ * `keepTraceForPassedTests` **[boolean][25]?** save trace for passed tests.
49
+ * `keepBrowserState` **[boolean][25]?** keep browser state between tests when `restart` is set to false.
50
+ * `keepCookies` **[boolean][25]?** keep cookies between tests when `restart` is set to false.
51
51
  * `waitForAction` **[number][11]?** how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
52
- * `waitForNavigation` **([string][5] | [Array][17]<[string][5]>)?** when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API][29]. Array values are accepted as well.
52
+ * `waitForNavigation` **([string][5] | [Array][18]<[string][5]>)?** when to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API][30]. Array values are accepted as well.
53
53
  * `pressKeyDelay` **[number][11]?** delay between key presses in ms. Used when calling Puppeteers page.type(...) in fillField/appendField
54
54
  * `getPageTimeout` **[number][11]?** config option to set maximum navigation time in milliseconds. If the timeout is set to 0, then timeout will be disabled.
55
55
  * `waitForTimeout` **[number][11]?** default wait* timeout in ms.
56
56
  * `windowSize` **[string][5]?** default window size. Set a dimension in format WIDTHxHEIGHT like `640x480`.
57
57
  * `userAgent` **[string][5]?** user-agent string.
58
- * `manualStart` **[boolean][24]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
58
+ * `manualStart` **[boolean][25]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
59
59
  * `browser` **[string][5]?** can be changed to `firefox` when using [puppeteer-firefox][2].
60
- * `chrome` **[object][6]?** pass additional [Puppeteer run options][30].
61
- * `highlightElement` **[boolean][24]?** highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
60
+ * `chrome` **[object][6]?** pass additional [Puppeteer run options][31].
61
+ * `highlightElement` **[boolean][25]?** highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
62
62
 
63
63
  ## findElement
64
64
 
@@ -82,7 +82,7 @@ Note: Unlike Playwright, Puppeteer's Locator API doesn't have .all() method for
82
82
  * `matcher` **[Object][6]** Puppeteer context to search within
83
83
  * `locator` **([Object][6] | [string][5])** Locator specification
84
84
 
85
- Returns **[Promise][12]<[Array][17]>** Array of ElementHandle objects
85
+ Returns **[Promise][12]<[Array][18]>** Array of ElementHandle objects
86
86
 
87
87
  ## wrapError
88
88
 
@@ -340,6 +340,10 @@ Returns **void** automatically synchronized promise through #recorder
340
340
 
341
341
  Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt.
342
342
 
343
+ ### capabilities
344
+
345
+ Type: CodeceptJS.HelperCapabilities
346
+
343
347
  ### checkOption
344
348
 
345
349
  Selects a checkbox or radio button.
@@ -917,6 +921,22 @@ I.forceClick({css: 'nav a.login'});
917
921
 
918
922
  Returns **void** automatically synchronized promise through #recorder
919
923
 
924
+ ### grabAriaSnapshot
925
+
926
+ Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
927
+ The format matches Playwright's [ARIA snapshots][17].
928
+
929
+ ```js
930
+ const snapshot = await I.grabAriaSnapshot();
931
+ const formSnapshot = await I.grabAriaSnapshot('#login-form');
932
+ ```
933
+
934
+ #### Parameters
935
+
936
+ * `locator` **([string][5] | [object][6])** element located by CSS|XPath|strict locator. Defaults to body element.
937
+
938
+ Returns **[Promise][12]<[string][5]>** YAML representation of the accessibility tree
939
+
920
940
  ### grabAttributeFrom
921
941
 
922
942
  Retrieves an attribute from an element located by CSS or XPath and returns it to test.
@@ -948,7 +968,7 @@ let hints = await I.grabAttributeFromAll('.tooltip', 'title');
948
968
  * `locator` **([string][5] | [object][6])** element located by CSS|XPath|strict locator.
949
969
  * `attr` **[string][5]** attribute name.
950
970
 
951
- Returns **[Promise][12]<[Array][17]<[string][5]>>** attribute value
971
+ Returns **[Promise][12]<[Array][18]<[string][5]>>** attribute value
952
972
 
953
973
  ### grabBrowserLogs
954
974
 
@@ -959,7 +979,7 @@ let logs = await I.grabBrowserLogs();
959
979
  console.log(JSON.stringify(logs))
960
980
  ```
961
981
 
962
- Returns **[Promise][12]<[Array][17]<any>>**&#x20;
982
+ Returns **[Promise][12]<[Array][18]<any>>**&#x20;
963
983
 
964
984
  ### grabCookie
965
985
 
@@ -1009,7 +1029,7 @@ const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
1009
1029
  * `locator` **([string][5] | [object][6])** element located by CSS|XPath|strict locator.
1010
1030
  * `cssProperty` **[string][5]** CSS property name.
1011
1031
 
1012
- Returns **[Promise][12]<[Array][17]<[string][5]>>** CSS value
1032
+ Returns **[Promise][12]<[Array][18]<[string][5]>>** CSS value
1013
1033
 
1014
1034
  ### grabCurrentUrl
1015
1035
 
@@ -1122,7 +1142,7 @@ let postHTMLs = await I.grabHTMLFromAll('.post');
1122
1142
  * `locator` &#x20;
1123
1143
  * `element` **([string][5] | [object][6])** located by CSS|XPath|strict locator.
1124
1144
 
1125
- Returns **[Promise][12]<[Array][17]<[string][5]>>** HTML code for an element
1145
+ Returns **[Promise][12]<[Array][18]<[string][5]>>** HTML code for an element
1126
1146
 
1127
1147
  ### grabNumberOfOpenTabs
1128
1148
 
@@ -1182,7 +1202,7 @@ expect(traffics[0].response.status).to.equal(200);
1182
1202
  expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
1183
1203
  ```
1184
1204
 
1185
- Returns **[Array][17]** recorded network traffics
1205
+ Returns **[Array][18]** recorded network traffics
1186
1206
 
1187
1207
  ### grabSource
1188
1208
 
@@ -1225,7 +1245,7 @@ let pins = await I.grabTextFromAll('#pin li');
1225
1245
 
1226
1246
  * `locator` **([string][5] | [object][6])** element located by CSS|XPath|strict locator.
1227
1247
 
1228
- Returns **[Promise][12]<[Array][17]<[string][5]>>** attribute value
1248
+ Returns **[Promise][12]<[Array][18]<[string][5]>>** attribute value
1229
1249
 
1230
1250
  ### grabTitle
1231
1251
 
@@ -1267,7 +1287,7 @@ let inputs = await I.grabValueFromAll('//form/input');
1267
1287
 
1268
1288
  * `locator` **([string][5] | [object][6])** field located by label|name|CSS|XPath|strict locator.
1269
1289
 
1270
- Returns **[Promise][12]<[Array][17]<[string][5]>>** attribute value
1290
+ Returns **[Promise][12]<[Array][18]<[string][5]>>** attribute value
1271
1291
 
1272
1292
  ### grabWebElement
1273
1293
 
@@ -1303,12 +1323,12 @@ Returns **[Promise][12]<any>** WebElement of being used Web helper
1303
1323
 
1304
1324
  Grab the recording WS messages
1305
1325
 
1306
- Returns **([Array][17]<any> | [undefined][18])**&#x20;
1326
+ Returns **([Array][18]<any> | [undefined][19])**&#x20;
1307
1327
 
1308
1328
  ### handleDownloads
1309
1329
 
1310
1330
  Sets a directory to where save files. Allows to test file downloads.
1311
- Should be used with [FileSystem helper][19] to check that file were downloaded correctly.
1331
+ Should be used with [FileSystem helper][20] to check that file were downloaded correctly.
1312
1332
 
1313
1333
  By default, files are saved to `output/downloads`.
1314
1334
  This directory is cleaned on every `handleDownloads` call, to ensure no old files are kept.
@@ -1327,13 +1347,13 @@ I.seeFile('avatar.jpg');
1327
1347
 
1328
1348
  ### mockRoute
1329
1349
 
1330
- Mocks network request using [`Request Interception`][20]
1350
+ Mocks network request using [`Request Interception`][21]
1331
1351
 
1332
1352
  ```js
1333
1353
  I.mockRoute(/(.png$)|(.jpg$)/, route => route.abort());
1334
1354
  ```
1335
1355
 
1336
- This method allows intercepting and mocking requests & responses. [Learn more about it][20]
1356
+ This method allows intercepting and mocking requests & responses. [Learn more about it][21]
1337
1357
 
1338
1358
  #### Parameters
1339
1359
 
@@ -1372,11 +1392,11 @@ I.openNewTab();
1372
1392
 
1373
1393
  ### pressKey
1374
1394
 
1375
- *Note:* Shortcuts like `'Meta'` + `'A'` do not work on macOS ([puppeteer/puppeteer#1313][21]).
1395
+ *Note:* Shortcuts like `'Meta'` + `'A'` do not work on macOS ([puppeteer/puppeteer#1313][22]).
1376
1396
 
1377
1397
  Presses a key in the browser (on a focused element).
1378
1398
 
1379
- *Hint:* For populating text field or textarea, it is recommended to use [`fillField`][22].
1399
+ *Hint:* For populating text field or textarea, it is recommended to use [`fillField`][23].
1380
1400
 
1381
1401
  ```js
1382
1402
  I.pressKey('Backspace');
@@ -1435,7 +1455,7 @@ Some of the supported key names are:
1435
1455
 
1436
1456
  #### Parameters
1437
1457
 
1438
- * `key` **([string][5] | [Array][17]<[string][5]>)** key or array of keys to press.
1458
+ * `key` **([string][5] | [Array][18]<[string][5]>)** key or array of keys to press.
1439
1459
 
1440
1460
  Returns **void** automatically synchronized promise through #recorder
1441
1461
 
@@ -1443,7 +1463,7 @@ Returns **void** automatically synchronized promise through #recorder
1443
1463
 
1444
1464
  Presses a key in the browser and leaves it in a down state.
1445
1465
 
1446
- To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][23]).
1466
+ To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][24]).
1447
1467
 
1448
1468
  ```js
1449
1469
  I.pressKeyDown('Control');
@@ -1461,7 +1481,7 @@ Returns **void** automatically synchronized promise through #recorder
1461
1481
 
1462
1482
  Releases a key in the browser which was previously set to a down state.
1463
1483
 
1464
- To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][23]).
1484
+ To make combinations with modifier key and user operation (e.g. `'Control'` + [`click`][24]).
1465
1485
 
1466
1486
  ```js
1467
1487
  I.pressKeyDown('Control');
@@ -1551,7 +1571,7 @@ I.saveScreenshot('debug.png', true) //resizes to available scrollHeight and scro
1551
1571
  #### Parameters
1552
1572
 
1553
1573
  * `fileName` **[string][5]** file name to save.
1554
- * `fullPage` **[boolean][24]** (optional, `false` by default) flag to enable fullscreen screenshot mode.
1574
+ * `fullPage` **[boolean][25]** (optional, `false` by default) flag to enable fullscreen screenshot mode.
1555
1575
 
1556
1576
  Returns **void** automatically synchronized promise through #recorder
1557
1577
 
@@ -1991,7 +2011,7 @@ I.selectOption('Which OS do you use?', ['Android', 'iOS']);
1991
2011
  #### Parameters
1992
2012
 
1993
2013
  * `select` **([string][5] | [object][6])** field located by label|name|CSS|XPath|strict locator.
1994
- * `option` **([string][5] | [Array][17]<any>)** visible text or value of option.
2014
+ * `option` **([string][5] | [Array][18]<any>)** visible text or value of option.
1995
2015
  * `context` **([string][5]? | [object][6])** (optional, `null` by default) element located by CSS | XPath | strict locator.
1996
2016
 
1997
2017
  Returns **void** automatically synchronized promise through #recorder
@@ -2014,7 +2034,7 @@ I.setCookie([
2014
2034
 
2015
2035
  #### Parameters
2016
2036
 
2017
- * `cookie` **(Cookie | [Array][17]<Cookie>)** a cookie object or array of cookie objects.
2037
+ * `cookie` **(Cookie | [Array][18]<Cookie>)** a cookie object or array of cookie objects.
2018
2038
 
2019
2039
  Returns **void** automatically synchronized promise through #recorder
2020
2040
 
@@ -2129,7 +2149,7 @@ I.switchToPreviousTab(2);
2129
2149
 
2130
2150
  Types out the given text into an active field.
2131
2151
  To slow down typing use a second parameter, to set interval between key presses.
2132
- *Note:* Should be used when [`fillField`][22] is not an option.
2152
+ *Note:* Should be used when [`fillField`][23] is not an option.
2133
2153
 
2134
2154
  ```js
2135
2155
  // passing in a string
@@ -2149,7 +2169,7 @@ I.type(secret('123456'));
2149
2169
 
2150
2170
  * `keys` &#x20;
2151
2171
  * `delay` **[number][11]?** (optional) delay in ms between key presses
2152
- * `key` **([string][5] | [Array][17]<[string][5]>)** or array of keys to type.
2172
+ * `key` **([string][5] | [Array][18]<[string][5]>)** or array of keys to type.
2153
2173
 
2154
2174
  Returns **void** automatically synchronized promise through #recorder
2155
2175
 
@@ -2180,7 +2200,7 @@ Use Puppeteer API inside a test.
2180
2200
  First argument is a description of an action.
2181
2201
  Second argument is async function that gets this helper as parameter.
2182
2202
 
2183
- { [`page`][25], [`browser`][26] } from Puppeteer API are available.
2203
+ { [`page`][26], [`browser`][27] } from Puppeteer API are available.
2184
2204
 
2185
2205
  ```js
2186
2206
  I.usePuppeteerTo('emulate offline mode', async ({ page }) {
@@ -2312,7 +2332,7 @@ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and
2312
2332
  #### Parameters
2313
2333
 
2314
2334
  * `fn` **([string][5] | [function][15])** to be executed in browser context.
2315
- * `argsOrSec` **([Array][17]<any> | [number][11])?** (optional, `1` by default) arguments for function or seconds.
2335
+ * `argsOrSec` **([Array][18]<any> | [number][11])?** (optional, `1` by default) arguments for function or seconds.
2316
2336
  * `sec` **[number][11]?** (optional, `1` by default) time in seconds to wait
2317
2337
 
2318
2338
  Returns **void** automatically synchronized promise through #recorder
@@ -2337,7 +2357,7 @@ Returns **void** automatically synchronized promise through #recorder
2337
2357
 
2338
2358
  Waits for navigation to finish. By default, takes configured `waitForNavigation` option.
2339
2359
 
2340
- See [Puppeteer's reference][27]
2360
+ See [Puppeteer's reference][28]
2341
2361
 
2342
2362
  #### Parameters
2343
2363
 
@@ -2616,30 +2636,32 @@ Set current page
2616
2636
 
2617
2637
  [16]: https://playwright.dev/docs/api/class-locator#locator-focus
2618
2638
 
2619
- [17]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
2639
+ [17]: https://playwright.dev/docs/aria-snapshots
2640
+
2641
+ [18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
2620
2642
 
2621
- [18]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
2643
+ [19]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined
2622
2644
 
2623
- [19]: https://codecept.io/helpers/FileSystem
2645
+ [20]: https://codecept.io/helpers/FileSystem
2624
2646
 
2625
- [20]: https://pptr.dev/guides/network-interception
2647
+ [21]: https://pptr.dev/guides/network-interception
2626
2648
 
2627
- [21]: https://github.com/puppeteer/puppeteer/issues/1313
2649
+ [22]: https://github.com/puppeteer/puppeteer/issues/1313
2628
2650
 
2629
- [22]: #fillfield
2651
+ [23]: #fillfield
2630
2652
 
2631
- [23]: #click
2653
+ [24]: #click
2632
2654
 
2633
- [24]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
2655
+ [25]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
2634
2656
 
2635
- [25]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page
2657
+ [26]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-page
2636
2658
 
2637
- [26]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser
2659
+ [27]: https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#class-browser
2638
2660
 
2639
- [27]: https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.page.waitfornavigation.md
2661
+ [28]: https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.page.waitfornavigation.md
2640
2662
 
2641
- [28]: https://pptr.dev/api/puppeteer.tracing
2663
+ [29]: https://pptr.dev/api/puppeteer.tracing
2642
2664
 
2643
- [29]: https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.waitforoptions.md
2665
+ [30]: https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.waitforoptions.md
2644
2666
 
2645
- [30]: https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.launchoptions.md
2667
+ [31]: https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.launchoptions.md
@@ -519,6 +519,10 @@ Returns **void** automatically synchronized promise through #recorder
519
519
 
520
520
  Dismisses the active JavaScript popup, as created by `window.alert|window.confirm|window.prompt`.
521
521
 
522
+ ### capabilities
523
+
524
+ Type: CodeceptJS.HelperCapabilities
525
+
522
526
  ### checkOption
523
527
 
524
528
  Appium: not tested
package/lib/aria.js CHANGED
@@ -257,4 +257,39 @@ function diffAriaSnapshots(previous, current) {
257
257
  return formatDiff(added, removed)
258
258
  }
259
259
 
260
- export { diffAriaSnapshots, compactAriaSnapshot }
260
+ // ─────────────────────────────────────────────────────────────────
261
+ // Build: accessibility tree → YAML snapshot
262
+ // ─────────────────────────────────────────────────────────────────
263
+
264
+ const HIDDEN_ROLES = new Set(['RootWebArea', 'generic', 'none', 'LabelText', 'InlineTextBox', 'LineBreak', 'ListMarker'])
265
+
266
+ function renderAXTree(node, depth = 0, parentName = '') {
267
+ if (!node) return []
268
+ const indent = ' '.repeat(depth)
269
+ const name = (node.name || '').trim()
270
+ if (node.role === 'StaticText') return name && name !== parentName ? [`${indent}- text: ${JSON.stringify(name)}`] : []
271
+ const hidden = HIDDEN_ROLES.has(node.role)
272
+ const children = (node.children || []).flatMap(child => renderAXTree(child, hidden ? depth : depth + 1, hidden ? parentName : name))
273
+ if (hidden) return children
274
+ const line = `${indent}- ${node.role}${name ? ` ${JSON.stringify(name)}` : ''}`
275
+ return [children.length ? `${line}:` : line, ...children]
276
+ }
277
+
278
+ // Nested tree shaped like Puppeteer's SerializedAXNode: { role, name, children }
279
+ function ariaSnapshotFromTree(root) {
280
+ return renderAXTree(root).join('\n')
281
+ }
282
+
283
+ // Flat `nodes` list from CDP `Accessibility.getFullAXTree`, rooted at a DOM node
284
+ function ariaSnapshotFromAXNodes(axNodes, backendNodeId) {
285
+ const byId = new Map(axNodes.map(node => [node.nodeId, node]))
286
+ const toTree = node => ({
287
+ role: node.ignored ? 'none' : node.role?.value,
288
+ name: node.name?.value,
289
+ children: (node.childIds || []).map(id => byId.get(id)).filter(Boolean).map(toTree),
290
+ })
291
+ const root = axNodes.find(node => node.backendDOMNodeId === backendNodeId)
292
+ return root ? ariaSnapshotFromTree(toTree(root)) : ''
293
+ }
294
+
295
+ export { diffAriaSnapshots, compactAriaSnapshot, ariaSnapshotFromTree, ariaSnapshotFromAXNodes }
package/lib/container.js CHANGED
@@ -61,7 +61,7 @@ class Container {
61
61
  *
62
62
  */
63
63
  static get STANDARD_ACTING_HELPERS() {
64
- return ['Playwright', 'WebDriver', 'Puppeteer', 'Appium']
64
+ return ['Playwright', 'WebDriver', 'Puppeteer', 'Appium', 'Obscura', 'Lightpanda']
65
65
  }
66
66
  /**
67
67
  * Create container with all required helpers and support objects
@@ -8,10 +8,11 @@ import CDPConnection from './extras/CDPConnection.js'
8
8
  import installCodeceptClient from './clientscripts/cdpBrowserClient.js'
9
9
  import xpathPolyfillSource from './clientscripts/xpathPolyfill.js'
10
10
  import layoutProbe from './clientscripts/layoutProbe.js'
11
+ import { ariaSnapshotFromAXNodes } from '../aria.js'
11
12
  import Locator from '../locator.js'
12
13
  import output from '../output.js'
13
14
  import store from '../store.js'
14
- import { xpathLocator, normalizePath, resolveUrl, toCamelCase, convertCssPropertiesToCamelCase, normalizeSpacesInString, fileExists, base64EncodeFile, getMimeType, isFile, isWindows } from '../utils.js'
15
+ import { xpathLocator, normalizePath, resolveUrl, toCamelCase, convertCssPropertiesToCamelCase, normalizeSpacesInString, fileExists, base64EncodeFile, getMimeType, isFile, isWindows, screenshotOutputFolder } from '../utils.js'
15
16
  import ElementNotFound from './errors/ElementNotFound.js'
16
17
  import MultipleElementsFound from './errors/MultipleElementsFound.js'
17
18
  import { includes as stringIncludes } from '../assert/include.js'
@@ -38,7 +39,7 @@ import { assembleApng, isPng } from './extras/apngAssembler.js'
38
39
  * @prop {object} [headers={}] - headers sent when connecting to the endpoint, e.g. for authenticated remote browsers.
39
40
  * @prop {string} [input=auto] - how actions are dispatched: `cdp` (real mouse and keyboard events) or `synthetic` (DOM events). `auto` picks `cdp` when the browser renders layout.
40
41
  * @prop {string|boolean} [xpathPolyfill=auto] - inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
41
- * @prop {object} [capabilities={}] - browser capabilities (`layout`, `xpath`, `screenshot`, `innerText`) to use instead of detecting them at runtime.
42
+ * @prop {object} [capabilities={}] - browser capabilities (`layout`, `xpath`, `screenshot`, `video`, `innerText`, `aria`) to use instead of detecting them at runtime.
42
43
  * @prop {number} [waitForTimeout=5] - default timeout for wait* actions, in seconds.
43
44
  * @prop {number} [waitForAction] - fixed delay after each action, in milliseconds. When unset, actions wait only for the navigation they trigger.
44
45
  * @prop {number} [pollInterval=25] - interval between checks while waiting, in milliseconds.
@@ -137,7 +138,8 @@ class CDPBrowser extends Helper {
137
138
  this.serverError = null
138
139
  this.binaryPath = null
139
140
  this._selfManagedResolved = false
140
- this.capabilities = { layout: null, xpath: null, screenshot: null, innerText: null, ...this.options.capabilities }
141
+ /** @type {CodeceptJS.HelperCapabilities} */
142
+ this.capabilities = { screenshot: null, video: null, trace: false, aria: true, layout: null, xpath: null, innerText: null, ...this.options.capabilities }
141
143
  this.withinCandidates = null
142
144
  this.requests = []
143
145
  this.recording = false
@@ -615,6 +617,9 @@ class CDPBrowser extends Helper {
615
617
  if (this.capabilities.screenshot === null) {
616
618
  this.capabilities.screenshot = this.capabilities.layout === 'real'
617
619
  }
620
+ if (this.capabilities.video === null) {
621
+ this.capabilities.video = this.capabilities.screenshot
622
+ }
618
623
  if (this.options.input === 'auto') {
619
624
  this.options.input = this.capabilities.layout === 'real' ? 'cdp' : 'synthetic'
620
625
  }
@@ -754,6 +759,32 @@ class CDPBrowser extends Helper {
754
759
  return this._evaluate('document.documentElement.outerHTML')
755
760
  }
756
761
 
762
+ /**
763
+ * Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
764
+ * The format matches Playwright's [ARIA snapshots](https://playwright.dev/docs/aria-snapshots).
765
+ *
766
+ * ```js
767
+ * const snapshot = await I.grabAriaSnapshot();
768
+ * const formSnapshot = await I.grabAriaSnapshot('#login-form');
769
+ * ```
770
+ *
771
+ * @param {string|object} [locator='//body'] element located by CSS|XPath|strict locator. Defaults to body element.
772
+ * @return {Promise<string>} YAML representation of the accessibility tree
773
+ */
774
+ async grabAriaSnapshot(locator = '//body') {
775
+ const candidates = this._candidates(locator)
776
+ const { found } = await this._run(candidates, 'count')
777
+ if (!found) throw new ElementNotFound(locator)
778
+ const scope = this.withinCandidates ? [this.withinCandidates] : null
779
+ const expression = `window.__codecept.run(${JSON.stringify(candidates)}, 'element', null, ${JSON.stringify(scope)}, ${JSON.stringify(this._selectionDescriptor())}).result`
780
+ const { result } = await this.cdp.send('Runtime.evaluate', { expression }, this.sessionId)
781
+ const { node } = await this.cdp.send('DOM.describeNode', { objectId: result.objectId }, this.sessionId)
782
+ const { nodes } = await this.cdp.send('Accessibility.getFullAXTree', {}, this.sessionId)
783
+ const snapshot = ariaSnapshotFromAXNodes(nodes, node.backendNodeId)
784
+ this.debugSection('Aria Snapshot', `${snapshot.split('\n').length} lines`)
785
+ return snapshot
786
+ }
787
+
757
788
  _candidates(locator, kind = 'element') {
758
789
  locator = new Locator(locator)
759
790
  if (locator.isShadow()) {
@@ -1368,9 +1399,8 @@ class CDPBrowser extends Helper {
1368
1399
  this.debug('saveScreenshot skipped: this browser has no rendering engine')
1369
1400
  return
1370
1401
  }
1371
- const outputDir = global.output_dir || '.'
1372
1402
  const res = await this.cdp.send('Page.captureScreenshot', { format: 'png' }, this.sessionId)
1373
- fs.writeFileSync(path.join(outputDir, fileName), Buffer.from(res.data, 'base64'))
1403
+ fs.writeFileSync(screenshotOutputFolder(fileName), Buffer.from(res.data, 'base64'))
1374
1404
  }
1375
1405
 
1376
1406
  /**
@@ -1383,10 +1413,9 @@ class CDPBrowser extends Helper {
1383
1413
  }
1384
1414
  const res = await this._run(this._candidates(locator), 'rect')
1385
1415
  if (!res.found) throw new ElementNotFound(locator)
1386
- const outputDir = global.output_dir || '.'
1387
1416
  const { x, y, width, height } = res.result
1388
1417
  const shot = await this.cdp.send('Page.captureScreenshot', { format: 'png', clip: { x, y, width, height, scale: 1 } }, this.sessionId)
1389
- fs.writeFileSync(path.join(outputDir, fileName), Buffer.from(shot.data, 'base64'))
1418
+ fs.writeFileSync(screenshotOutputFolder(fileName), Buffer.from(shot.data, 'base64'))
1390
1419
  }
1391
1420
 
1392
1421
  /**
@@ -221,7 +221,7 @@ class Decision extends Helper {
221
221
  title: await helper.grabTitle(),
222
222
  }
223
223
 
224
- if (helper.grabAriaSnapshot) {
224
+ if (helper.grabAriaSnapshot && !(helper.capabilities && helper.capabilities.aria === false)) {
225
225
  state.aria = compactAriaSnapshot(await helper.grabAriaSnapshot()).slice(0, this.options.maxLength)
226
226
  return state
227
227
  }
@@ -244,7 +244,7 @@ class Decision extends Helper {
244
244
 
245
245
  _actingHelper() {
246
246
  const helper = pickActingHelper(Container.helpers())
247
- if (!helper) throw new Error('Decision helper requires a web helper: Playwright, Puppeteer or WebDriver')
247
+ if (!helper) throw new Error('Decision helper requires a web helper: Playwright, Puppeteer, WebDriver, Obscura or Lightpanda')
248
248
  return helper
249
249
  }
250
250
  }
@@ -340,6 +340,8 @@ class Playwright extends Helper {
340
340
  super(config)
341
341
 
342
342
  // playwright will be loaded dynamically in _init method
343
+ /** @type {CodeceptJS.HelperCapabilities} */
344
+ this.capabilities = { screenshot: true, video: true, trace: true, aria: true }
343
345
 
344
346
  // set defaults
345
347
  this.isRemoteBrowser = false
@@ -6,6 +6,7 @@ import Helper from '@codeceptjs/helper'
6
6
  import { v4 as uuidv4 } from 'uuid'
7
7
  import promiseRetry from 'promise-retry'
8
8
  import Locator from '../locator.js'
9
+ import { ariaSnapshotFromTree } from '../aria.js'
9
10
  import recorder from '../recorder.js'
10
11
  import store from '../store.js'
11
12
  import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
@@ -237,6 +238,8 @@ class Puppeteer extends Helper {
237
238
  super(config)
238
239
 
239
240
  // puppeteer will be loaded dynamically in _init method
241
+ /** @type {CodeceptJS.HelperCapabilities} */
242
+ this.capabilities = { screenshot: true, video: false, trace: true, aria: true }
240
243
  // set defaults
241
244
  this.isRemoteBrowser = false
242
245
  this.isRunning = false
@@ -289,6 +292,7 @@ class Puppeteer extends Helper {
289
292
 
290
293
  _setConfig(config) {
291
294
  this.options = this._validateConfig(config)
295
+ this.capabilities.aria = this.options.browser !== 'firefox'
292
296
  this.puppeteerOptions = {
293
297
  headless: !this.options.show,
294
298
  ...this._getOptions(config),
@@ -1827,6 +1831,27 @@ class Puppeteer extends Helper {
1827
1831
  return this.page.content()
1828
1832
  }
1829
1833
 
1834
+ /**
1835
+ * Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
1836
+ * The format matches Playwright's [ARIA snapshots](https://playwright.dev/docs/aria-snapshots).
1837
+ *
1838
+ * ```js
1839
+ * const snapshot = await I.grabAriaSnapshot();
1840
+ * const formSnapshot = await I.grabAriaSnapshot('#login-form');
1841
+ * ```
1842
+ *
1843
+ * @param {string|object} [locator='//body'] element located by CSS|XPath|strict locator. Defaults to body element.
1844
+ * @return {Promise<string>} YAML representation of the accessibility tree
1845
+ */
1846
+ async grabAriaSnapshot(locator = '//body') {
1847
+ const els = await this._locate(locator)
1848
+ assertElementExists(els, locator)
1849
+ const tree = await this.page.accessibility.snapshot({ root: els[0], interestingOnly: false })
1850
+ const snapshot = ariaSnapshotFromTree(tree)
1851
+ this.debugSection('Aria Snapshot', `${snapshot.split('\n').length} lines`)
1852
+ return snapshot
1853
+ }
1854
+
1830
1855
  /**
1831
1856
  * Get JS log from browser.
1832
1857
  *
@@ -461,6 +461,8 @@ class WebDriver extends Helper {
461
461
  constructor(config) {
462
462
  super(config)
463
463
  // webdriverio will be loaded dynamically in _init method
464
+ /** @type {CodeceptJS.HelperCapabilities} */
465
+ this.capabilities = { screenshot: true, video: false, trace: false, aria: false }
464
466
 
465
467
  // set defaults
466
468
  this.root = webRoot
@@ -319,6 +319,7 @@ export default function installCodeceptClient(xpathNeedsPolyfill) {
319
319
  els[0].blur()
320
320
  return true
321
321
  },
322
+ element: els => els[0],
322
323
  rect: els => {
323
324
  if (els[0].scrollIntoView) els[0].scrollIntoView({ block: 'center', inline: 'center' })
324
325
  const r = els[0].getBoundingClientRect()
@@ -78,7 +78,7 @@ export default function (config = {}) {
78
78
  const helper = pickActingHelper(Container.helpers())
79
79
 
80
80
  if (!helper) {
81
- output.warn('aiTrace plugin: No supported helper found (Playwright, Puppeteer, WebDriver). Plugin disabled.')
81
+ output.print('aiTrace plugin: No supported helper found. Plugin disabled.')
82
82
  return
83
83
  }
84
84
 
@@ -109,7 +109,7 @@ function initUrlMode(pattern) {
109
109
  const helper = getBrowserHelper()
110
110
 
111
111
  if (!helper) {
112
- output.error('pause:on=url requires a browser helper (Playwright, WebDriver, Puppeteer, Appium)')
112
+ output.error('pause:on=url requires a browser helper (Playwright, WebDriver, Puppeteer, Appium, Obscura, Lightpanda)')
113
113
  return
114
114
  }
115
115
 
@@ -350,12 +350,9 @@ function buildSrt(steps) {
350
350
  return out
351
351
  }
352
352
 
353
- // `getBrowserHelper` (from `pluginParser.js`) only recognizes `Container.STANDARD_ACTING_HELPERS`
354
- // (`Playwright`/`WebDriver`/`Puppeteer`/`Appium`), so it never finds `CDPBrowser`/`Obscura`/
355
- // `Kitesurf`. Rather than widen that shared list — used by several other plugins with their own,
356
- // Playwright/WebDriver-specific assumptions — this plugin does its own duck-typed fallback lookup,
357
- // scoped to itself: any active helper exposing a `startScreencast` function qualifies, with no
358
- // hardcoded class names, so any future CDP-family helper picks this up automatically too.
353
+ // `getBrowserHelper` (from `pluginParser.js`) only recognizes `Container.STANDARD_ACTING_HELPERS`,
354
+ // so helpers outside that list (`CDPBrowser`, `Kitesurf`) are found by a duck-typed fallback:
355
+ // any active helper exposing a `startScreencast` function qualifies.
359
356
  function getScreencastHelper() {
360
357
  const standard = getBrowserHelper()
361
358
  if (standard) return standard
@@ -189,14 +189,15 @@ function scheduleScreenshot(test, fileName, options) {
189
189
  }
190
190
 
191
191
  async function takeScreenshot(test, fileName, options) {
192
+ const helper = getBrowserHelper()
193
+ if (!helper || typeof helper.saveScreenshot !== 'function') return
194
+ if (helper.capabilities && helper.capabilities.screenshot === false) return
195
+
192
196
  const quietMode = !store.outputDir
193
197
  if (!quietMode) {
194
198
  output.plugin('screenshot', `Saving screenshot ${fileName}`)
195
199
  }
196
200
 
197
- const helper = getBrowserHelper()
198
- if (!helper || typeof helper.saveScreenshot !== 'function') return
199
-
200
201
  try {
201
202
  if (options.reportDir) {
202
203
  fileName = path.join(options.reportDir, fileName)
@@ -332,6 +333,7 @@ function wireSlides(options, trigger) {
332
333
 
333
334
  const helper = getBrowserHelper()
334
335
  if (!helper || typeof helper.saveScreenshot !== 'function') return
336
+ if (helper.capabilities && helper.capabilities.screenshot === false) return
335
337
 
336
338
  try {
337
339
  const screenshotPath = path.join(dir, fileName)
@@ -176,7 +176,8 @@ export async function captureSnapshot(helper, {
176
176
  } catch {}
177
177
  }
178
178
 
179
- if (captureScreenshot && helper.saveScreenshot) {
179
+ const canScreenshot = !(helper.capabilities && helper.capabilities.screenshot === false)
180
+ if (captureScreenshot && canScreenshot && helper.saveScreenshot) {
180
181
  try {
181
182
  const file = `${prefix}_screenshot.png`
182
183
  await helper.saveScreenshot(path.join(dir, file), fullPage)
@@ -201,7 +202,8 @@ export async function captureSnapshot(helper, {
201
202
  } catch {}
202
203
  }
203
204
 
204
- if (captureARIA && helper.grabAriaSnapshot) {
205
+ const canAria = !(helper.capabilities && helper.capabilities.aria === false)
206
+ if (captureARIA && canAria && helper.grabAriaSnapshot) {
205
207
  try {
206
208
  const aria = await helper.grabAriaSnapshot()
207
209
  const file = `${prefix}_aria.txt`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "4.2.1-beta.2",
3
+ "version": "4.2.1",
4
4
  "type": "module",
5
5
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
6
6
  "keywords": [
@@ -465,6 +465,20 @@ declare namespace CodeceptJS {
465
465
  y: number
466
466
  }
467
467
 
468
+ /**
469
+ * Features an acting helper supports. Plugins read them to decide what to capture.
470
+ * `null` means the value is detected at runtime.
471
+ */
472
+ interface HelperCapabilities {
473
+ screenshot: boolean | null
474
+ video: boolean | null
475
+ trace: boolean
476
+ aria: boolean
477
+ layout?: 'real' | 'none' | null
478
+ xpath?: 'native' | 'polyfill' | null
479
+ innerText?: 'native' | 'computed' | null
480
+ }
481
+
468
482
  // Could get extended by user generated typings
469
483
  interface Methods extends ActorStatic {}
470
484
  interface I {}
@@ -1197,7 +1197,7 @@ declare namespace CodeceptJS {
1197
1197
  * @property [headers = {}] - headers sent when connecting to the endpoint, e.g. for authenticated remote browsers.
1198
1198
  * @property [input = auto] - how actions are dispatched: `cdp` (real mouse and keyboard events) or `synthetic` (DOM events). `auto` picks `cdp` when the browser renders layout.
1199
1199
  * @property [xpathPolyfill = auto] - inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
1200
- * @property [capabilities = {}] - browser capabilities (`layout`, `xpath`, `screenshot`, `innerText`) to use instead of detecting them at runtime.
1200
+ * @property [capabilities = {}] - browser capabilities (`layout`, `xpath`, `screenshot`, `video`, `innerText`, `aria`) to use instead of detecting them at runtime.
1201
1201
  * @property [waitForTimeout = 5] - default timeout for wait* actions, in seconds.
1202
1202
  * @property [waitForAction] - fixed delay after each action, in milliseconds. When unset, actions wait only for the navigation they trigger.
1203
1203
  * @property [pollInterval = 25] - interval between checks while waiting, in milliseconds.
@@ -1249,6 +1249,7 @@ declare namespace CodeceptJS {
1249
1249
  */
1250
1250
  class CDPBrowserTs {
1251
1251
  constructor(config: CDPBrowserConfig);
1252
+ capabilities: CodeceptJS.HelperCapabilities;
1252
1253
  /**
1253
1254
  * Opts a subclass into managing its own browser server process. Called from a subclass
1254
1255
  * constructor with the raw user config and a server descriptor:
@@ -1404,6 +1405,18 @@ declare namespace CodeceptJS {
1404
1405
  * @returns source code
1405
1406
  */
1406
1407
  grabSource(): Promise<string>;
1408
+ /**
1409
+ * Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
1410
+ * The format matches Playwright's [ARIA snapshots](https://playwright.dev/docs/aria-snapshots).
1411
+ *
1412
+ * ```js
1413
+ * const snapshot = await I.grabAriaSnapshot();
1414
+ * const formSnapshot = await I.grabAriaSnapshot('#login-form');
1415
+ * ```
1416
+ * @param [locator = '//body'] - element located by CSS|XPath|strict locator. Defaults to body element.
1417
+ * @returns YAML representation of the accessibility tree
1418
+ */
1419
+ grabAriaSnapshot(locator?: string | any): Promise<string>;
1407
1420
  /**
1408
1421
  * Checks that a page contains a visible text.
1409
1422
  * Use context parameter to narrow down the search.
@@ -3924,6 +3937,7 @@ declare namespace CodeceptJS {
3924
3937
  * ```
3925
3938
  */
3926
3939
  class PlaywrightTs {
3940
+ capabilities: CodeceptJS.HelperCapabilities;
3927
3941
  /**
3928
3942
  * Use Playwright API inside a test.
3929
3943
  *
@@ -6135,6 +6149,7 @@ declare namespace CodeceptJS {
6135
6149
  * ## Methods
6136
6150
  */
6137
6151
  class PuppeteerTs {
6152
+ capabilities: CodeceptJS.HelperCapabilities;
6138
6153
  /**
6139
6154
  * Use Puppeteer API inside a test.
6140
6155
  *
@@ -7132,6 +7147,18 @@ declare namespace CodeceptJS {
7132
7147
  * @returns source code
7133
7148
  */
7134
7149
  grabSource(): Promise<string>;
7150
+ /**
7151
+ * Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
7152
+ * The format matches Playwright's [ARIA snapshots](https://playwright.dev/docs/aria-snapshots).
7153
+ *
7154
+ * ```js
7155
+ * const snapshot = await I.grabAriaSnapshot();
7156
+ * const formSnapshot = await I.grabAriaSnapshot('#login-form');
7157
+ * ```
7158
+ * @param [locator = '//body'] - element located by CSS|XPath|strict locator. Defaults to body element.
7159
+ * @returns YAML representation of the accessibility tree
7160
+ */
7161
+ grabAriaSnapshot(locator?: string | any): Promise<string>;
7135
7162
  /**
7136
7163
  * Get JS log from browser.
7137
7164
  *
@@ -8587,6 +8614,7 @@ declare namespace CodeceptJS {
8587
8614
  * ## Methods
8588
8615
  */
8589
8616
  class WebDriverTs {
8617
+ capabilities: CodeceptJS.HelperCapabilities;
8590
8618
  /**
8591
8619
  * Use [webdriverio](https://webdriver.io/docs/api.html) API inside a test.
8592
8620
  *
@@ -1225,7 +1225,7 @@ declare namespace CodeceptJS {
1225
1225
  * @property [headers = {}] - headers sent when connecting to the endpoint, e.g. for authenticated remote browsers.
1226
1226
  * @property [input = auto] - how actions are dispatched: `cdp` (real mouse and keyboard events) or `synthetic` (DOM events). `auto` picks `cdp` when the browser renders layout.
1227
1227
  * @property [xpathPolyfill = auto] - inject an XPath polyfill for browsers with incomplete XPath support. `auto` detects when it is needed.
1228
- * @property [capabilities = {}] - browser capabilities (`layout`, `xpath`, `screenshot`, `innerText`) to use instead of detecting them at runtime.
1228
+ * @property [capabilities = {}] - browser capabilities (`layout`, `xpath`, `screenshot`, `video`, `innerText`, `aria`) to use instead of detecting them at runtime.
1229
1229
  * @property [waitForTimeout = 5] - default timeout for wait* actions, in seconds.
1230
1230
  * @property [waitForAction] - fixed delay after each action, in milliseconds. When unset, actions wait only for the navigation they trigger.
1231
1231
  * @property [pollInterval = 25] - interval between checks while waiting, in milliseconds.
@@ -1277,6 +1277,7 @@ declare namespace CodeceptJS {
1277
1277
  */
1278
1278
  class CDPBrowser {
1279
1279
  constructor(config: CDPBrowserConfig);
1280
+ capabilities: CodeceptJS.HelperCapabilities;
1280
1281
  /**
1281
1282
  * Opts a subclass into managing its own browser server process. Called from a subclass
1282
1283
  * constructor with the raw user config and a server descriptor:
@@ -1435,6 +1436,18 @@ declare namespace CodeceptJS {
1435
1436
  * @returns source code
1436
1437
  */
1437
1438
  grabSource(): Promise<string>;
1439
+ /**
1440
+ * Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
1441
+ * The format matches Playwright's [ARIA snapshots](https://playwright.dev/docs/aria-snapshots).
1442
+ *
1443
+ * ```js
1444
+ * const snapshot = await I.grabAriaSnapshot();
1445
+ * const formSnapshot = await I.grabAriaSnapshot('#login-form');
1446
+ * ```
1447
+ * @param [locator = '//body'] - element located by CSS|XPath|strict locator. Defaults to body element.
1448
+ * @returns YAML representation of the accessibility tree
1449
+ */
1450
+ grabAriaSnapshot(locator?: string | any): Promise<string>;
1438
1451
  /**
1439
1452
  * Checks that a page contains a visible text.
1440
1453
  * Use context parameter to narrow down the search.
@@ -4027,6 +4040,7 @@ declare namespace CodeceptJS {
4027
4040
  * ```
4028
4041
  */
4029
4042
  class Playwright {
4043
+ capabilities: CodeceptJS.HelperCapabilities;
4030
4044
  /**
4031
4045
  * Use Playwright API inside a test.
4032
4046
  *
@@ -6326,6 +6340,7 @@ declare namespace CodeceptJS {
6326
6340
  * ## Methods
6327
6341
  */
6328
6342
  class Puppeteer {
6343
+ capabilities: CodeceptJS.HelperCapabilities;
6329
6344
  /**
6330
6345
  * Use Puppeteer API inside a test.
6331
6346
  *
@@ -7370,6 +7385,18 @@ declare namespace CodeceptJS {
7370
7385
  * @returns source code
7371
7386
  */
7372
7387
  grabSource(): Promise<string>;
7388
+ /**
7389
+ * Retrieves the ARIA snapshot of the page, or of an element, built from the browser accessibility tree.
7390
+ * The format matches Playwright's [ARIA snapshots](https://playwright.dev/docs/aria-snapshots).
7391
+ *
7392
+ * ```js
7393
+ * const snapshot = await I.grabAriaSnapshot();
7394
+ * const formSnapshot = await I.grabAriaSnapshot('#login-form');
7395
+ * ```
7396
+ * @param [locator = '//body'] - element located by CSS|XPath|strict locator. Defaults to body element.
7397
+ * @returns YAML representation of the accessibility tree
7398
+ */
7399
+ grabAriaSnapshot(locator?: string | any): Promise<string>;
7373
7400
  /**
7374
7401
  * Get JS log from browser.
7375
7402
  *
@@ -8868,6 +8895,7 @@ declare namespace CodeceptJS {
8868
8895
  * ## Methods
8869
8896
  */
8870
8897
  class WebDriver {
8898
+ capabilities: CodeceptJS.HelperCapabilities;
8871
8899
  /**
8872
8900
  * Use [webdriverio](https://webdriver.io/docs/api.html) API inside a test.
8873
8901
  *