@progress/kendo-e2e 4.11.3 → 4.12.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.
@@ -2,71 +2,612 @@ import { By, ThenableWebDriver, WebElement, WebElementCondition } from "selenium
2
2
  import { WaitCondition } from "./conditions";
3
3
  import { ExpectApi } from "./expect";
4
4
  /**
5
- * This class encapsulates common location and interaction functionality over a {@link ThenableWebDriver}.
5
+ * Core class that provides automatic waiting and simplified interaction with web elements.
6
+ *
7
+ * **Key Features:**
8
+ * - **Automatic waiting** - No need to add manual waits, all methods wait for elements automatically
9
+ * - **Smart element location** - Accepts CSS selectors, By locators, or WebElement instances
10
+ * - **Fluent API** - Chain methods for readable test code
11
+ * - **Built-in retry logic** - Handles timing issues that cause flaky tests
12
+ *
13
+ * This eliminates the common Selenium pitfalls of StaleElementReferenceException and timing issues.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const app = new WebApp(driver);
18
+ *
19
+ * // Simple element interaction with automatic waiting
20
+ * await app.click('#submit-button');
21
+ * await app.type('#username', 'testuser');
22
+ *
23
+ * // Find and interact with elements
24
+ * const header = await app.find('.page-header');
25
+ * const text = await app.getText(header);
26
+ *
27
+ * // Wait for conditions
28
+ * await app.wait(EC.isVisible('#success-message'));
29
+ *
30
+ * // Modern expect API with retry logic
31
+ * await app.expect('#result').toHaveText('Success');
32
+ * await app.expect('.modal').toBeVisible();
33
+ * ```
6
34
  */
