pw-element-interactions 0.0.4 → 0.0.6

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.
@@ -1,6 +1,6 @@
1
1
  import { Page } from '@playwright/test';
2
2
  import { ElementRepository } from 'pw-element-repository';
3
- import { DropdownSelectOptions } from '../interactions/Interaction';
3
+ import { DropdownSelectOptions, TextVerifyOptions, CountVerifyOptions, DragAndDropOptions } from '../enum/Options';
4
4
  /**
5
5
  * The `Steps` class serves as a unified Facade for test orchestration.
6
6
  * It combines element acquisition (via `pw-element-repository`) with
@@ -12,52 +12,87 @@ export declare class Steps {
12
12
  private repo;
13
13
  private interact;
14
14
  private navigate;
15
+ private extract;
15
16
  private verify;
17
+ private utils;
16
18
  /**
17
19
  * Initializes the Steps class with the required Playwright page and element repository.
18
- * * @param page - The current Playwright Page object.
20
+ * @param page - The current Playwright Page object.
19
21
  * @param repo - An initialized instance of `ElementRepository` containing your locators.
22
+ * @param timeout - Optional global timeout override (in milliseconds).
20
23
  */
21
- constructor(page: Page, repo: ElementRepository);
24
+ constructor(page: Page, repo: ElementRepository, timeout?: number);
22
25
  /**
23
26
  * Navigates the browser to the specified URL.
24
- * * @param url - The absolute or relative URL to navigate to.
27
+ * @param url - The absolute or relative URL to navigate to.
25
28
  */
26
29
  navigateTo(url: string): Promise<void>;
27
30
  /**
28
31
  * Reloads the current page.
29
32
  */
30
33
  refresh(): Promise<void>;
34
+ /**
35
+ * Navigates the browser history stack either backwards or forwards.
36
+ * Mirrors the behavior of the browser's native Back and Forward buttons.
37
+ * @param direction - The direction to move in history: either 'BACKWARDS' or 'FORWARDS'.
38
+ */
39
+ backOrForward(direction: 'BACKWARDS' | 'FORWARDS'): Promise<void>;
40
+ /**
41
+ * Resizes the browser viewport to the specified dimensions.
42
+ * Useful for simulating different device screen sizes or responsive breakpoints.
43
+ * @param width - The desired width of the viewport in pixels.
44
+ * @param height - The desired height of the viewport in pixels.
45
+ */
46
+ setViewport(width: number, height: number): Promise<void>;
31
47
  /**
32
48
  * Retrieves an element from the repository and performs a standard click.
33
- * * @param pageName - The page or component grouping name in your repository.
49
+ * @param pageName - The page or component grouping name in your repository.
34
50
  * @param elementName - The specific element name in your repository.
35
51
  */
36
52
  click(pageName: string, elementName: string): Promise<void>;
53
+ /**
54
+ * Retrieves an element and dispatches a native 'click' event directly to it.
55
+ * Bypasses default scrolling and intersection checks. Useful for obscured elements.
56
+ * @param pageName - The page or component grouping name in your repository.
57
+ * @param elementName - The specific element name in your repository.
58
+ */
59
+ clickWithoutScrolling(pageName: string, elementName: string): Promise<void>;
37
60
  /**
38
61
  * Retrieves a random element from a resolved list of locators and clicks it.
39
62
  * Useful for clicking random items in a list or grid (e.g., product cards).
40
- * * @param pageName - The page or component grouping name in your repository.
63
+ * @param pageName - The page or component grouping name in your repository.
41
64
  * @param elementName - The specific element name in your repository representing multiple elements.
42
65
  */
43
66
  clickRandom(pageName: string, elementName: string): Promise<void>;
44
67
  /**
45
68
  * Retrieves an element and clicks it only if it is visible.
46
69
  * Prevents test failures on optional elements like cookie banners or promotional pop-ups.
47
- * * @param pageName - The page or component grouping name in your repository.
70
+ * @param pageName - The page or component grouping name in your repository.
48
71
  * @param elementName - The specific element name in your repository.
49
72
  */
50
73
  clickIfPresent(pageName: string, elementName: string): Promise<void>;
