@cepharum/contextual-gherkin 3.0.0 → 4.0.0

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/index.d.ts CHANGED
@@ -1,17 +1,29 @@
1
1
  declare module "@cepharum/contextual-gherkin" {
2
- import {Browser, BrowserContextOptions, Expect, Mouse} from "@playwright/test";
2
+ import {Browser, BrowserContextOptions, Expect, LaunchOptions, Locator, Mouse} from "@playwright/test";
3
+
4
+ type PlaywrightActualBrowserName = "chromium" | "firefox" | "webkit";
5
+
6
+ type PlaywrightSupportedBrowserName = PlaywrightActualBrowserName | "chrome" | "safari" | "edge";
3
7
 
4
8
  /**
5
9
  * Exposes helper functions for conveniently integrating contextual-gherkin
6
10
  * with different frameworks for running tests.
7
11
  */
8
- const use = {
12
+ namespace use {
9
13
  /**
10
14
  * Generates adapter for running tests based on contextual-gherkin with
11
- * playwright as test runner. The returned promise resolves with an
12
- * adapter suitable for use with function ContextualGherkin().
13
- */
14
- async playwright(): Promise<PlaywrightAdapter> {}
15
+ * playwright. The returned promise resolves with an adapter suitable
16
+ * for use with function ContextualGherkin().
17
+ *
18
+ * @param browserName name of browser to use, defaults to "chromium"
19
+ * @param browserOptions options used on launching the selected browser
20
+ * @param contextOptions options used on creating (another) context in selected browser
21
+ */
22
+ function playwright(
23
+ browserName?: PlaywrightSupportedBrowserName,
24
+ browserOptions?: LaunchOptions,
25
+ contextOptions?: BrowserContextOptions
26
+ ): Promise<PlaywrightAdapter>;
15
27
  }
16
28
 
17
29
  /**
@@ -29,13 +41,13 @@ declare module "@cepharum/contextual-gherkin" {
29
41
  * @param adapter interface for interacting with a browser instance
30
42
  * @returns promise for instance of contextual-gherkin
31
43
  */
32
- async function ContextualGherkin(configuration?: Configuration, adapter?: BrowserAdapter): Promise<Api>;
44
+ function ContextualGherkin(configuration?: Configuration, adapter?: BrowserAdapter): Promise<Api>;
33
45
 
34
46
  /**
35
47
  * Implements singleton API instance for interacting with contextual-gherkin
36
48
  * in current runtime.
37
49
  */
38
- class Api<B = BrowserAdapter<C, A>, C = AbstractContext, A = Assertions> {
50
+ class Api<C = AbstractContext, A = Assertions, B = BrowserAdapter<C, A>> {
39
51
  /**
40
52
  * Creates singleton instance of contextual-gherkin API in current
41
53
  * runtime on first invocation or augments configuration of existing
@@ -44,13 +56,13 @@ declare module "@cepharum/contextual-gherkin" {
44
56
  * @param config configuration of singleton instance, gets merged with previously provided configuration
45
57
  * @param browser adapter for interacting with a browser, required on first invocation, rejected on succeeding invocations
46
58
  */
47
- static async setup( config: Configuration, browser?: B ): Promise<Api<C, A, B>>;
59
+ static setup<C = AbstractContext, A = Assertions, B = BrowserAdapter<C, A>>( config: Configuration, browser?: B ): Promise<Api<C, A, B>>;
48
60
 
49
61
  /**
50
62
  * Provides singleton instance of current runtime's contextual-gherkin
51
63
  * API for interacting with content of one or more browser views.
52
64
  */
53
- static access<BA = B, AC = C, AS = A>(): Api<BA, AC, AS>;
65
+ static access<C = AbstractContext, A = Assertions, B = BrowserAdapter<C, A>>(): Api<C, A, B>;
54
66
 
55
67
  /**
56
68
  * Exposes normalized configuration of contextual-gherkin.
@@ -85,13 +97,13 @@ declare module "@cepharum/contextual-gherkin" {
85
97
  /**
86
98
  * Explicitly creates view with provided name.
87
99
  *
88
- * @param name name of view to create
89
- * @param sharedSession if true, created view shares its session with current one (e.g. having same user authenticated)
90
- * @param select if true, created view is implicitly selected to be current one in follow-up interactions
100
+ * @param name name of view to create, "default" when omitted
101
+ * @param sharedSession if true, created view shares its session with current one (e.g. having same user authenticated), defaults to true
102
+ * @param select if true, created view is implicitly selected to be current one in follow-up interactions, defaults to false
91
103
  * @returns promise for context to interact with named view
92
104
  * @throws TypeError if named view has been created before
93
105
  */
94
- async createView( name: string = "default", sharedSession: boolean = true, select: boolean = false ): Promise<C>;
106
+ createView( name: string, sharedSession: boolean, select: boolean ): Promise<C>;
95
107
 
96
108
  /**
97
109
  * Fetches view by its name, creating it if necessary.
@@ -100,10 +112,10 @@ declare module "@cepharum/contextual-gherkin" {
100
112
  * current view. Use @see Api#createView() to create a view with a
101
113
  * dedicated session.
102
114
  *
103
- * @param name name of view to fetch
115
+ * @param name name of view to fetch, "default" when omitted
104
116
  * @returns promise for context to interact with named view
105
117
  */
106
- async getViewByName( name: string = "default" ): Promise<C>;
118
+ getViewByName( name?: string ): Promise<C>;
107
119
 
108
120
  /**
109
121
  * Fetches view by its name, creating it if necessary, and selects it as
@@ -113,10 +125,10 @@ declare module "@cepharum/contextual-gherkin" {
113
125
  * current view. Use @see Api#createView() to create a view with a
114
126
  * dedicated session.
115
127
  *
116
- * @param name name of view to select
128
+ * @param name name of view to select, "default" when omitted
117
129
  * @returns promise for context to interact with named view
118
130
  */
119
- async selectViewByName( name: string = "default" ): Promise<C>;
131
+ selectViewByName( name?: string ): Promise<C>;
120
132
 
121
133
  /**
122
134
  * Clears histories of all currently managed views.
@@ -168,7 +180,7 @@ declare module "@cepharum/contextual-gherkin" {
168
180
  *
169
181
  * @returns promise resolved when test runner has been resumed
170
182
  */
171
- async debug(): Promise<void>;
183
+ debug(): Promise<void>;
172
184
 
173
185
  /**
174
186
  * Creates promise resolved after giving number of milliseconds.
@@ -176,7 +188,7 @@ declare module "@cepharum/contextual-gherkin" {
176
188
  * @param ms number of milliseconds to wait before resolving returned promise
177
189
  * @returns promise resolved after given number of milliseconds
178
190
  */
179
- async wait( ms: number ): Promise<void>;
191
+ wait( ms: number ): Promise<void>;
180
192
 
181
193
  /**
182
194
  * Gets all aliases of provided type name.
@@ -242,13 +254,13 @@ declare module "@cepharum/contextual-gherkin" {
242
254
  * @param shareSessionWith provides reference on a previously created view's context to share session with
243
255
  * @returns promise created view's context
244
256
  */
245
- async createView( api: Api<BrowserAdapter, C>, shareSessionWith?: C ): Promise<C>;
257
+ createView( api: Api<BrowserAdapter, C>, shareSessionWith?: C ): Promise<C>;
246
258
 
247
259
  /**
248
260
  * Destructs connection to browser by means of closing the controlled
249
261
  * browser invalidating all its views implicitly.
250
262
  */
251
- async disconnect(): Promise<void>;
263
+ disconnect(): Promise<void>;
252
264
 
253
265
  /**
254
266
  * Compiles set of methods available for triggering actions on elements
@@ -256,12 +268,12 @@ declare module "@cepharum/contextual-gherkin" {
256
268
  *
257
269
  * @param locator description of elements resulting actions are performed on
258
270
  */
259
- async getActions( locator: any ): Promise<Actions>;
271
+ getActions( locator: any ): Promise<Actions>;
260
272
 
261
273
  /**
262
274
  * Provides assertions library for assessing state of elements.
263
275
  */
264
- async getAssertions(): Promise<() => A>;
276
+ getAssertions(): Promise<() => A>;
265
277
  }
266
278
 
267
279
  /**
@@ -271,7 +283,7 @@ declare module "@cepharum/contextual-gherkin" {
271
283
  constructor( browser: PlaywrightBrowser, contextOptions?: PlaywrightBrowserContextOptions );
272
284
 
273
285
  /** @inheritDoc */
274
- async createView( api: Api<PlaywrightAdapter, PlaywrightContext>, shareSessionWith: PlaywrightContext = undefined ): Promise<PlaywrightContext>;
286
+ createView( api: Api<PlaywrightAdapter, PlaywrightContext>, shareSessionWith?: PlaywrightContext ): Promise<PlaywrightContext>;
275
287
  }
276
288
 
277
289
  /**
@@ -513,7 +525,7 @@ declare module "@cepharum/contextual-gherkin" {
513
525
  subIndex?: number;
514
526
  }
515
527
 
516
- /**
528
+ /**
517
529
  * Defines common API of a context.
518
530
  *
519
531
  * Every context is managing a set of elements in the document of a connected
@@ -523,18 +535,19 @@ declare module "@cepharum/contextual-gherkin" {
523
535
  * Contexts can be tracked and recovered to implement follow-up queries and
524
536
  * actions.
525
537
  */
538
+ // @ts-ignore
526
539
  abstract class AbstractContext<C = AbstractContext> {
527
540
  /**
528
541
  * @param framework names the framework this context is working with
529
542
  * @param source context this instance is starting as a duplicate of
530
543
  */
531
- constructor( framework: ContextFramework, source?: T );
544
+ constructor( framework: ContextFramework, source?: C );
532
545
 
533
546
  /**
534
547
  * Provides history of recently queried elements tracked per type of
535
548
  * element.
536
549
  */
537
- history: ContextHistoryByElementType<T>;
550
+ history: ContextHistoryByElementType<C>;
538
551
 
539
552
  /**
540
553
  * Names framework current context is used to interact with a connected
@@ -554,7 +567,7 @@ declare module "@cepharum/contextual-gherkin" {
554
567
  * It usually addresses ascendants of current context's set of matching
555
568
  * elements.
556
569
  */
557
- parent?: Context;
570
+ parent?: C;
558
571
 
559
572
  /**
560
573
  * Exposes singular form of type name used to pick a query for
@@ -662,7 +675,7 @@ declare module "@cepharum/contextual-gherkin" {
662
675
  * @param defaultSelector selector to use in case none has been configured for the given type
663
676
  * @returns another context representing all matching elements found as descendants of elements in current context
664
677
  */
665
- find( typeOfElement: string, defaultSelector?: SimpleSelector ): Context;
678
+ find( typeOfElement: string, defaultSelector?: SimpleSelector ): AbstractContext;
666
679
 
667
680
  /**
668
681
  * Reduces current set of matching elements to the one at given index.
@@ -674,21 +687,46 @@ declare module "@cepharum/contextual-gherkin" {
674
687
  * @param index non-nullish index into current context's set of matching elements to pick
675
688
  * @returns another context representing that selected element, only, current context if index is nullish
676
689
  */
677
- nth( index: number|null ): Context;
690
+ nth( index: number|null ): AbstractContext;
678
691
 
679
692
  /**
680
- * Reduces current context's set of matching elements to those matching
681
- * another selector for given type of element.
693
+ * Limits current set of matching elements to those also matching the
694
+ * selector configured for a given element type, intersecting the current
695
+ * set rather than searching descendants.
682
696
  *
683
- * @note In opposition to filter(), this function isn't descending into
684
- * the hierarchy of elements but inspects currently matching
685
- * elements, only.
697
+ * @param typeOfElement type of element to intersect current matches with
698
+ * @param defaultSelector selector to use if none has been configured for the named type of elements
699
+ * @returns another context representing only those matching elements of current context that also match selector of given type
700
+ */
701
+ filterByType( typeOfElement: string, defaultSelector?: SimpleSelector ): AbstractContext;
702
+
703
+ /**
704
+ * Limits current set of matching elements to those also matching a given
705
+ * selector, intersecting the current set rather than searching descendants.
686
706
  *
687
- * @param typeOfElement type of element to reduce matches to
707
+ * @param selector selector string to intersect current matches with
708
+ * @returns another context representing only those matching elements of current context that also match given selector
709
+ */
710
+ filterBySelector( selector: string ): AbstractContext;
711
+
712
+ /**
713
+ * Limits current set of matching elements to those containing a descendant
714
+ * matching the selector configured for a given element type.
715
+ *
716
+ * @param typeOfElement type of element to look for in descendants
688
717
  * @param defaultSelector selector to use if none has been configured for the named type of elements
689
- * @returns another context representing only those matching elements of current context that match selector of given name, too
718
+ * @returns another context representing only those matching elements of current context that contain a descendant of given type
719
+ */
720
+ filterBySubType( typeOfElement: string, defaultSelector?: SimpleSelector ): AbstractContext;
721
+
722
+ /**
723
+ * Limits current set of matching elements to those containing a descendant
724
+ * matching a given selector.
725
+ *
726
+ * @param selector selector string to look for in descendants
727
+ * @returns another context representing only those matching elements of current context that contain a descendant matching given selector
690
728
  */
691
- filter( typeOfElement: string, defaultSelector?: SimpleSelector ): Context;
729
+ filterBySubSelector( selector: string ): AbstractContext;
692
730
 
693
731
  /**
694
732
  * Reduces current context's set of matching elements to those marked as
@@ -704,7 +742,7 @@ declare module "@cepharum/contextual-gherkin" {
704
742
  * @param closureScope set of simple values to be provided as closure scope to invoked callback
705
743
  * @returns another context representing only those matching elements of current context that cause provided callback to return truthy
706
744
  */
707
- filterFn( fn: SelectorFn, closureScope?: { [key: string]: any } ): Context;
745
+ filterFn( fn: SelectorFn, closureScope?: { [key: string]: any } ): AbstractContext;
708
746
 
709
747
  /**
710
748
  * Reduces current context's set of matching elements to those having
@@ -728,7 +766,7 @@ declare module "@cepharum/contextual-gherkin" {
728
766
  * @param closureScope set of simple values to be provided as closure scope to invoked callback
729
767
  * @returns another context representing only those matching elements of current context that have children causing provided callback to return truthy
730
768
  */
731
- filterBySubsWithFn( typeOfSub: string, defaultSelector: SimpleSelector, fn: SelectorFn, closureScope?: { [key: string]: any } ): Context;
769
+ filterBySubsWithFn( typeOfSub: string, defaultSelector: SimpleSelector, fn: SelectorFn, closureScope?: { [key: string]: any } ): AbstractContext;
732
770
 
733
771
  /**
734
772
  * Implements a convenient helper to filter current set of matching
@@ -741,7 +779,7 @@ declare module "@cepharum/contextual-gherkin" {
741
779
  * @param partially if true, given text or regular expression is expected to be a part of a child's normalized textual content, only
742
780
  * @returns another context limited to those matching elements of current context that have children with a given text
743
781
  */
744
- filterBySubsWithText( typeOfSub: string, defaultSelector: SimpleSelector, text: string|RegExp, partially?: boolean ): Context;
782
+ filterBySubsWithText( typeOfSub: string, defaultSelector: SimpleSelector, text: string|RegExp, partially?: boolean ): AbstractContext;
745
783
 
746
784
  /**
747
785
  * Limits set of matching elements to those with a named attribute
@@ -751,7 +789,7 @@ declare module "@cepharum/contextual-gherkin" {
751
789
  * @param value value to expect in a matching element's attribute
752
790
  * @returns another context with all those elements of current one which have a matching value in named attribute
753
791
  */
754
- withAttribute( name: string, value: string|RegExp|boolean ): Context;
792
+ withAttribute( name: string, value: string|RegExp|boolean ): AbstractContext;
755
793
 
756
794
  /**
757
795
  * Limits set of matching elements to those with a named DOM property
@@ -768,7 +806,7 @@ declare module "@cepharum/contextual-gherkin" {
768
806
  * @param value value to expect in a matching element's DOM property, use callback invoked with found value to return truthy on a match
769
807
  * @returns another context with all those elements of current one which have a matching value in named DOM property
770
808
  */
771
- withProperty( name: string, value: string|RegExp|boolean|SelectorFn ): Context;
809
+ withProperty( name: string, value: string|RegExp|boolean|SelectorFn ): AbstractContext;
772
810
 
773
811
  /**
774
812
  * Limits set of matching elements to those with a named DOM property
@@ -777,10 +815,10 @@ declare module "@cepharum/contextual-gherkin" {
777
815
  *
778
816
  * @param name name of DOM property to inspect, might be mapped internally according to selectors configuration
779
817
  * @param value value to expect in a matching element's DOM property, use callback invoked with found value to return truthy on a match
780
- * @param negated if true, value must not be included with any named property of currently matching elements
818
+ * @param negated if true, value must not be included with any named property of currently matching elements, false by default
781
819
  * @returns another context with all those elements of current one which have a matching value in named DOM property
782
820
  */
783
- withListProperty( name: string, value: string, negated: boolean = false ): Context;
821
+ withListProperty( name: string, value: string, negated?: boolean ): AbstractContext;
784
822
 
785
823
  /**
786
824
  * Detaches current context from its original query used to address
@@ -792,7 +830,7 @@ declare module "@cepharum/contextual-gherkin" {
792
830
  *
793
831
  * @param cardinality cardinality of resulting context
794
832
  */
795
- detach( cardinality?: Cardinality ): Promise<Context>;
833
+ detach( cardinality?: Cardinality ): Promise<AbstractContext>;
796
834
 
797
835
  /**
798
836
  * Tracks detached version of current context in history of contexts for
@@ -812,7 +850,7 @@ declare module "@cepharum/contextual-gherkin" {
812
850
  * @param cardinality selects expected number of elements in match to find
813
851
  * @returns previously tracked context matching parameters
814
852
  */
815
- getTracked( typeOfElement, index, cardinality = null ): Context;
853
+ getTracked( typeOfElement, index, cardinality? ): AbstractContext;
816
854
 
817
855
  /**
818
856
  * Looks up runtime configuration for a selector matching provided
@@ -830,11 +868,11 @@ declare module "@cepharum/contextual-gherkin" {
830
868
  * provided data extracted from a {cardinal-word} expression.
831
869
  *
832
870
  * @param cardinal data of an encountered {cardinal-word} expression
833
- * @param track controls if current context should be tracked in history after passing check
834
- * @param message custom message to display if check fails
871
+ * @param track controls if current context should be tracked in history after passing check, true by default
872
+ * @param message custom message to display if check fails, "expecting %amount" by default
835
873
  * @returns promise resolved when check has passed and context has been optionally tracked
836
874
  */
837
- checkCardinalWord(cardinal: NumberAndWord, track: boolean = true, message: string = "expecting %amount" ): Promise<void>;
875
+ checkCardinalWord(cardinal: NumberAndWord, track?: boolean, message?: string ): Promise<void>;
838
876
 
839
877
  /**
840
878
  * Conveniently asserts that some or all matching elements of current
@@ -850,11 +888,11 @@ declare module "@cepharum/contextual-gherkin" {
850
888
  *
851
889
  * @param filteredContext another context of matching elements to compare with current one
852
890
  * @param contextualWord parsed instance of `{contextual-word}` used to fetch current context from history
853
- * @param requireAll if true, provided context has to list all elements of current context, otherwise it has to list at least one element
854
- * @param track if true, this context is tracked if it has been reduced after fetching it from context due to provided `phrase`
891
+ * @param requireAll if true, provided context has to list all elements of current context, otherwise it has to list at least one element, true by default
892
+ * @param track if true, this context is tracked if it has been reduced after fetching it from context due to provided `phrase`, true by default
855
893
  * @returns promise resolved when check has passed and context has been optionally tracked in history
856
894
  */
857
- checkFilteredInContext( filteredContext: Context, contextualWord: ContextualWord, requireAll: boolean = true, track: boolean = true ): Promise<void>;
895
+ checkFilteredInContext( filteredContext: AbstractContext, contextualWord: ContextualWord, requireAll?: boolean, track?: boolean ): Promise<void>;
858
896
  }
859
897
 
860
898
  /**
@@ -908,7 +946,7 @@ declare module "@cepharum/contextual-gherkin" {
908
946
  *
909
947
  * @param target context addressing target element(s) is/are dragged to
910
948
  */
911
- dragTo(target: context): Promise<void>;
949
+ dragTo(target: AbstractContext): Promise<void>;
912
950
 
913
951
  /**
914
952
  * Dispatches custom event to elements matching current context.
@@ -992,7 +1030,7 @@ declare module "@cepharum/contextual-gherkin" {
992
1030
  * Provides the locator used to query a connected browser's page for
993
1031
  * matching elements.
994
1032
  */
995
- locator: Locator;
1033
+ locator: PlaywrightLocator;
996
1034
  }
997
1035
 
998
1036
  // re-define some playwright types with a custom name so for using it in
@@ -1003,32 +1041,32 @@ declare module "@cepharum/contextual-gherkin" {
1003
1041
 
1004
1042
  type Action = "click" | "hover" | "enter";
1005
1043
 
1006
- async function globalFind( cardinal: NumberAndWord ): Promise<void>;
1007
- async function globalFindByAttribute( cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1008
- async function globalFindByProperty( cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1009
- async function globalFindByClass( cardinal: NumberAndWord, className: string, negated: boolean ): Promise<void>;
1010
- async function globalFindByLabel( cardinal: NumberAndWord, label: string, partially: boolean ): Promise<void>;
1011
- async function globalFindByTextContent( cardinal: NumberAndWord, text: string, partially: boolean ): Promise<void>;
1012
-
1013
- async function globalActionByAttribute( cardinal: NumberAndWord, name: string, value: string|RegExp, action: Action, input?: string ): Promise<void>;
1014
- async function globalActionByProperty( cardinal: NumberAndWord, name: string, value: string|RegExp, action: Action, input?: string ): Promise<void>;
1015
- async function globalActionByClass( cardinal: NumberAndWord, className: string, negated?: boolean, action: Action, input?: string ): Promise<void>;
1016
- async function globalActionByLabel( cardinal: NumberAndWord, label: string, partially: boolean, action: Action, input?: string ): Promise<void>;
1017
- async function globalActionByTextContent( cardinal: NumberAndWord, text: string, partially: boolean, action: Action, input?: string ): Promise<void>;
1018
-
1019
- async function localFind( phrase: ContextualWord, cardinal: NumberAndWord ): Promise<void>;
1020
- async function localFindByAttribute( phrase: ContextualWord, cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1021
- async function localFindByProperty( phrase: ContextualWord, cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1022
- async function localFindByClass( phrase: ContextualWord, cardinal: NumberAndWord, className: string, negated: boolean ): Promise<void>;
1023
- async function localFindByLabel( phrase: ContextualWord, cardinal: NumberAndWord, label: string, partially: boolean ): Promise<void>;
1024
- async function localFindByTextContent( phrase: ContextualWord, cardinal: NumberAndWord, text: string, partially: boolean ): Promise<void>;
1025
-
1026
- async function localAction( phrase: ContextualWord, action: Action, input?: string ): Promise<void>;
1027
-
1028
- async function localStateByAttribute( phrase: ContextualWord, all: boolean, name: string, value: string|RegExp ): Promise<void>;
1029
- async function localStateByProperty( phrase: ContextualWord, all: boolean, name: string, value: string|RegExp ): Promise<void>;
1030
- async function localStateByClass( phrase: ContextualWord, all: boolean, className: string, negated: boolean ): Promise<void>;
1031
- async function localStateByLabel( phrase: ContextualWord, label: string, partially: boolean ): Promise<void>;
1032
- async function localStateByTextContent( phrase: ContextualWord, text: string, partially: boolean ): Promise<void>;
1033
- async function localStateExists( phrase: ContextualWord, mustExist: boolean ): Promise<void>;
1044
+ function globalFind( cardinal: NumberAndWord ): Promise<void>;
1045
+ function globalFindByAttribute( cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1046
+ function globalFindByProperty( cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1047
+ function globalFindByClass( cardinal: NumberAndWord, className: string, negated: boolean ): Promise<void>;
1048
+ function globalFindByLabel( cardinal: NumberAndWord, label: string, partially: boolean ): Promise<void>;
1049
+ function globalFindByTextContent( cardinal: NumberAndWord, text: string, partially: boolean ): Promise<void>;
1050
+
1051
+ function globalActionByAttribute( cardinal: NumberAndWord, name: string, value: string|RegExp, action: Action, input?: string ): Promise<void>;
1052
+ function globalActionByProperty( cardinal: NumberAndWord, name: string, value: string|RegExp, action: Action, input?: string ): Promise<void>;
1053
+ function globalActionByClass( cardinal: NumberAndWord, className: string, negated: boolean, action: Action, input?: string ): Promise<void>;
1054
+ function globalActionByLabel( cardinal: NumberAndWord, label: string, partially: boolean, action: Action, input?: string ): Promise<void>;
1055
+ function globalActionByTextContent( cardinal: NumberAndWord, text: string, partially: boolean, action: Action, input?: string ): Promise<void>;
1056
+
1057
+ function localFind( phrase: ContextualWord, cardinal: NumberAndWord ): Promise<void>;
1058
+ function localFindByAttribute( phrase: ContextualWord, cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1059
+ function localFindByProperty( phrase: ContextualWord, cardinal: NumberAndWord, name: string, value: string|RegExp ): Promise<void>;
1060
+ function localFindByClass( phrase: ContextualWord, cardinal: NumberAndWord, className: string, negated: boolean ): Promise<void>;
1061
+ function localFindByLabel( phrase: ContextualWord, cardinal: NumberAndWord, label: string, partially: boolean ): Promise<void>;
1062
+ function localFindByTextContent( phrase: ContextualWord, cardinal: NumberAndWord, text: string, partially: boolean ): Promise<void>;
1063
+
1064
+ function localAction( phrase: ContextualWord, action: Action, input?: string ): Promise<void>;
1065
+
1066
+ function localStateByAttribute( phrase: ContextualWord, all: boolean, name: string, value: string|RegExp ): Promise<void>;
1067
+ function localStateByProperty( phrase: ContextualWord, all: boolean, name: string, value: string|RegExp ): Promise<void>;
1068
+ function localStateByClass( phrase: ContextualWord, all: boolean, className: string, negated: boolean ): Promise<void>;
1069
+ function localStateByLabel( phrase: ContextualWord, label: string, partially: boolean ): Promise<void>;
1070
+ function localStateByTextContent( phrase: ContextualWord, text: string, partially: boolean ): Promise<void>;
1071
+ function localStateExists( phrase: ContextualWord, mustExist: boolean ): Promise<void>;
1034
1072
  }
@@ -3,7 +3,7 @@ import { PlaywrightContext } from "../context/playwright.js";
3
3
  import { clientHelper } from "../support/playwright/client-helper.js";
4
4
 
5
5
  /**
6
- * @implements {BrowserAdapter}
6
+ * @extends {BrowserAdapter}
7
7
  */
8
8
  export class PlaywrightAdapter {
9
9
  /**
@@ -33,7 +33,7 @@ export class PlaywrightAdapter {
33
33
  }
34
34
 
35
35
  /**
36
- * @param {cgApi} api
36
+ * @param {Api} api
37
37
  * @param {PlaywrightContext} shareSessionWith
38
38
  */
39
39
  async createView( api, shareSessionWith = undefined ) {
package/lib/api.js CHANGED
@@ -84,7 +84,9 @@ export class Api {
84
84
  */
85
85
  static access() {
86
86
  if ( !singleton ) {
87
- throw new Error( "missing contextual-gherkin API ... see https://cepharum-foss.gitlab.io/contextual-gherkin/api/configuration.html" );
87
+ throw Object.assign( new Error( "missing contextual-gherkin API ... see https://cepharum-foss.gitlab.io/contextual-gherkin/api/configuration.html" ), {
88
+ missingContextualGherkin: true,
89
+ } );
88
90
  }
89
91
 
90
92
  return singleton;
package/lib/cli.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import File from "node:fs/promises";
2
- import OS from "node:os";
3
2
  import Path from "node:path";
4
3
  import { fileURLToPath, pathToFileURL } from "node:url";
5
4
 
@@ -13,25 +12,6 @@ export function getMyFolder() {
13
12
  return Path.resolve( fileURLToPath( import.meta.url ), "../.." );
14
13
  }
15
14
 
16
- /**
17
- * Gathers information on named file without throwing in case the file simply
18
- * does not exist.
19
- *
20
- * @param {string} filename name of file to inspect
21
- * @returns {Promise<Stats|null>} promise for found file's information, null if file is missing
22
- */
23
- export async function statFile( filename ) {
24
- try {
25
- return await File.stat( filename );
26
- } catch ( cause ) {
27
- if ( cause.code === "ENOENT" ) {
28
- return null;
29
- }
30
-
31
- throw cause;
32
- }
33
- }
34
-
35
15
  /**
36
16
  * Reads single package.json file.
37
17
  */
@@ -237,40 +217,6 @@ export function parseArguments( argv ) {
237
217
  };
238
218
  }
239
219
 
240
- /**
241
- * Inspects npm executable used to invoke cucumber-js.
242
- *
243
- * @paranm {Object<string,string>} env set of environment variables
244
- * @returns {Promise<Object<string,any>>} promise for options to properly spawn npm
245
- */
246
- export async function detectNpmOptions( env ) {
247
- const envPath = env.PATH ?? env.Path;
248
- const isWindows = OS.platform() === "win32";
249
-
250
- for ( const path of envPath.split( Path.delimiter ) ) {
251
- const candidate = Path.resolve( path, isWindows ? "npm.cmd" : "npm" );
252
- const npmStat = await statFile( candidate ); // eslint-disable-line no-await-in-loop
253
-
254
- if ( npmStat?.isFile() || npmStat?.isSymbolicLink() ) {
255
- const spawnOptions = {
256
- shell: candidate.endsWith( ".cmd" ),
257
- };
258
-
259
- if ( !spawnOptions.shell ) {
260
- const file = await File.readFile( candidate, "utf8" ); // eslint-disable-line no-await-in-loop
261
-
262
- if ( file.startsWith( "#!/" ) ) {
263
- spawnOptions.shell = true;
264
- }
265
- }
266
-
267
- return spawnOptions;
268
- }
269
- }
270
-
271
- return undefined;
272
- }
273
-
274
220
  /**
275
221
  * Inspects existing dependency @cucumber/cucumber for the pathname of script
276
222
  * implementing the CLI binary of cucumber.
@@ -171,25 +171,78 @@ export class PlaywrightContext extends AbstractContext {
171
171
  }
172
172
 
173
173
  /**
174
- * Limits current set of matches to those matching as a given type of
175
- * elements, too.
174
+ * Limits current set of matches to those also matching a given element
175
+ * type's selector, intersecting the current set rather than searching
176
+ * descendants.
176
177
  *
177
- * @param {string} typeOfElement names type of elements to focus on
178
+ * @param {string} typeOfElement names type of elements to intersect with
178
179
  * @param {SimpleSelector} defaultSelector selector to use as fallback
179
- * @returns {Context} node describing matches of filtering and their processing context
180
+ * @returns {Context} node describing the filtered set of elements
180
181
  */
181
- filter( typeOfElement, defaultSelector = undefined ) {
182
+ filterByType( typeOfElement, defaultSelector = undefined ) {
182
183
  const type = this.api.toNormalizedSingularName( typeOfElement );
183
184
  const { query, dependencies } = this.getSelector( type, defaultSelector );
184
185
 
185
186
  return new this.constructor( this, {
186
- locator: this.locator.filter( { has: this.createSubLocator( query, dependencies ) } ),
187
+ locator: this.locator.and( this.createSubLocator( query, dependencies, true ) ),
187
188
  type: this.type,
188
189
  selectors: this.selectors,
189
190
  cardinality: this.cardinality
190
191
  } );
191
192
  }
192
193
 
194
+ /**
195
+ * Limits current set of matches to those also matching a given selector,
196
+ * intersecting the current set rather than searching descendants.
197
+ *
198
+ * @param {string} selector selector string accepted by Playwright locators
199
+ * @returns {Context} node describing the filtered set of elements
200
+ */
201
+ filterBySelector( selector ) {
202
+ return new this.constructor( this, {
203
+ locator: this.locator.and( this.locator.page().locator( selector ) ),
204
+ type: this.type,
205
+ selectors: this.selectors,
206
+ cardinality: this.cardinality,
207
+ } );
208
+ }
209
+
210
+ /**
211
+ * Limits current set of matches to those containing a descendant matching
212
+ * a given element type's selector.
213
+ *
214
+ * @param {string} typeOfElement names type of elements to look for in descendants
215
+ * @param {SimpleSelector} defaultSelector selector to use as fallback
216
+ * @returns {Context} node describing the filtered set of elements
217
+ */
218
+ filterBySubType( typeOfElement, defaultSelector = undefined ) {
219
+ const type = this.api.toNormalizedSingularName( typeOfElement );
220
+ const { query, dependencies } = this.getSelector( type, defaultSelector );
221
+
222
+ return new this.constructor( this, {
223
+ locator: this.locator.filter( { has: this.createSubLocator( query, dependencies ) } ),
224
+ type: this.type,
225
+ selectors: this.selectors,
226
+ cardinality: this.cardinality,
227
+ } );
228
+ }
229
+
230
+ /**
231
+ * Limits current set of matches to those containing a descendant matching
232
+ * a given selector.
233
+ *
234
+ * @param {string} selector selector string accepted by Playwright locators
235
+ * @returns {Context} node describing the filtered set of elements
236
+ */
237
+ filterBySubSelector( selector ) {
238
+ return new this.constructor( this, {
239
+ locator: this.locator.filter( { has: this.locator.page().locator( selector ) } ),
240
+ type: this.type,
241
+ selectors: this.selectors,
242
+ cardinality: this.cardinality,
243
+ } );
244
+ }
245
+
193
246
  /**
194
247
  * Limits current set of matches to those picked by a given callback
195
248
  * function invoked in browser.
@@ -1,4 +1,4 @@
1
- import { firefox, chromium, webkit } from "playwright";
1
+ import { firefox, chromium, webkit } from "@playwright/test";
2
2
 
3
3
  import { PlaywrightAdapter } from "../../adapter/playwright.js";
4
4
  import { registerPlaywrightSelectors } from "./custom-selectors.js";
@@ -10,6 +10,8 @@ export async function registerPlaywrightSelectors() {
10
10
  registerAttributeSelector(),
11
11
  registerShadowQuerySelector(),
12
12
  registerMeSelector(),
13
+ registerWidthSelector(),
14
+ registerHeightSelector(),
13
15
  ] );
14
16
  }
15
17
 
@@ -141,6 +143,116 @@ export function registerShadowQuerySelector() {
141
143
  } ) );
142
144
  }
143
145
 
146
+ /**
147
+ * Registers custom selector engine `cg-width` for locating elements whose
148
+ * rendered width satisfies a numeric constraint.
149
+ *
150
+ * Query syntax: <value> exact match (px)
151
+ * >=<value> minimum width (px)
152
+ * <=<value> maximum width (px)
153
+ *
154
+ * When the engine root is an Element it is tested directly. When the root is
155
+ * a Document or ShadowRoot all descendant elements are searched instead.
156
+ */
157
+ export function registerWidthSelector() {
158
+ return selectors.register( "cg-width", () => ( {
159
+ // client function, runs in browser, can't reliably use shared code other than what is injected as init script
160
+ query( root, query ) {
161
+ const [ , op, value ] = /^(>=|<=)?(\d+(?:\.\d+)?)$/.exec( query ) || [];
162
+ if ( value == null ) {
163
+ throw new TypeError( "malformed query for matching elements by width" );
164
+ }
165
+
166
+ const target = parseFloat( value );
167
+ const test = node => {
168
+ const actual = node.getBoundingClientRect().width;
169
+ return op === ">=" ? actual >= target : op === "<=" ? actual <= target : actual === target;
170
+ };
171
+
172
+ if ( typeof root.getBoundingClientRect === "function" ) {
173
+ return test( root ) ? root : undefined;
174
+ }
175
+
176
+ return Array.from( root.querySelectorAll( "*" ) ).find( test );
177
+ },
178
+
179
+ // client function, runs in browser, can't reliably use shared code other than what is injected as init script
180
+ queryAll( root, query ) {
181
+ const [ , op, value ] = /^(>=|<=)?(\d+(?:\.\d+)?)$/.exec( query ) || [];
182
+ if ( value == null ) {
183
+ throw new TypeError( "malformed query for matching elements by width" );
184
+ }
185
+
186
+ const target = parseFloat( value );
187
+ const test = node => {
188
+ const actual = node.getBoundingClientRect().width;
189
+ return op === ">=" ? actual >= target : op === "<=" ? actual <= target : actual === target;
190
+ };
191
+
192
+ if ( typeof root.getBoundingClientRect === "function" ) {
193
+ return test( root ) ? [root] : [];
194
+ }
195
+
196
+ return Array.from( root.querySelectorAll( "*" ) ).filter( test );
197
+ },
198
+ } ) );
199
+ }
200
+
201
+ /**
202
+ * Registers custom selector engine `cg-height` for locating elements whose
203
+ * rendered height satisfies a numeric constraint.
204
+ *
205
+ * Query syntax: <value> exact match (px)
206
+ * >=<value> minimum height (px)
207
+ * <=<value> maximum height (px)
208
+ *
209
+ * When the engine root is an Element it is tested directly. When the root is
210
+ * a Document or ShadowRoot all descendant elements are searched instead.
211
+ */
212
+ export function registerHeightSelector() {
213
+ return selectors.register( "cg-height", () => ( {
214
+ // client function, runs in browser, can't reliably use shared code other than what is injected as init script
215
+ query( root, query ) {
216
+ const [ , op, value ] = /^(>=|<=)?(\d+(?:\.\d+)?)$/.exec( query ) || [];
217
+ if ( value == null ) {
218
+ throw new TypeError( "malformed query for matching elements by height" );
219
+ }
220
+
221
+ const target = parseFloat( value );
222
+ const test = node => {
223
+ const actual = node.getBoundingClientRect().height;
224
+ return op === ">=" ? actual >= target : op === "<=" ? actual <= target : actual === target;
225
+ };
226
+
227
+ if ( typeof root.getBoundingClientRect === "function" ) {
228
+ return test( root ) ? root : undefined;
229
+ }
230
+
231
+ return Array.from( root.querySelectorAll( "*" ) ).find( test );
232
+ },
233
+
234
+ // client function, runs in browser, can't reliably use shared code other than what is injected as init script
235
+ queryAll( root, query ) {
236
+ const [ , op, value ] = /^(>=|<=)?(\d+(?:\.\d+)?)$/.exec( query ) || [];
237
+ if ( value == null ) {
238
+ throw new TypeError( "malformed query for matching elements by height" );
239
+ }
240
+
241
+ const target = parseFloat( value );
242
+ const test = node => {
243
+ const actual = node.getBoundingClientRect().height;
244
+ return op === ">=" ? actual >= target : op === "<=" ? actual <= target : actual === target;
245
+ };
246
+
247
+ if ( typeof root.getBoundingClientRect === "function" ) {
248
+ return test( root ) ? [root] : [];
249
+ }
250
+
251
+ return Array.from( root.querySelectorAll( "*" ) ).filter( test );
252
+ },
253
+ } ) );
254
+ }
255
+
144
256
  /**
145
257
  * Registers custom selector for locating current root element itself primarily
146
258
  * to feature its combination with other locators.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cepharum/contextual-gherkin",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "flexible step definitions for Gherkin",
5
5
  "author": "cepharum GmbH <thomas.urban@cepharum.de>",
6
6
  "homepage": "https://cepharum-foss.gitlab.io/contextual-gherkin/",
@@ -11,7 +11,15 @@ Then( "I debug", { timeout: -1 }, debug );
11
11
  Then( "I pause", { timeout: -1 }, debug );
12
12
 
13
13
  // make sure to disconnect the browser after testing
14
- AfterAll( () => Api.access().browser.disconnect() );
14
+ AfterAll( async() => {
15
+ try {
16
+ await Api.access().browser.disconnect();
17
+ } catch ( cause ) {
18
+ if ( !cause.missingContextualGherkin ) {
19
+ throw cause;
20
+ }
21
+ }
22
+ } );
15
23
 
16
24
  After( () => {
17
25
  Api.access().clearHistories();