7
35
  export declare class WebApp {
36
+ /** The underlying Selenium WebDriver instance */
8
37
  driver: ThenableWebDriver;
38
+ /**
39
+ * Creates a WebApp instance wrapping a Selenium WebDriver.
40
+ *
41
+ * @param driver - Selenium WebDriver instance to wrap
42
+ */
9
43
  constructor(driver: ThenableWebDriver);
44
+ /**
45
+ * Finds a single element with automatic waiting.
46
+ *
47
+ * **Automatically waits** up to the specified timeout for the element to appear in the DOM.
48
+ * This eliminates the need for manual waits and handles dynamic content loading.
49
+ *
50
+ * @param locator - CSS selector string or Selenium By locator
51
+ * @param options - Optional configuration
52
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
53
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
54
+ * @returns Promise resolving to the WebElement
55
+ * @throws Error if element is not found within the timeout period
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // Using CSS selector (recommended)
60
+ * const button = await app.find('#submit-btn');
61
+ * const firstItem = await app.find('.list-item');
62
+ *
63
+ * // Using Selenium By locator
64
+ * const element = await app.find(By.xpath('//div[@data-test="value"]'));
65
+ *
66
+ * // With custom timeout
67
+ * const slowElement = await app.find('#async-content', { timeout: 20000 });
68
+ * ```
69
+ */
10
70
  find(locator: By | string, { timeout, pollTimeout }?: {
11
71
  timeout?: number;
12
72
  pollTimeout?: number;
13
73
  }): Promise<WebElement>;
74
+ /**
75
+ * Finds all matching elements without waiting.
76
+ *
77
+ * Returns an empty array if no elements are found. For scenarios where you need to wait
78
+ * for at least one element, use {@link findAllWithTimeout} instead.
79
+ *
80
+ * @param locator - CSS selector string or Selenium By locator
81
+ * @returns Promise resolving to array of WebElements (empty if none found)
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // Get all list items
86
+ * const items = await app.findAll('.list-item');
87
+ * console.log(`Found ${items.length} items`);
88
+ *
89
+ * // Iterate over elements
90
+ * for (const item of items) {
91
+ * const text = await item.getText();
92
+ * console.log(text);
93
+ * }
94
+ *
95
+ * // Using By locator
96
+ * const buttons = await app.findAll(By.css('button'));
97
+ * ```
98
+ */
14
99
  findAll(locator: By | string): Promise<WebElement[]>;
100
+ /**
101
+ * Finds all matching elements with automatic waiting for at least one element to appear.
102
+ *
103
+ * Waits until at least one element matching the locator appears, then returns all matching elements.
104
+ * Use this when you expect elements to load dynamically and need to ensure they're present.
105
+ *
106
+ * @param locator - CSS selector string or Selenium By locator
107
+ * @param options - Optional configuration
108
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
109
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
110
+ * @returns Promise resolving to array of WebElements
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // Wait for search results to load
115
+ * const results = await app.findAllWithTimeout('.search-result');
116
+ *
117
+ * // With custom timeout for slow-loading content
118
+ * const items = await app.findAllWithTimeout('.async-item', { timeout: 15000 });
119
+ * ```
120
+ */
15
121
  findAllWithTimeout(locator: By | string, { timeout, pollTimeout }?: {
16
122
  timeout?: number;
17
123
  pollTimeout?: number;
18
124
  }): Promise<WebElement[]>;
125
+ /**
126
+ * Finds a child element within a parent element with automatic waiting.
127
+ *
128
+ * Useful for scoped element searches within a specific container. Automatically waits
129
+ * for both the parent and child elements to appear.
130
+ *
131
+ * @param rootElement - Parent element (WebElement, By locator, or CSS selector)
132
+ * @param locator - Child element selector (By locator or CSS selector)
133
+ * @param options - Optional configuration
134
+ * @param options.waitForChild - Whether to wait for child to appear (default: true)
135
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
136
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
137
+ * @returns Promise resolving to the child WebElement
138
+ * @throws Error if child element is not found within the timeout period
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * // Find button within a specific dialog
143
+ * const dialog = await app.find('.modal-dialog');
144
+ * const closeBtn = await app.findChild(dialog, '.close-button');
145
+ *
146
+ * // Or find child directly using parent selector
147
+ * const button = await app.findChild('.modal-dialog', 'button.submit');
148
+ *
149
+ * // Without waiting for child (if you know it exists)
150
+ * const child = await app.findChild(parent, '.child', { waitForChild: false });
151
+ * ```
152
+ */
19
153
  findChild(rootElement: WebElement | By | string, locator: By | string, { waitForChild, timeout, pollTimeout }?: {
20
154
  waitForChild?: boolean;
21
155
  timeout?: number;
22
156
  pollTimeout?: number;
23
157
  }): Promise<WebElement>;
158
+ /**
159
+ * Finds all child elements within a parent element with automatic waiting.
160
+ *
161
+ * Similar to {@link findChild} but returns all matching children instead of just the first one.
162
+ * Waits for at least one child to appear before returning.
163
+ *
164
+ * @param rootElement - Parent element (WebElement, By locator, or CSS selector)
165
+ * @param locator - Child elements selector (By locator or CSS selector)
166
+ * @param options - Optional configuration
167
+ * @param options.waitForChild - Whether to wait for at least one child to appear (default: true)
168
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
169
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
170
+ * @returns Promise resolving to array of child WebElements
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * // Find all rows in a specific table
175
+ * const table = await app.find('#data-table');
176
+ * const rows = await app.findChildren(table, 'tr');
177
+ *
178
+ * // Or find children directly using parent selector
179
+ * const items = await app.findChildren('.dropdown-menu', 'li');
180
+ *
181
+ * // Process all children
182
+ * for (const row of rows) {
183
+ * const text = await row.getText();
184
+ * console.log(text);
185
+ * }
186
+ * ```
187
+ */
24
188
  findChildren(rootElement: WebElement | By | string, locator: By | string, { waitForChild, timeout, pollTimeout }?: {
25
189
  waitForChild?: boolean;
26
190
  timeout?: number;
27
191
  pollTimeout?: number;
28
192
  }): Promise<WebElement[]>;
193
+ /**
194
+ * Clicks an element with automatic waiting and retry logic.
195
+ *
196
+ * **Handles common click issues automatically:**
197
+ * - Waits for element to appear in DOM
198
+ * - Waits for element to be visible
199
+ * - Waits for element to be enabled
200
+ * - Retries if click fails initially
201
+ *
202
+ * This eliminates flaky tests caused by timing issues.
203
+ *
204
+ * @param element - Element to click (WebElement, By locator, or CSS selector)
205
+ * @param options - Optional configuration
206
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
207
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
208
+ * @returns Promise that resolves when click succeeds
209
+ * @throws Error if element cannot be clicked within timeout
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * // Simple click using CSS selector
214
+ * await app.click('#submit-button');
215
+ *
216
+ * // Click with custom timeout
217
+ * await app.click('.slow-loading-btn', { timeout: 15000 });
218
+ *
219
+ * // Click using By locator
220
+ * await app.click(By.xpath('//button[text()="Submit"]'));
221
+ *
222
+ * // Click a previously found element
223
+ * const button = await app.find('#my-button');
224
+ * await app.click(button);
225
+ * ```
226
+ */
29
227
  click(element: WebElement | By | string, { timeout, pollTimeout }?: {
30
228
  timeout?: number;
31
229
  pollTimeout?: number;
32
230
  }): Promise<void>;
231
+ /**
232
+ * Moves the mouse cursor over an element (hover action).
233
+ *
234
+ * Useful for testing hover states, tooltips, dropdown menus, and other hover-triggered UI.
235
+ * Automatically waits for the element to be present before hovering.
236
+ *
237
+ * @param element - Element to hover over (WebElement, By locator, or CSS selector)
238
+ * @param options - Optional configuration
239
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
240
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
241
+ * @returns Promise that resolves when hover completes
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * // Hover to reveal dropdown menu
246
+ * await app.hover('.menu-item');
247
+ * await app.click('.submenu-option');
248
+ *
249
+ * // Hover to show tooltip
250
+ * await app.hover('#info-icon');
251
+ * const tooltip = await app.find('.tooltip');
252
+ * const text = await app.getText(tooltip);
253
+ *
254
+ * // Hover on element found with By locator
255
+ * await app.hover(By.css('[data-test="hover-target"]'));
256
+ * ```
257
+ */
33
258
  hover(element: WebElement | By | string, { timeout, pollTimeout }?: {
34
259
  timeout?: number;
35
260
  pollTimeout?: number;
36
261
  }): Promise<void>;
262
+ /**
263
+ * Sets focus on an element programmatically.
264
+ *
265
+ * Directly focuses the element using JavaScript, which is more reliable than clicking for focus.
266
+ * Useful for testing keyboard interactions, input fields, and focus-dependent behaviors.
267
+ *
268
+ * @param element - Element to focus (WebElement, By locator, or CSS selector)
269
+ * @param options - Optional configuration
270
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
271
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
272
+ * @returns Promise that resolves when focus is set
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * // Focus an input field
277
+ * await app.focus('#username');
278
+ * await app.sendKey(Key.CONTROL, 'a'); // Select all
279
+ *
280
+ * // Focus before typing
281
+ * await app.focus('#search-box');
282
+ * await app.type('#search-box', 'test query');
283
+ *
284
+ * // Test focus-dependent behavior
285
+ * await app.focus('#email');
286
+ * await app.expect('.validation-hint').toBeVisible();
287
+ * ```
288
+ */
37
289
  focus(element: WebElement | By | string, { timeout, pollTimeout }?: {
38
290
  timeout?: number;
39
291
  pollTimeout?: number;
40
292
  }): Promise<void>;
293
+ /**
294
+ * Performs a right-click (context menu click) on an element.
295
+ *
296
+ * Opens the context menu for the element, allowing you to test right-click menus and actions.
297
+ *
298
+ * @param element - Element to right-click (WebElement, By locator, or CSS selector)
299
+ * @param options - Optional configuration
300
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
301
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
302
+ * @returns Promise that resolves when right-click completes
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * // Open context menu and select option
307
+ * await app.contextClick('.file-item');
308
+ * await app.click('.context-menu-delete');
309
+ *
310
+ * // Right-click on canvas element
311
+ * await app.contextClick('#drawing-canvas');
312
+ * await app.expect('.context-menu').toBeVisible();
313
+ * ```
314
+ */
41
315
  contextClick(element: WebElement | By | string, { timeout, pollTimeout }?: {
42
316
  timeout?: number;
43
317
  pollTimeout?: number;
44
318
  }): Promise<void>;
319
+ /**
320
+ * Performs a double-click on an element.
321
+ *
322
+ * Useful for testing double-click interactions like selecting text, opening files, or
323
+ * triggering double-click-specific behaviors in your application.
324
+ *
325
+ * @param element - Element to double-click (WebElement, By locator, or CSS selector)
326
+ * @param options - Optional configuration
327
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
328
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
329
+ * @returns Promise that resolves when double-click completes
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * // Double-click to open file
334
+ * await app.doubleClick('.file-icon');
335
+ *
336
+ * // Double-click to select word
337
+ * await app.doubleClick('.text-content');
338
+ *
339
+ * // Double-click with custom wait
340
+ * await app.doubleClick('#expandable-item', { timeout: 5000 });
341
+ * ```
342
+ */
45
343
  doubleClick(element: WebElement | By | string, { timeout, pollTimeout }?: {
46
344
  timeout?: number;
47
345
  pollTimeout?: number;
48
346
  }): Promise<void>;
347
+ /**
348
+ * Waits for an element to stop animating, then clicks it.
349
+ *
350
+ * Perfect for clicking elements that are animating into view (slides, fades, etc.).
351
+ * Prevents clicks during animation which can cause missed clicks or wrong targets.
352
+ *
353
+ * @param element - Element to wait for and click (WebElement, By locator, or CSS selector)
354
+ * @param options - Optional configuration
355
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
356
+ * @param options.pollTimeout - Interval between animation checks in milliseconds (default: 50)
357
+ * @returns Promise that resolves when element is stable and clicked
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * // Click button that slides into view
362
+ * await app.waitForAnimationAndClick('.animated-button');
363
+ *
364
+ * // Click element in animated modal
365
+ * await app.waitForAnimationAndClick('.modal .submit-btn', { timeout: 5000 });
366
+ * ```
367
+ */
49
368
  waitForAnimationAndClick(element: WebElement | By | string, { timeout, pollTimeout }?: {
50
369
  timeout?: number;
51
370
  pollTimeout?: number;
52
371
  }): Promise<void>;
372
+ /**
373
+ * Scrolls element into view and then clicks it.
374
+ *
375
+ * Handles elements that are not initially in viewport. Scrolls the element to the center
376
+ * of the viewport before clicking, ensuring reliable clicks on off-screen elements.
377
+ *
378
+ * @param element - Element to scroll to and click (WebElement, By locator, or CSS selector)
379
+ * @param options - Optional configuration
380
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
381
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
382
+ * @returns Promise that resolves when element is scrolled into view and clicked
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * // Click element at bottom of page
387
+ * await app.scrollAndClick('#footer-button');
388
+ *
389
+ * // Scroll and click in long form
390
+ * await app.scrollAndClick('.form-submit', { timeout: 5000 });
391
+ *
392
+ * // Click element in scrollable container
393
+ * await app.scrollAndClick('.list-item:last-child');
394
+ * ```
395
+ */
53
396
  scrollAndClick(element: WebElement | By | string, { timeout, pollTimeout }?: {
54
397
  timeout?: number;
55
398
  pollTimeout?: number;
56
399
  }): Promise<void>;
400
+ /**
401
+ * Scrolls an element into the viewport without clicking it.
402
+ *
403
+ * Useful when you need an element visible for screenshots, visibility checks, or
404
+ * before performing other actions. Centers the element in the viewport.
405
+ *
406
+ * @param locator - Element to scroll to (By locator or CSS selector)
407
+ * @param options - Optional configuration
408
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
409
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
410
+ * @returns Promise that resolves when element is scrolled into view
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * // Scroll to element for screenshot
415
+ * await app.scrollIntoView('#chart');
416
+ * const screenshot = await app.getScreenshot();
417
+ *
418
+ * // Scroll before checking visibility
419
+ * await app.scrollIntoView('.lazy-load-content');
420
+ * await app.expect('.lazy-load-content').toBeVisible();
421
+ * ```
422
+ */
57
423
  scrollIntoView(locator: By | string, { timeout, pollTimeout }?: {
58
424
  timeout?: number;
59
425
  pollTimeout?: number;
60
426
  }): Promise<void>;
427
+ /**
428
+ * Drags a source element and drops it onto a target element.
429
+ *
430
+ * Performs a complete drag-and-drop operation, useful for testing sortable lists,
431
+ * drag-and-drop file uploads, kanban boards, and similar interactions.
432
+ *
433
+ * @param source - Element to drag (WebElement or By locator)
434
+ * @param target - Element to drop onto (WebElement or By locator)
435
+ * @returns Promise that resolves when drag-and-drop completes
436
+ *
437
+ * @example
438
+ * ```typescript
439
+ * // Drag list item to reorder
440
+ * await app.dragTo(
441
+ * By.css('.list-item:nth-child(1)'),
442
+ * By.css('.list-item:nth-child(3)')
443
+ * );
444
+ *
445
+ * // Drag file to upload area
446
+ * const file = await app.find('.file-icon');
447
+ * const dropzone = await app.find('.upload-dropzone');
448
+ * await app.dragTo(file, dropzone);
449
+ *
450
+ * // Drag card between columns (kanban)
451
+ * await app.dragTo('#card-1', '#column-done');
452
+ * ```
453
+ */
61
454
  dragTo(source: WebElement | By, target: WebElement | By): Promise<void>;
455
+ /**
456
+ * Drags an element by a specified pixel offset.
457
+ *
458
+ * Moves an element by dragging it a specific number of pixels in X and Y directions.
459
+ * Useful for testing sliders, resizable panels, draggable windows, and custom drag interactions.
460
+ *
461
+ * @param element - Element to drag (WebElement, By locator, or CSS selector)
462
+ * @param offsetX - Horizontal offset in pixels (positive = right, negative = left)
463
+ * @param offsetY - Vertical offset in pixels (positive = down, negative = up)
464
+ * @returns Promise that resolves when drag completes
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * // Drag slider to the right
469
+ * await app.dragByOffset('.slider-handle', 100, 0);
470
+ *
471
+ * // Drag element down and left
472
+ * await app.dragByOffset('.draggable-box', -50, 75);
473
+ *
474
+ * // Resize panel by dragging splitter
475
+ * await app.dragByOffset('.splitter', 0, -100);
476
+ * ```
477
+ */
62
478
  dragByOffset(element: WebElement | By | string, offsetX: number, offsetY: number): Promise<void>;
479
+ /**
480
+ * Types text into an input element.
481
+ *
482
+ * Automatically finds the element, optionally clears existing content, types the text,
483
+ * and can optionally press Enter after typing. Perfect for form filling and text input.
484
+ *
485
+ * @param element - Input element to type into (WebElement, By locator, or CSS selector)
486
+ * @param text - Text to type
487
+ * @param options - Optional configuration
488
+ * @param options.clear - Whether to clear existing content first (default: true)
489
+ * @param options.sendEnter - Whether to press Enter after typing (default: false)
490
+ * @returns Promise that resolves when typing completes
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * // Type into input (clears existing text by default)
495
+ * await app.type('#username', 'testuser');
496
+ *
497
+ * // Type and submit with Enter
498
+ * await app.type('#search', 'search query', { sendEnter: true });
499
+ *
500
+ * // Type without clearing existing text
501
+ * await app.type('#notes', 'additional text', { clear: false });
502
+ *
503
+ * // Fill form fields
504
+ * await app.type('#email', 'user@example.com');
505
+ * await app.type('#password', 'secret123');
506
+ * await app.click('#login-button');
507
+ * ```
508
+ */
63
509
  type(element: WebElement | By | string, text: string, { clear, sendEnter }?: {
64
510
  clear?: boolean;
65
511
  sendEnter?: boolean;
66
512
  }): Promise<void>;
513
+ /**
514
+ * Sends a single keyboard key press.
515
+ *
516
+ * Simulates pressing a keyboard key. Use Selenium's Key constants for special keys.
517
+ *
518
+ * @param key - Key to press (use Key.ENTER, Key.TAB, Key.ESCAPE, etc.)
519
+ * @returns Promise that resolves when key press completes
520
+ *
521
+ * @example
522
+ * ```typescript
523
+ * import { Key } from '@kendo/kendo-e2e';
524
+ *
525
+ * // Press Enter
526
+ * await app.sendKey(Key.ENTER);
527
+ *
528
+ * // Press Tab to move focus
529
+ * await app.sendKey(Key.TAB);
530
+ *
531
+ * // Press Escape to close modal
532
+ * await app.sendKey(Key.ESCAPE);
533
+ *
534
+ * // Press Arrow Down
535
+ * await app.sendKey(Key.ARROW_DOWN);
536
+ * ```
537
+ */
67
538
  sendKey(key: string): Promise<void>;
539
+ /**
540
+ * Sends a two-key combination (e.g., Ctrl+C).
541
+ *
542
+ * Convenience method for common two-key combinations. For more keys, use {@link sendKeysCombination}.
543
+ *
544
+ * @param key1 - First key (typically a modifier like Key.CONTROL)
545
+ * @param key2 - Second key
546
+ * @returns Promise that resolves when key combination completes
547
+ *
548
+ * @example
549
+ * ```typescript
550
+ * import { Key } from '@kendo/kendo-e2e';
551
+ *
552
+ * // Copy text
553
+ * await app.sendKeyCombination(Key.CONTROL, 'c');
554
+ *
555
+ * // Paste text
556
+ * await app.sendKeyCombination(Key.CONTROL, 'v');
557
+ *
558
+ * // Open browser dev tools (F12 might not work in some contexts)
559
+ * await app.sendKeyCombination(Key.CONTROL, Key.SHIFT);
560
+ * ```
561
+ */
68
562
  sendKeyCombination(key1: string, key2: string): Promise<void>;
563
+ /**
564
+ * Sends a combination of multiple keyboard keys simultaneously.
565
+ *
566
+ * Holds down all keys in order, then releases them in reverse order, simulating
567
+ * a realistic key combination press.
568
+ *
569
+ * @param keys - Array of keys to press together
570
+ * @returns Promise that resolves when key combination completes
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * import { Key } from '@kendo/kendo-e2e';
575
+ *
576
+ * // Ctrl+Shift+Delete
577
+ * await app.sendKeysCombination([Key.CONTROL, Key.SHIFT, Key.DELETE]);
578
+ *
579
+ * // Select all (Ctrl+A)
580
+ * await app.sendKeysCombination([Key.CONTROL, 'a']);
581
+ *
582
+ * // Custom three-key combo
583
+ * await app.sendKeysCombination([Key.ALT, Key.SHIFT, 'F']);
584
+ * ```
585
+ */
69
586
  sendKeysCombination(keys: string[]): Promise<void>;
587
+ /**
588
+ * Sends Ctrl+key on Windows/Linux or Cmd+key on macOS automatically.
589
+ *
590
+ * Cross-platform helper that uses the appropriate modifier key for the current OS.
591
+ * Perfect for common shortcuts like copy, paste, save, etc.
592
+ *
593
+ * @param key - Key to combine with Ctrl/Cmd
594
+ * @returns Promise that resolves when key combination completes
595
+ *
596
+ * @example
597
+ * ```typescript
598
+ * // Copy (Ctrl+C on Windows/Linux, Cmd+C on macOS)
599
+ * await app.sendControlKeyCombination('c');
600
+ *
601
+ * // Paste (cross-platform)
602
+ * await app.sendControlKeyCombination('v');
603
+ *
604
+ * // Select all (cross-platform)
605
+ * await app.sendControlKeyCombination('a');
606
+ *
607
+ * // Save (cross-platform)
608
+ * await app.sendControlKeyCombination('s');
609
+ * ```
610
+ */
70
611
  sendControlKeyCombination(key: string): Promise<void>;
71
612
  isVisible(element: WebElement | By | string, { timeout, pollTimeout }?: {
72
613
  timeout?: number;
@@ -91,38 +632,267 @@ export declare class WebApp {
91
632
  hasAttribute(element: WebElement | By | string, attribute: string, value: string, exactMatch?: boolean): Promise<boolean>;
92
633
  hasClass(element: WebElement | By | string, value: string, exactMatch?: boolean): Promise<boolean>;
93
634
  sleep(milliseconds: number): Promise<void>;
635
+ /**
636
+ * Waits for a condition to become true.
637
+ *
638
+ * Core waiting method that polls a condition until it returns true or timeout is reached.
639
+ * Use predefined conditions from {@link EC} class or create custom conditions.
640
+ *
641
+ * @param condition - Condition function or WebElementCondition to wait for
642
+ * @param options - Optional configuration
643
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
644
+ * @param options.message - Custom error message if condition times out (default: 'Failed to satisfy condition.')
645
+ * @param options.pollTimeout - Interval between condition checks in milliseconds (default: 25)
646
+ * @returns Promise that resolves when condition is met
647
+ * @throws Error with the specified message if condition is not met within timeout
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * // Wait for element to be visible
652
+ * await app.wait(EC.isVisible('#modal'));
653
+ *
654
+ * // Wait with custom timeout and message
655
+ * await app.wait(EC.hasText(element, 'Success'), {
656
+ * timeout: 15000,
657
+ * message: 'Success message did not appear'
658
+ * });
659
+ *
660
+ * // Wait for custom condition
661
+ * await app.wait(async () => {
662
+ * const count = await app.findAll('.item');
663
+ * return count.length > 5;
664
+ * }, { message: 'Less than 5 items found' });
665
+ * ```
666
+ */
94
667
  wait(condition: WebElementCondition | WaitCondition, { timeout, message, pollTimeout }?: {
95
668
  timeout?: number;
96
669
  message?: string;
97
670
  pollTimeout?: number;
98
671
  }): Promise<void>;
672
+ /**
673
+ * Waits for a condition without throwing an error if it fails.
674
+ *
675
+ * Returns true if condition is met, false if timeout is reached. Perfect for conditional
676
+ * logic in tests where you want to check if something happened without failing the test.
677
+ *
678
+ * @param condition - Condition function or WebElementCondition to wait for
679
+ * @param options - Optional configuration
680
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
681
+ * @param options.pollTimeout - Interval between condition checks in milliseconds (default: 25)
682
+ * @returns Promise resolving to true if condition met, false if timeout reached
683
+ *
684
+ * @example
685
+ * ```typescript
686
+ * // Check if element appears (don't fail if it doesn't)
687
+ * const appeared = await app.waitSafely(EC.isVisible('.optional-message'));
688
+ * if (appeared) {
689
+ * console.log('Message was shown');
690
+ * }
691
+ *
692
+ * // Conditional test flow
693
+ * const hasModal = await app.waitSafely(EC.isVisible('.modal'), { timeout: 3000 });
694
+ * if (hasModal) {
695
+ * await app.click('.modal .close');
696
+ * }
697
+ *
698
+ * // Check if element has specific text
699
+ * const hasText = await app.waitSafely(EC.hasText('#status', 'Complete'));
700
+ * ```
701
+ */
99
702
  waitSafely(condition: WebElementCondition | WaitCondition, { timeout, pollTimeout }?: {
100
703
  timeout?: number;
101
704
  pollTimeout?: number;
102
705
  }): Promise<boolean>;
706
+ /**
707
+ * Waits for an element to stop moving or resizing (animation to complete).
708
+ *
709
+ * Monitors element position and size, waiting until they remain stable for a poll interval.
710
+ * Essential for reliable interaction with animated elements.
711
+ *
712
+ * @param element - Element to monitor (WebElement, By locator, or CSS selector)
713
+ * @param options - Optional configuration
714
+ * @param options.timeout - Maximum time to wait in milliseconds (default: 10000)
715
+ * @param options.pollTimeout - Interval between stability checks in milliseconds (default: 50)
716
+ * @returns Promise that resolves when element is stable
717
+ * @throws Error if element doesn't stabilize within timeout
718
+ *
719
+ * @example
720
+ * ```typescript
721
+ * // Wait for sliding panel to stop
722
+ * await app.waitForAnimation('.slide-panel');
723
+ * await app.click('.slide-panel button');
724
+ *
725
+ * // Wait for expanding accordion
726
+ * await app.click('.accordion-header');
727
+ * await app.waitForAnimation('.accordion-content');
728
+ *
729
+ * // Use before taking screenshots of animated content
730
+ * await app.waitForAnimation('.chart');
731
+ * const screenshot = await app.getScreenshot();
732
+ * ```
733
+ */
103
734
  waitForAnimation(element: WebElement | By | string, { timeout, pollTimeout }?: {
104
735
  timeout?: number;
105
736
  pollTimeout?: number;
106
737
  }): Promise<void>;
107
738
  getScreenshot(): Promise<string>;
739
+ /**
740
+ * @deprecated Use executeScript with proper types instead
741
+ * @internal
742
+ */
108
743
  executeScript(script: string | ((...args: unknown[]) => unknown)): Promise<unknown>;
744
+ /**
745
+ * Gets the visible text content of an element.
746
+ *
747
+ * Returns the text that would be visible to a user, excluding hidden elements.
748
+ * Automatically finds the element if a locator is provided.
749
+ *
750
+ * @param element - Element to get text from (WebElement, By locator, or CSS selector)
751
+ * @returns Promise resolving to the element's text, or undefined if element has no text
752
+ *
753
+ * @example
754
+ * ```typescript
755
+ * // Get button text
756
+ * const buttonText = await app.getText('#submit-btn');
757
+ * console.log(buttonText); // 'Submit Form'
758
+ *
759
+ * // Get paragraph content
760
+ * const message = await app.getText('.success-message');
761
+ *
762
+ * // Get text from found element
763
+ * const element = await app.find('.label');
764
+ * const text = await app.getText(element);
765
+ * ```
766
+ */
109
767
  getText(element: WebElement | By | string): Promise<string>;
768
+ /**
769
+ * Gets the value of an HTML attribute from an element.
770
+ *
771
+ * Retrieves attribute values like 'href', 'src', 'disabled', 'data-*', etc.
772
+ * Returns null if the attribute doesn't exist.
773
+ *
774
+ * @param element - Element to get attribute from (WebElement, By locator, or CSS selector)
775
+ * @param attribute - Name of the attribute to retrieve
776
+ * @returns Promise resolving to the attribute value or null
777
+ *
778
+ * @example
779
+ * ```typescript
780
+ * // Get link href
781
+ * const url = await app.getAttribute('a.download', 'href');
782
+ *
783
+ * // Check if button is disabled
784
+ * const isDisabled = await app.getAttribute('#submit', 'disabled');
785
+ *
786
+ * // Get data attribute
787
+ * const userId = await app.getAttribute('.user', 'data-user-id');
788
+ *
789
+ * // Get input value
790
+ * const value = await app.getAttribute('#email', 'value');
791
+ * ```
792
+ */
110
793
  getAttribute(element: WebElement | By | string, attribute: string): Promise<string>;
794
+ /**
795
+ * Gets a JavaScript property value from an element.
796
+ *
797
+ * Different from {@link getAttribute} - this gets DOM properties (like 'value', 'checked')
798
+ * which may differ from HTML attributes. Properties reflect the current state.
799
+ *
800
+ * @param element - Element to get property from (WebElement, By locator, or CSS selector)
801
+ * @param property - Name of the property to retrieve
802
+ * @returns Promise resolving to the property value
803
+ *
804
+ * @example
805
+ * ```typescript
806
+ * // Get checkbox checked state (property, not attribute)
807
+ * const isChecked = await app.getProperty('#agree', 'checked');
808
+ *
809
+ * // Get input value (current value, not initial)
810
+ * const currentValue = await app.getProperty('#username', 'value');
811
+ *
812
+ * // Get element's innerHTML
813
+ * const html = await app.getProperty('.container', 'innerHTML');
814
+ *
815
+ * // Get computed style property
816
+ * const display = await app.getProperty('#element', 'style');
817
+ * ```
818
+ */
111
819
  getProperty(element: WebElement | By | string, property: string): Promise<string>;
820
+ /**
821
+ * Gets the text color (color CSS property) of an element as hex value.
822
+ *
823
+ * Converts the color from any format (rgb, rgba, named) to hex format (#RRGGBB).
824
+ * Useful for visual testing and theme verification.
825
+ *
826
+ * @param element - Element to get color from (WebElement, By locator, or CSS selector)
827
+ * @returns Promise resolving to hex color string (e.g., '#ff0000')
828
+ *
829
+ * @example
830
+ * ```typescript
831
+ * // Check error message color
832
+ * const errorColor = await app.getColor('.error-message');
833
+ * expect(errorColor).toBe('#ff0000'); // red
834
+ *
835
+ * // Verify link color
836
+ * const linkColor = await app.getColor('a.primary');
837
+ *
838
+ * // Check themed text color
839
+ * const textColor = await app.getColor('.themed-text');
840
+ * ```
841
+ */
112
842
  getColor(element: WebElement | By | string): Promise<string>;
843
+ /**
844
+ * Gets the background color (background-color CSS property) of an element as hex value.
845
+ *
846
+ * Converts the background color from any format to hex format (#RRGGBB).
847
+ * Useful for verifying button states, highlights, and theme colors.
848
+ *
849
+ * @param element - Element to get background color from (WebElement, By locator, or CSS selector)
850
+ * @returns Promise resolving to hex color string (e.g., '#ffffff')
851
+ *
852
+ * @example
853
+ * ```typescript
854
+ * // Check button background
855
+ * const btnBg = await app.getBackgroundColor('#primary-btn');
856
+ * expect(btnBg).toBe('#007bff'); // bootstrap primary
857
+ *
858
+ * // Verify selected item highlight
859
+ * const selectedBg = await app.getBackgroundColor('.selected');
860
+ *
861
+ * // Check alert background color
862
+ * const alertBg = await app.getBackgroundColor('.alert-warning');
863
+ * ```
864
+ */
113
865
  getBackgroundColor(element: WebElement | By | string): Promise<string>;
114
866
  /**
115
- * Hides the text caret either globally (all input & textarea elements) or for a specific element.
867
+ * Hides the text cursor/caret for cleaner screenshots.
116
868
  *
117
- * When no element is provided, a <style> tag is injected that sets caret-color to transparent
118
- * for all input and textarea elements. This is reversible only by page reload or manually removing
119
- * the injected style element.
869
+ * When called without arguments, hides the cursor globally for all input/textarea elements.
870
+ * When called with an element, hides the cursor only for that specific element.
871
+ * Global hiding persists until page reload.
120
872
  *
121
- * When an element is provided (WebElement, By locator, or CSS selector string), the element is
122
- * located (if needed) and its caret color is set to transparent.
873
+ * @param element - Optional specific element to hide cursor for (WebElement, By locator, or CSS selector)
874
+ * @param options - Optional configuration
875
+ * @param options.timeout - Maximum time to wait for element in milliseconds (default: 10000)
876
+ * @param options.pollTimeout - Interval between retry attempts in milliseconds (default: 25)
877
+ * @returns Promise that resolves when cursor is hidden
878
+ *
879
+ * @example
880
+ * ```typescript
881
+ * // Hide cursor globally before screenshot
882
+ * await app.hideCursor();
883
+ * const screenshot = await app.getScreenshot();
884
+ *
885
+ * // Hide cursor for specific input
886
+ * await app.focus('#username');
887
+ * await app.hideCursor('#username');
888
+ * const inputScreenshot = await app.getScreenshot();
889
+ *
890
+ * // Hide cursor in focused field for visual test
891
+ * await app.type('#search', 'test');
892
+ * await app.hideCursor('#search');
893
+ * ```
123
894
  *
124
- * @param element Optional element whose caret should be hidden (WebElement instance, By locator, or CSS selector string).
125
- * @param options Optional timeout and pollTimeout for element location.
895
+ * @see For more details, see [hideCursor documentation](../../docs/hideCursor.md)
126
896
  */
127
897
  hideCursor(element?: WebElement | By | string, { timeout, pollTimeout }?: {
128
898
  timeout?: number;