74
+ /**
75
+ * Retrieves an element and hovers over it. Useful for triggering dropdowns or tooltips.
76
+ * @param pageName - The page or component grouping name in your repository.
77
+ * @param elementName - The specific element name in your repository.
78
+ */
79
+ hover(pageName: string, elementName: string): Promise<void>;
80
+ /**
81
+ * Retrieves an element and scrolls it into view if it is not already visible.
82
+ * @param pageName - The page or component grouping name in your repository.
83
+ * @param elementName - The specific element name in your repository.
84
+ */
85
+ scrollIntoView(pageName: string, elementName: string): Promise<void>;
51
86
  /**
52
87
  * Retrieves an input field and fills it with the provided text, replacing any existing value.
53
- * * @param pageName - The page or component grouping name in your repository.
88
+ * @param pageName - The page or component grouping name in your repository.
54
89
  * @param elementName - The specific element name in your repository.
55
90
  * @param text - The text to type into the input field.
56
91
  */
57
92
  fill(pageName: string, elementName: string, text: string): Promise<void>;
58
93
  /**
59
94
  * Retrieves an input element of type `file` and sets its files.
60
- * * @param pageName - The page or component grouping name in your repository.
95
+ * @param pageName - The page or component grouping name in your repository.
61
96
  * @param elementName - The specific element name in your repository.
62
97
  * @param filePath - The local file path of the file to be uploaded.
63
98
  */
