@progress/kendo-e2e 4.11.2 → 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.
@@ -0,0 +1,337 @@
1
+ # Getting Started with kendo-e2e
2
+
3
+ **kendo-e2e** is a Selenium-based testing library with **automatic waiting** built-in, making your tests faster to write and more reliable.
4
+
5
+ ## Why kendo-e2e?
6
+
7
+ Traditional Selenium tests are flaky because they require manual waits. kendo-e2e solves this by:
8
+
9
+ ✅ **Automatic waiting** - Every method waits for elements automatically
10
+ ✅ **No StaleElementReferenceException** - Built-in retry logic
11
+ ✅ **Modern expect API** - Playwright-style assertions with auto-retry
12
+ ✅ **Less code** - Write tests faster with intuitive methods
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @kendo/kendo-e2e --save-dev
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### Basic Browser Test
23
+
24
+ ```typescript
25
+ import { Browser } from '@kendo/kendo-e2e';
26
+
27
+ describe('My First Test', () => {
28
+ let browser: Browser;
29
+
30
+ beforeAll(async () => {
31
+ browser = new Browser();
32
+ });
33
+
34
+ afterAll(async () => {
35
+ await browser.close();
36
+ });
37
+
38
+ it('should load the page and interact', async () => {
39
+ // Navigate to URL
40
+ await browser.navigateTo('https://example.com');
41
+
42
+ // Click button (automatically waits for it to appear)
43
+ await browser.click('#login-button');
44
+
45
+ // Type in input (automatically waits and clears)
46
+ await browser.type('#username', 'testuser');
47
+ await browser.type('#password', 'secret123');
48
+
49
+ // Submit form
50
+ await browser.click('#submit');
51
+
52
+ // Assert with automatic retry (waits up to 3s by default)
53
+ await browser.expect('.welcome-message').toHaveText('Welcome testuser');
54
+ await browser.expect('.dashboard').toBeVisible();
55
+ });
56
+ });
57
+ ```
58
+
59
+ ### Key Differences from Plain Selenium
60
+
61
+ | Plain Selenium | kendo-e2e |
62
+ |----------------|-----------|
63
+ | `driver.findElement(By.css('#btn'))` then manual wait | `await browser.click('#btn')` |
64
+ | Manual `WebDriverWait` everywhere | Automatic waiting built-in |
65
+ | `StaleElementReferenceException` errors | Automatic retry handles it |
66
+ | Complex wait conditions | Simple `expect()` API |
67
+
68
+ ## Configuration
69
+
70
+ Control browser settings via environment variables:
71
+
72
+ ```bash
73
+ # Browser selection
74
+ BROWSER_NAME=chrome # chrome, firefox, safari, MicrosoftEdge
75
+ HEADLESS=true # Run without UI (default: false)
76
+
77
+ # Window size
78
+ BROWSER_WIDTH=1920
79
+ BROWSER_HEIGHT=1080
80
+ ```
81
+
82
+ ### In Code Configuration
83
+
84
+ ```typescript
85
+ // Mobile emulation
86
+ const browser = new Browser({
87
+ mobileEmulation: { deviceName: 'iPhone 14 Pro Max' }
88
+ });
89
+
90
+ // Custom window size
91
+ const browser = new Browser();
92
+ await browser.resizeWindow(1920, 1080);
93
+
94
+ // BiDi protocol for advanced features
95
+ const browser = new Browser({ enableBidi: true });
96
+ ```
97
+
98
+ ## Common Patterns
99
+
100
+ ### Finding Elements
101
+
102
+ ```typescript
103
+ // Find single element (waits automatically)
104
+ const button = await browser.find('#submit');
105
+ const header = await browser.find('.page-header');
106
+
107
+ // Find all matching elements (no wait)
108
+ const items = await browser.findAll('.list-item');
109
+
110
+ // Find with wait for at least one
111
+ const results = await browser.findAllWithTimeout('.search-result');
112
+
113
+ // Find child within parent
114
+ const dialog = await browser.find('.modal');
115
+ const closeBtn = await browser.findChild(dialog, '.close-button');
116
+ ```
117
+
118
+ ### Interacting with Elements
119
+
120
+ ```typescript
121
+ // Click (waits for visible and enabled)
122
+ await browser.click('#button');
123
+
124
+ // Type text (clears by default)
125
+ await browser.type('#input', 'text');
126
+
127
+ // Type without clearing
128
+ await browser.type('#notes', 'more text', { clear: false });
129
+
130
+ // Type and press Enter
131
+ await browser.type('#search', 'query', { sendEnter: true });
132
+
133
+ // Hover over element
134
+ await browser.hover('.menu-item');
135
+
136
+ // Double-click
137
+ await browser.doubleClick('.file-icon');
138
+
139
+ // Right-click
140
+ await browser.contextClick('.item');
141
+
142
+ // Drag and drop
143
+ await browser.dragTo('#source', '#target');
144
+ ```
145
+
146
+ ### Waiting and Assertions
147
+
148
+ ```typescript
149
+ // Modern expect API (auto-retries)
150
+ await browser.expect('#message').toHaveText('Success');
151
+ await browser.expect('.modal').toBeVisible();
152
+ await browser.expect('.spinner').not.toBeVisible();
153
+
154
+ // Wait for condition
155
+ import { EC } from '@kendo/kendo-e2e';
156
+ await browser.wait(EC.isVisible('#element'));
157
+
158
+ // Wait safely (returns boolean, doesn't throw)
159
+ const appeared = await browser.waitSafely(EC.isVisible('.optional'));
160
+ if (appeared) {
161
+ await browser.click('.optional .close');
162
+ }
163
+ ```
164
+
165
+ ### Keyboard Interactions
166
+
167
+ ```typescript
168
+ import { Key } from '@kendo/kendo-e2e';
169
+
170
+ // Send single key
171
+ await browser.sendKey(Key.ENTER);
172
+ await browser.sendKey(Key.TAB);
173
+ await browser.sendKey(Key.ESCAPE);
174
+
175
+ // Key combinations
176
+ await browser.sendKeyCombination(Key.CONTROL, 'c'); // Copy
177
+
178
+ // Cross-platform Ctrl/Cmd
179
+ await browser.sendControlKeyCombination('v'); // Paste
180
+ ```
181
+
182
+ ### Working with Forms
183
+
184
+ ```typescript
185
+ // Fill out a form
186
+ await browser.type('#firstName', 'John');
187
+ await browser.type('#lastName', 'Doe');
188
+ await browser.type('#email', 'john@example.com');
189
+ await browser.click('#submit');
190
+
191
+ // Verify form submission
192
+ await browser.expect('.success-message').toBeVisible();
193
+ await browser.expect('.success-message').toHaveText('Form submitted successfully');
194
+ ```
195
+
196
+ ## Best Practices
197
+
198
+ ### ✅ Do This
199
+
200
+ ```typescript
201
+ // Use expect() for assertions with auto-retry
202
+ await browser.expect('#status').toHaveText('Complete');
203
+
204
+ // Use CSS selectors (simpler, faster)
205
+ await browser.click('#submit');
206
+ await browser.click('.btn-primary');
207
+
208
+ // Chain operations naturally
209
+ await browser.navigateTo('https://example.com');
210
+ await browser.click('#login');
211
+ await browser.type('#username', 'user');
212
+ await browser.click('#submit');
213
+ await browser.expect('.dashboard').toBeVisible();
214
+ ```
215
+
216
+ ### ❌ Avoid This
217
+
218
+ ```typescript
219
+ // DON'T add manual sleeps - automatic waiting handles it
220
+ await browser.sleep(2000); // ❌ Unnecessary
221
+
222
+ // DON'T use complex XPath when CSS works
223
+ await browser.click(By.xpath('//div[@id="submit"]')); // ❌
224
+ await browser.click('#submit'); // ✅ Better
225
+
226
+ // DON'T manually wait before actions
227
+ await browser.wait(EC.isVisible('#button'));
228
+ await browser.click('#button'); // ❌ click() already waits!
229
+ // Just do:
230
+ await browser.click('#button'); // ✅
231
+ ```
232
+
233
+ ## Testing Checklist
234
+
235
+ Essential checks for every test:
236
+
237
+ ```typescript
238
+ it('should work without errors', async () => {
239
+ // Clear browser console
240
+ await browser.clearLogs();
241
+
242
+ // Your test actions
243
+ await browser.navigateTo('https://example.com');
244
+ await browser.click('#trigger-action');
245
+
246
+ // Check for console errors
247
+ const errors = await browser.getErrorLogs();
248
+ expect(errors.length).toBe(0);
249
+
250
+ // Check accessibility
251
+ const a11yViolations = await browser.getAccessibilityViolations();
252
+ expect(a11yViolations.length).toBe(0);
253
+ });
254
+ ```
255
+
256
+ ## Next Steps
257
+
258
+ - 📚 Read [API Reference](./API_REFERENCE.md) for complete method documentation
259
+ - 🎯 Check [Common Patterns](./PATTERNS.md) for real-world examples
260
+
261
+ ## Example Test Suite
262
+
263
+ ```typescript
264
+ import { Browser } from '@kendo/kendo-e2e';
265
+
266
+ describe('Login Flow', () => {
267
+ let browser: Browser;
268
+
269
+ beforeAll(async () => {
270
+ browser = new Browser();
271
+ });
272
+
273
+ afterAll(async () => {
274
+ await browser.close();
275
+ });
276
+
277
+ beforeEach(async () => {
278
+ await browser.navigateTo('https://example.com/login');
279
+ await browser.clearLogs();
280
+ });
281
+
282
+ it('should show login form', async () => {
283
+ await browser.expect('#login-form').toBeVisible();
284
+ await browser.expect('#username').toBeVisible();
285
+ await browser.expect('#password').toBeVisible();
286
+ });
287
+
288
+ it('should login successfully', async () => {
289
+ await browser.type('#username', 'testuser');
290
+ await browser.type('#password', 'password123');
291
+ await browser.click('#login-button');
292
+
293
+ await browser.expect('.welcome-message').toBeVisible();
294
+ await browser.expect('.welcome-message').toHaveText('Welcome testuser');
295
+
296
+ // Verify no console errors
297
+ const errors = await browser.getErrorLogs();
298
+ expect(errors.length).toBe(0);
299
+ });
300
+
301
+ it('should show error for invalid credentials', async () => {
302
+ await browser.type('#username', 'invalid');
303
+ await browser.type('#password', 'wrong');
304
+ await browser.click('#login-button');
305
+
306
+ await browser.expect('.error-message').toBeVisible();
307
+ await browser.expect('.error-message').toHaveText('Invalid credentials');
308
+ });
309
+ });
310
+ ```
311
+
312
+ ## Troubleshooting
313
+
314
+ ### Tests are slow
315
+ - Reduce timeouts for faster feedback: `await browser.expect('#el').toBeVisible({ timeout: 5000 })`
316
+ - Use headless mode: `HEADLESS=true npm test`
317
+
318
+ ### Element not found
319
+ - Check your selector is correct
320
+ - Verify element exists in the DOM when expected
321
+ - Try using `findAllWithTimeout` if content loads dynamically
322
+
323
+ ### Flaky tests
324
+ - Use `expect()` instead of manual waits
325
+ - Ensure proper `beforeAll`/`afterAll` cleanup (start browser once, not per test)
326
+ - Check for timing-dependent logic in your app
327
+
328
+ ### Browser not starting
329
+ - Ensure browser driver is installed
330
+ - Check `BROWSER_NAME` environment variable
331
+ - Verify browser is installed on your system
332
+
333
+ ## Getting Help
334
+
335
+ - Check [examples](../examples/) folder for more samples
336
+ - Review [tests](../tests/) for advanced usage patterns
337
+ - Read method JSDoc in your IDE for inline documentation