@@ -65,43 +100,87 @@ export declare class Steps {
65
100
  /**
66
101
  * Retrieves a `<select>` dropdown element and selects an option based on the provided strategy.
67
102
  * Defaults to selecting a random, non-disabled option if no strategy is specified.
68
- * * @param pageName - The page or component grouping name in your repository.
103
+ * @param pageName - The page or component grouping name in your repository.
69
104
  * @param elementName - The specific element name in your repository.
70
105
  * @param options - Configuration specifying whether to select by 'random', 'index', or 'value'.
71
106
  * @returns The exact value attribute of the selected option.
72
107
  */
73
108
  selectDropdown(pageName: string, elementName: string, options?: DropdownSelectOptions): Promise<string>;
109
+ /**
110
+ * Drags an element either to a specified target element, a target element with an offset, or by a coordinate offset.
111
+ * @param pageName - The page or component grouping name in your repository.
112
+ * @param elementName - The specific element name in your repository (the element to drag).
113
+ * @param options - Configuration specifying a 'targetLocator', offsets, or both.
114
+ */
115
+ dragAndDrop(pageName: string, elementName: string, options: DragAndDropOptions): Promise<void>;
116
+ /**
117
+ * Drags an element either to a specified target element, a target element with an offset, or by a coordinate offset.
118
+ * @param pageName - The page or component grouping name in your repository.
119
+ * @param elementName - The specific element name in your repository (the element to drag).
120
+ * @param options - Configuration specifying a 'targetLocator', offsets, or both.
121
+ */
122
+ dragAndDropListedElement(pageName: string, elementName: string, elementText: string, options: DragAndDropOptions): Promise<void>;
123
+ /**
124
+ * Safely retrieves and trims the text content of a specified element.
125
+ * @param pageName - The page or component grouping name in your repository.
126
+ * @param elementName - The specific element name in your repository.
127
+ * @returns The trimmed string, or an empty string if null.
128
+ */
129
+ getText(pageName: string, elementName: string): Promise<string | null>;
130
+ /**
131
+ * Retrieves the value of a specified attribute (e.g., 'href', 'aria-pressed') from an element.
132
+ * @param pageName - The page or component grouping name in your repository.
133
+ * @param elementName - The specific element name in your repository.
134
+ * @param attributeName - The name of the attribute to retrieve.
135
+ * @returns The attribute value as a string, or null if it doesn't exist.
136
+ */
137
+ getAttribute(pageName: string, elementName: string, attributeName: string): Promise<string | null>;
74
138
  /**
75
139
  * Asserts that a specified element is attached to the DOM and is visible.
76
- * * @param pageName - The page or component grouping name in your repository.
140
+ * @param pageName - The page or component grouping name in your repository.
77
141
  * @param elementName - The specific element name in your repository.
78
142
  */
79
143
  verifyPresence(pageName: string, elementName: string): Promise<void>;
80
144
  /**
81
145
  * Asserts that a specified element is hidden or completely detached from the DOM.
82
- * * @param pageName - The page or component grouping name in your repository.
146
+ * @param pageName - The page or component grouping name in your repository.
83
147
  * @param elementName - The specific element name in your repository.
84
148
  */
85
149
  verifyAbsence(pageName: string, elementName: string): Promise<void>;
86
150
  /**
87
- * Asserts that the specified element exactly matches the expected text.
88
- * * @param pageName - The page or component grouping name in your repository.
151
+ * Asserts that the specified element exactly matches the expected text, or optionally checks if it is not empty.
152
+ * @param pageName - The page or component grouping name in your repository.
153
+ * @param elementName - The specific element name in your repository.
154
+ * @param expectedText - The exact string expected inside the element (optional if checking 'notEmpty').
155
+ * @param options - Configuration to alter the verification behavior.
156
+ */
157
+ verifyText(pageName: string, elementName: string, expectedText?: string, options?: TextVerifyOptions): Promise<void>;
158
+ /**
159
+ * Asserts the number of elements matching the locator based on the provided conditions.
160
+ * @param pageName - The page or component grouping name in your repository.
89
161
  * @param elementName - The specific element name in your repository.
90
- * @param expectedText - The exact string expected inside the element.
162
+ * @param options - Configuration specifying 'exact', 'greaterThan', or 'lessThan' logic.
91
163
  */
92
- verifyText(pageName: string, elementName: string, expectedText: string): Promise<void>;
164
+ verifyCount(pageName: string, elementName: string, options: CountVerifyOptions): Promise<void>;
93
165
  /**
94
166
  * Performs a rigorous verification of one or more images.
95
167
  * Asserts visibility, checks for a valid 'src' attribute, ensures a positive 'naturalWidth',
96
168
  * and evaluates the native browser `decode()` promise to ensure the image isn't broken.
97
- * * @param pageName - The page or component grouping name in your repository.
169
+ * @param pageName - The page or component grouping name in your repository.
98
170
  * @param elementName - The specific element name in your repository.
99
171
  * @param scroll - Whether to smoothly scroll the image(s) into view before verifying (default: true).
100
172
  */
101
173
  verifyImages(pageName: string, elementName: string, scroll?: boolean): Promise<void>;
102
174
  /**
103
175
  * Asserts that the current browser URL contains the expected substring.
104
- * * @param text - The substring expected to be present within the active URL.
176
+ * @param text - The substring expected to be present within the active URL.
105
177
  */
106
178
  verifyUrlContains(text: string): Promise<void>;
179
+ /**
180
+ * Waits for an element to reach a specific state in the DOM.
181
+ * @param pageName - The page or component grouping name in your repository.
182
+ * @param elementName - The specific element name in your repository.
183
+ * @param state - The state to wait for: 'visible' | 'attached' | 'hidden' | 'detached'. Defaults to 'visible'.
184
+ */
185
+ waitForState(pageName: string, elementName: string, state?: 'visible' | 'attached' | 'hidden' | 'detached'): Promise<void>;
107
186
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Steps = void 0;
4
- const ElementInteractions_1 = require("../ElementInteractions");
4
+ const ElementInteractions_1 = require("../interactions/facade/ElementInteractions");
5
5
  /**
6
6
  * The `Steps` class serves as a unified Facade for test orchestration.
7
7
  * It combines element acquisition (via `pw-element-repository`) with
@@ -13,26 +13,31 @@ class Steps {
13
13
  repo;
14
14
  interact;
15
15
  navigate;
16
+ extract;
16
17
  verify;
18
+ utils;
17
19
  /**
18
20
  * Initializes the Steps class with the required Playwright page and element repository.
19
- * * @param page - The current Playwright Page object.
21
+ * @param page - The current Playwright Page object.
20
22
  * @param repo - An initialized instance of `ElementRepository` containing your locators.
23
+ * @param timeout - Optional global timeout override (in milliseconds).
21
24
  */
22
- constructor(page, repo) {
25
+ constructor(page, repo, timeout) {
23
26
  this.page = page;
24
27
  this.repo = repo;
25
- const interactions = new ElementInteractions_1.ElementInteractions(page);
28
+ const interactions = new ElementInteractions_1.ElementInteractions(page, timeout);
26
29
  this.interact = interactions.interact;
27
30
  this.navigate = interactions.navigate;
31
+ this.extract = interactions.extract;
28
32
  this.verify = interactions.verify;
33
+ this.utils = interactions.utils;
29
34
  }
30
35
  // ==========================================
31
36
  // 🧭 NAVIGATION STEPS
32
37
  // ==========================================
33
38
  /**
34
39
  * Navigates the browser to the specified URL.
35
- * * @param url - The absolute or relative URL to navigate to.
40
+ * @param url - The absolute or relative URL to navigate to.
36
41
  */
37
42
  async navigateTo(url) {
38
43
  console.log(`[Step] -> Navigating to URL: "${url}"`);
@@ -45,12 +50,31 @@ class Steps {
45
50
  console.log(`[Step] -> Refreshing the current page`);
46
51
  await this.navigate.reload();
47
52
  }
53
+ /**
54
+ * Navigates the browser history stack either backwards or forwards.
55
+ * Mirrors the behavior of the browser's native Back and Forward buttons.
56
+ * @param direction - The direction to move in history: either 'BACKWARDS' or 'FORWARDS'.
57
+ */
58
+ async backOrForward(direction) {
59
+ console.log(`[Step] -> Navigating browser: "${direction}"`);
60
+ await this.navigate.backOrForward(direction);
61
+ }
62
+ /**
63
+ * Resizes the browser viewport to the specified dimensions.
64
+ * Useful for simulating different device screen sizes or responsive breakpoints.
65
+ * @param width - The desired width of the viewport in pixels.
66
+ * @param height - The desired height of the viewport in pixels.
67
+ */
68
+ async setViewport(width, height) {
69
+ console.log(`[Step] -> Setting viewport to ${width}x${height}`);
70
+ await this.navigate.setViewport(width, height);
71
+ }
48
72
  // ==========================================
49
73
  // 🖱️ INTERACTION STEPS
50
74
  // ==========================================
51
75
  /**
52
76
  * Retrieves an element from the repository and performs a standard click.
53
- * * @param pageName - The page or component grouping name in your repository.
77
+ * @param pageName - The page or component grouping name in your repository.
54
78
  * @param elementName - The specific element name in your repository.
55
79
  */
56
80
  async click(pageName, elementName) {
@@ -58,10 +82,21 @@ class Steps {
58
82
  const locator = await this.repo.get(this.page, pageName, elementName);
59
83
  await this.interact.click(locator);
60
84
  }
85
+ /**
86
+ * Retrieves an element and dispatches a native 'click' event directly to it.
87
+ * Bypasses default scrolling and intersection checks. Useful for obscured elements.
88
+ * @param pageName - The page or component grouping name in your repository.
89
+ * @param elementName - The specific element name in your repository.
90
+ */
91
+ async clickWithoutScrolling(pageName, elementName) {
92
+ console.log(`[Step] -> Clicking (no scroll) on '${elementName}' in '${pageName}'`);
93
+ const locator = await this.repo.get(this.page, pageName, elementName);
94
+ await this.interact.clickWithoutScrolling(locator);
95
+ }
61
96
  /**
62
97
  * Retrieves a random element from a resolved list of locators and clicks it.
63
98
  * Useful for clicking random items in a list or grid (e.g., product cards).
64
- * * @param pageName - The page or component grouping name in your repository.
99
+ * @param pageName - The page or component grouping name in your repository.
65
100
  * @param elementName - The specific element name in your repository representing multiple elements.
66
101
  */
67
102
  async clickRandom(pageName, elementName) {
@@ -72,7 +107,7 @@ class Steps {
72
107
  /**
73
108
  * Retrieves an element and clicks it only if it is visible.
74
109
  * Prevents test failures on optional elements like cookie banners or promotional pop-ups.
75
- * * @param pageName - The page or component grouping name in your repository.
110
+ * @param pageName - The page or component grouping name in your repository.
76
111
  * @param elementName - The specific element name in your repository.
77
112
  */
78
113
  async clickIfPresent(pageName, elementName) {
@@ -80,9 +115,29 @@ class Steps {
80
115
  const locator = await this.repo.get(this.page, pageName, elementName);
81
116
  await this.interact.clickIfPresent(locator);
82
117
  }
118
+ /**
119
+ * Retrieves an element and hovers over it. Useful for triggering dropdowns or tooltips.
120
+ * @param pageName - The page or component grouping name in your repository.
121
+ * @param elementName - The specific element name in your repository.
122
+ */
123
+ async hover(pageName, elementName) {
124
+ console.log(`[Step] -> Hovering over '${elementName}' in '${pageName}'`);
125
+ const locator = await this.repo.get(this.page, pageName, elementName);
126
+ await this.interact.hover(locator);
127
+ }
128
+ /**
129
+ * Retrieves an element and scrolls it into view if it is not already visible.
130
+ * @param pageName - The page or component grouping name in your repository.
131
+ * @param elementName - The specific element name in your repository.
132
+ */
133
+ async scrollIntoView(pageName, elementName) {
134
+ console.log(`[Step] -> Scrolling '${elementName}' in '${pageName}' into view`);
135
+ const locator = await this.repo.get(this.page, pageName, elementName);
136
+ await this.interact.scrollIntoView(locator);
137
+ }
83
138
  /**
84
139
  * Retrieves an input field and fills it with the provided text, replacing any existing value.
85
- * * @param pageName - The page or component grouping name in your repository.
140
+ * @param pageName - The page or component grouping name in your repository.
86
141
  * @param elementName - The specific element name in your repository.
87
142
  * @param text - The text to type into the input field.
88
143
  */
@@ -93,7 +148,7 @@ class Steps {
93
148
  }
94
149
  /**
95
150
  * Retrieves an input element of type `file` and sets its files.
96
- * * @param pageName - The page or component grouping name in your repository.
151
+ * @param pageName - The page or component grouping name in your repository.
97
152
  * @param elementName - The specific element name in your repository.
98
153
  * @param filePath - The local file path of the file to be uploaded.
99
154
  */
@@ -105,7 +160,7 @@ class Steps {
105
160
  /**
106
161
  * Retrieves a `<select>` dropdown element and selects an option based on the provided strategy.
107
162
  * Defaults to selecting a random, non-disabled option if no strategy is specified.
108
- * * @param pageName - The page or component grouping name in your repository.
163
+ * @param pageName - The page or component grouping name in your repository.
109
164
  * @param elementName - The specific element name in your repository.
110
165
  * @param options - Configuration specifying whether to select by 'random', 'index', or 'value'.
111
166
  * @returns The exact value attribute of the selected option.
@@ -116,12 +171,60 @@ class Steps {
116
171
  const locator = await this.repo.get(this.page, pageName, elementName);
117
172
  return await this.interact.selectDropdown(locator, options);
118
173
  }
174
+ /**
175
+ * Drags an element either to a specified target element, a target element with an offset, or by a coordinate offset.
176
+ * @param pageName - The page or component grouping name in your repository.
177
+ * @param elementName - The specific element name in your repository (the element to drag).
178
+ * @param options - Configuration specifying a 'targetLocator', offsets, or both.
179
+ */
180
+ async dragAndDrop(pageName, elementName, options) {
181
+ console.log(`[Step] -> Dragging and dropping '${elementName}' in '${pageName}'`);
182
+ const locator = await this.repo.get(this.page, pageName, elementName);
183
+ await this.interact.dragAndDrop(locator, options);
184
+ }
185
+ /**
186
+ * Drags an element either to a specified target element, a target element with an offset, or by a coordinate offset.
187
+ * @param pageName - The page or component grouping name in your repository.
188
+ * @param elementName - The specific element name in your repository (the element to drag).
189
+ * @param options - Configuration specifying a 'targetLocator', offsets, or both.
190
+ */
191
+ async dragAndDropListedElement(pageName, elementName, elementText, options) {
192
+ console.log(`[Step] -> Dragging and dropping '${elementText}' in '${pageName}'`);
193
+ const locator = await this.repo.getByText(this.page, pageName, elementName, elementText);
194
+ await this.interact.dragAndDrop(locator, options);
195
+ }
196
+ // ==========================================
197
+ // 📊 DATA EXTRACTION STEPS
198
+ // ==========================================
199
+ /**
200
+ * Safely retrieves and trims the text content of a specified element.
201
+ * @param pageName - The page or component grouping name in your repository.
202
+ * @param elementName - The specific element name in your repository.
203
+ * @returns The trimmed string, or an empty string if null.
204
+ */
205
+ async getText(pageName, elementName) {
206
+ console.log(`[Step] -> Getting text from '${elementName}' in '${pageName}'`);
207
+ const locator = await this.repo.get(this.page, pageName, elementName);
208
+ return await this.extract.getText(locator);
209
+ }
210
+ /**
211
+ * Retrieves the value of a specified attribute (e.g., 'href', 'aria-pressed') from an element.
212
+ * @param pageName - The page or component grouping name in your repository.
213
+ * @param elementName - The specific element name in your repository.
214
+ * @param attributeName - The name of the attribute to retrieve.
215
+ * @returns The attribute value as a string, or null if it doesn't exist.
216
+ */
217
+ async getAttribute(pageName, elementName, attributeName) {
218
+ console.log(`[Step] -> Getting attribute '${attributeName}' from '${elementName}' in '${pageName}'`);
219
+ const locator = await this.repo.get(this.page, pageName, elementName);
220
+ return await this.extract.getAttribute(locator, attributeName);
221
+ }
119
222
  // ==========================================
120
223
  // ✅ VERIFICATION STEPS
121
224
  // ==========================================
122
225
  /**
123
226
  * Asserts that a specified element is attached to the DOM and is visible.
124
- * * @param pageName - The page or component grouping name in your repository.
227
+ * @param pageName - The page or component grouping name in your repository.
125
228
  * @param elementName - The specific element name in your repository.
126
229
  */
127
230
  async verifyPresence(pageName, elementName) {
@@ -131,30 +234,43 @@ class Steps {
131
234
  }
132
235
  /**
133
236
  * Asserts that a specified element is hidden or completely detached from the DOM.
134
- * * @param pageName - The page or component grouping name in your repository.
237
+ * @param pageName - The page or component grouping name in your repository.
135
238
  * @param elementName - The specific element name in your repository.
136
239
  */
137
240
  async verifyAbsence(pageName, elementName) {
138
241
  console.log(`[Step] -> Verifying absence of '${elementName}' in '${pageName}'`);
242
+ const selector = await this.repo.getSelector(pageName, elementName);
243
+ await this.verify.absence(selector);
244
+ }
245
+ /**
246
+ * Asserts that the specified element exactly matches the expected text, or optionally checks if it is not empty.
247
+ * @param pageName - The page or component grouping name in your repository.
248
+ * @param elementName - The specific element name in your repository.
249
+ * @param expectedText - The exact string expected inside the element (optional if checking 'notEmpty').
250
+ * @param options - Configuration to alter the verification behavior.
251
+ */
252
+ async verifyText(pageName, elementName, expectedText, options) {
253
+ const logDetail = options?.notEmpty ? `is not empty` : `matches: "${expectedText}"`;
254
+ console.log(`[Step] -> Verifying text of '${elementName}' in '${pageName}' ${logDetail}`);
139
255
  const locator = await this.repo.get(this.page, pageName, elementName);
140
- await this.verify.absence(locator);
256
+ await this.verify.text(locator, expectedText, options);
141
257
  }
142
258
  /**
143
- * Asserts that the specified element exactly matches the expected text.
144
- * * @param pageName - The page or component grouping name in your repository.
259
+ * Asserts the number of elements matching the locator based on the provided conditions.
260
+ * @param pageName - The page or component grouping name in your repository.
145
261
  * @param elementName - The specific element name in your repository.
146
- * @param expectedText - The exact string expected inside the element.
262
+ * @param options - Configuration specifying 'exact', 'greaterThan', or 'lessThan' logic.
147
263
  */
148
- async verifyText(pageName, elementName, expectedText) {
149
- console.log(`[Step] -> Verifying text of '${elementName}' in '${pageName}' matches: "${expectedText}"`);
264
+ async verifyCount(pageName, elementName, options) {
265
+ console.log(`[Step] -> Verifying count for '${elementName}' in '${pageName}' with options: ${JSON.stringify(options)}`);
150
266
  const locator = await this.repo.get(this.page, pageName, elementName);
151
- await this.verify.text(locator, expectedText);
267
+ await this.verify.count(locator, options);
152
268
  }
153
269
  /**
154
270
  * Performs a rigorous verification of one or more images.
155
271
  * Asserts visibility, checks for a valid 'src' attribute, ensures a positive 'naturalWidth',
156
272
  * and evaluates the native browser `decode()` promise to ensure the image isn't broken.
157
- * * @param pageName - The page or component grouping name in your repository.
273
+ * @param pageName - The page or component grouping name in your repository.
158
274
  * @param elementName - The specific element name in your repository.
159
275
  * @param scroll - Whether to smoothly scroll the image(s) into view before verifying (default: true).
160
276
  */
@@ -165,11 +281,22 @@ class Steps {
165
281
  }
166
282
  /**
167
283
  * Asserts that the current browser URL contains the expected substring.
168
- * * @param text - The substring expected to be present within the active URL.
284
+ * @param text - The substring expected to be present within the active URL.
169
285
  */
170
286
  async verifyUrlContains(text) {
171
287
  console.log(`[Step] -> Verifying current URL contains: "${text}"`);
172
288
  await this.verify.urlContains(text);
173
289
  }
290
+ /**
291
+ * Waits for an element to reach a specific state in the DOM.
292
+ * @param pageName - The page or component grouping name in your repository.
293
+ * @param elementName - The specific element name in your repository.
294
+ * @param state - The state to wait for: 'visible' | 'attached' | 'hidden' | 'detached'. Defaults to 'visible'.
295
+ */
296
+ async waitForState(pageName, elementName, state = 'visible') {
297
+ console.log(`[Step] -> Waiting for '${elementName}' in '${pageName}' to be '${state}'`);
298
+ const locator = await this.repo.get(this.page, pageName, elementName);
299
+ await this.utils.waitForState(locator, state);
300
+ }
174
301
  }
175
302
  exports.Steps = Steps;
@@ -7,19 +7,15 @@ class DateUtilities {
7
7
  * Mirrors the Java DateUtilities.reformatDateString method.
8
8
  */
9
9
  static reformatDateString(rawDate, format) {
10
- // Parse the raw date string into a JS Date object
11
10
  const date = new Date(rawDate);
12
- // Guard clause: Check if the date is valid before formatting
13
11
  if (isNaN(date.getTime())) {
14
12
  throw new Error(`Invalid date string provided: ${rawDate}`);
15
13
  }
16
14
  const yyyy = date.getFullYear().toString();
17
15
  const MM = String(date.getMonth() + 1).padStart(2, '0');
18
16
  const dd = String(date.getDate()).padStart(2, '0');
19
- // Unpadded variables for single-digit months/days
20
17
  const M = String(date.getMonth() + 1);
21
18
  const d = String(date.getDate());
22
- // You can expand this switch/if statement as your framework's formatting needs grow
23
19
  switch (format) {
24
20
  case 'yyyy-MM-dd':
25
21
  return `${yyyy}-${MM}-${dd}`;
@@ -28,7 +24,7 @@ class DateUtilities {
28
24
  case 'dd MMM yyyy':
29
25
  const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
30
26
  return `${dd} ${monthNames[date.getMonth()]} ${yyyy}`;
31
- case 'yyyy-M-d': // 💡 New format matching the modal's output
27
+ case 'yyyy-M-d':
32
28
  return `${yyyy}-${M}-${d}`;
33
29
  default:
34
30
  console.warn(`Format ${format} not fully supported, returning ISO date.`);
@@ -0,0 +1,26 @@
1
+ import { Locator } from '@playwright/test';
2
+ /**
3
+ * Utility class to handle standardized waiting logic across the framework.
4
+ */
5
+ export declare class Utils {
6
+ private readonly timeout;
7
+ /**
8
+ * @param timeout - Optional timeout in milliseconds. Defaults to 30000.
9
+ */
10
+ constructor(timeout?: number);
11
+ /**
12
+ * Returns the current timeout value.
13
+ */
14
+ getTimeout(): number;
15
+ /**
16
+ * Standardized wait logic for element states.
17
+ * Does not fail the test on timeout; logs a warning instead.
18
+ * If the locator resolves to multiple elements (strict mode violation),
19
+ * the wait is retried automatically on the first matched element.
20
+ * @param locator - The Playwright Locator to wait on.
21
+ * @param state - The DOM state to wait for. Defaults to `'visible'`.
22
+ * @returns A Promise that resolves when the element reaches the desired state,
23
+ * or silently continues if the timeout is exceeded.
24
+ */
25
+ waitForState(locator: Locator, state?: 'visible' | 'attached' | 'hidden' | 'detached'): Promise<void>;
26
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Utils = void 0;
4
+ /**
5
+ * Utility class to handle standardized waiting logic across the framework.
6
+ */
7
+ class Utils {
8
+ timeout;
9
+ /**
10
+ * @param timeout - Optional timeout in milliseconds. Defaults to 30000.
11
+ */
12
+ constructor(timeout = 30000) {
13
+ this.timeout = timeout;
14
+ }
15
+ /**
16
+ * Returns the current timeout value.
17
+ */
18
+ getTimeout() {
19
+ return this.timeout;
20
+ }
21
+ /**
22
+ * Standardized wait logic for element states.
23
+ * Does not fail the test on timeout; logs a warning instead.
24
+ * If the locator resolves to multiple elements (strict mode violation),
25
+ * the wait is retried automatically on the first matched element.
26
+ * @param locator - The Playwright Locator to wait on.
27
+ * @param state - The DOM state to wait for. Defaults to `'visible'`.
28
+ * @returns A Promise that resolves when the element reaches the desired state,
29
+ * or silently continues if the timeout is exceeded.
30
+ */
31
+ async waitForState(locator, state = 'visible') {
32
+ try {
33
+ await locator.waitFor({ state, timeout: this.timeout });
34
+ }
35
+ catch (error) {
36
+ const message = error instanceof Error ? error.message : String(error);
37
+ if (message.includes('strict mode violation')) {
38
+ console.warn(`[Warning] -> Locator resolved to multiple elements. Waiting on first element instead.`);
39
+ try {
40
+ await locator.first().waitFor({ state, timeout: this.timeout });
41
+ }
42
+ catch {
43
+ console.warn(`[Warning] -> First element failed to reach state '${state}' within ${this.timeout}ms. Proceeding...`);
44
+ }
45
+ return;
46
+ }
47
+ console.warn(`[Warning] -> Element failed to reach state '${state}' within ${this.timeout}ms. Proceeding...`);
48
+ }
49
+ }
50
+ }
51
+ exports.Utils = Utils;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pw-element-interactions",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "A robust, readable interaction and assertion Facade for Playwright. Abstract away boilerplate into semantic, English-like methods, making your test automation framework cleaner, easier to maintain, and accessible to non-developers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,10 +14,12 @@
14
14
  "dist"
15
15
  ],
16
16
  "peerDependencies": {
17
+ "@civitas-cerebrum/context-store": ">=0.0.2",
17
18
  "@playwright/test": ">=1.0.0",
18
19
  "pw-element-repository": ">=0.0.3"
19
20
  },
20
21
  "devDependencies": {
22
+ "@civitas-cerebrum/context-store": "^0.0.2",
21
23
  "@playwright/test": "^1.58.2",
22
24
  "@types/node": "^20.0.0",
23
25
  "pw-element-repository": "^0.0.3",
@@ -43,4 +45,4 @@
43
45
  },
44
46
  "author": "Umut Ay Bora",
45
47
  "license": "MIT"
46
- }
48
+ }
@@ -1,10 +0,0 @@
1
- import { Page } from '@playwright/test';
2
- import { Interactions } from './interactions/Interaction';
3
- import { Navigation } from './interactions/Navigation';
4
- import { Verifications } from './interactions/Verification';
5
- export declare class ElementInteractions {
6
- navigate: Navigation;
7
- interact: Interactions;
8
- verify: Verifications;
9
- constructor(page: Page);
10
- }