lexxit-automation-framework 3.0.3 → 3.0.4

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.
Files changed (54) hide show
  1. package/dist-obf/actions/baseHandler.js +1 -1
  2. package/dist-obf/actions/browserManager.js +1 -1
  3. package/dist-obf/actions/checkboxHandler.js +1 -1
  4. package/dist-obf/actions/clickHandler.js +1 -1
  5. package/dist-obf/actions/customcodehandler.js +1 -1
  6. package/dist-obf/actions/dropdownHandler.js +1 -1
  7. package/dist-obf/actions/radiobuttonHandler.js +1 -1
  8. package/dist-obf/actions/textHandler.js +1 -1
  9. package/dist-obf/api/server.js +1 -1
  10. package/dist-obf/config.js +1 -1
  11. package/dist-obf/executor/functionMap.js +1 -1
  12. package/dist-obf/executor/mapping.js +1 -1
  13. package/dist-obf/executor/scriptExecutor.js +1 -1
  14. package/dist-obf/executor/stepExecutor.js +1 -1
  15. package/dist-obf/runner/testRunner.js +1 -1
  16. package/dist-obf/sse/sseManager.js +1 -1
  17. package/dist-obf/store/executionStore.js +1 -1
  18. package/dist-obf/store/testDataStore.js +1 -1
  19. package/dist-obf/types/types.js +1 -1
  20. package/dist-obf/utils/healingService.js +1 -1
  21. package/dist-obf/utils/locatorService.js +1 -1
  22. package/dist-obf/utils/logger.js +1 -1
  23. package/dist-obf/utils/metadataService.js +1 -1
  24. package/dist-obf/utils/waitConditions.js +1 -1
  25. package/dist-obf/validator/validator.js +1 -1
  26. package/package.json +5 -2
  27. package/npmignore +0 -8
  28. package/public/dashboard.html +0 -591
  29. package/src/actions/baseHandler.ts +0 -351
  30. package/src/actions/browserManager.ts +0 -432
  31. package/src/actions/checkboxHandler.ts +0 -276
  32. package/src/actions/clickHandler.ts +0 -513
  33. package/src/actions/customcodehandler.ts +0 -251
  34. package/src/actions/dropdownHandler.ts +0 -501
  35. package/src/actions/radiobuttonHandler.ts +0 -286
  36. package/src/actions/textHandler.ts +0 -498
  37. package/src/api/server.ts +0 -210
  38. package/src/config.ts +0 -7
  39. package/src/executor/functionMap.ts +0 -153
  40. package/src/executor/mapping.ts +0 -70
  41. package/src/executor/scriptExecutor.ts +0 -162
  42. package/src/executor/stepExecutor.ts +0 -289
  43. package/src/runner/testRunner.ts +0 -78
  44. package/src/sse/sseManager.ts +0 -130
  45. package/src/store/executionStore.ts +0 -152
  46. package/src/store/testDataStore.ts +0 -46
  47. package/src/types/types.ts +0 -159
  48. package/src/utils/healingService.ts +0 -210
  49. package/src/utils/locatorService.ts +0 -73
  50. package/src/utils/logger.ts +0 -27
  51. package/src/utils/metadataService.ts +0 -137
  52. package/src/utils/waitConditions.ts +0 -141
  53. package/src/validator/validator.ts +0 -140
  54. package/tsconfig.json +0 -16
@@ -1,513 +0,0 @@
1
- // import { Page } from 'playwright';
2
- // import { StepResult, ScreenshotMode } from '../types/types';
3
- // import { DEFAULT_SCREENSHOT_MODE } from '../config';
4
- // import { LocatorService } from '../utils/locatorService';
5
- // import { BaseHandler } from './baseHandler';
6
-
7
- // export class ClickHandler extends BaseHandler{
8
- // private page: Page;
9
- // private screenshotMode: ScreenshotMode;
10
-
11
- // private lastApiResponse: { status: number; url: string; body: any } | null = null;
12
-
13
- // constructor(page: Page, screenshotMode: ScreenshotMode = DEFAULT_SCREENSHOT_MODE) {
14
- // super();
15
- // this.page = page;
16
- // this.screenshotMode = screenshotMode;
17
- // // Capture recent JSON network responses for better failure diagnostics
18
- // try {
19
- // this.page.on('response', async (resp) => {
20
- // try {
21
- // const ct = resp.headers()['content-type'] || '';
22
- // if (ct.includes('application/json') || ct.includes('text/plain') || ct.includes('application/text')) {
23
- // let body: any;
24
- // try {
25
- // body = await resp.json();
26
- // } catch {
27
- // try {
28
- // body = await resp.text();
29
- // } catch {
30
- // body = undefined;
31
- // }
32
- // }
33
-
34
- // this.lastApiResponse = {
35
- // status: resp.status(),
36
- // url: resp.url(),
37
- // body,
38
- // };
39
- // }
40
- // } catch {
41
- // // swallow
42
- // }
43
- // });
44
- // } catch {
45
- // // ignore if page event binding fails
46
- // }
47
- // }
48
-
49
- // private getLastApiResponse() {
50
- // return this.lastApiResponse;
51
- // }
52
-
53
- // // ─── Helpers ───────────────────────────────────────────────────────────────
54
-
55
- // // private getStartTime(): string {
56
- // // return new Date().toISOString();
57
- // // }
58
-
59
- // // private getDuration(startMs: number): number {
60
- // // return Date.now() - startMs;
61
- // // }
62
-
63
- // // private buildResult(
64
- // // status: 'PASS' | 'FAIL',
65
- // // expected_result: string,
66
- // // comments: string,
67
- // // startMs: number,
68
- // // startTime: string,
69
- // // step_name: string = '',
70
- // // uid: string | null = null,
71
- // // obj_uid: string | null = null,
72
- // // page_uid: string | null = null
73
- // // ): StepResult {
74
- // // return {
75
- // // uid,
76
- // // obj_uid,
77
- // // page_uid,
78
- // // step_name,
79
- // // step_script: '',
80
- // // status,
81
- // // expected_result,
82
- // // comments,
83
- // // duration: this.getDuration(startMs),
84
- // // start_time: startTime
85
- // // };
86
- // // }
87
-
88
- // // private async captureScreenshot(isFailure: boolean): Promise<string | undefined> {
89
- // // if (this.screenshotMode === 'never') return undefined;
90
- // // if (this.screenshotMode === 'on_failure' && !isFailure) return undefined;
91
- // // try {
92
- // // if (!this.page || this.page.isClosed()) return undefined;
93
- // // const buf = await this.page.screenshot({ type: 'png', fullPage: false });
94
- // // return buf.toString('base64');
95
- // // } catch {
96
- // // return undefined;
97
- // // }
98
- // // }
99
-
100
- // private async capturePageSource(): Promise<string | undefined> {
101
- // try {
102
- // if (!this.page || this.page.isClosed()) return undefined;
103
- // return await this.page.content();
104
- // } catch {
105
- // return undefined;
106
- // }
107
- // }
108
-
109
- // private async captureFailureMetadata(): Promise<{ screenshot?: string; pageSource?: string }> {
110
- // const screenshot = await this.captureScreenshot(true);
111
- // const pageSource = await this.capturePageSource();
112
- // return { screenshot, pageSource };
113
- // }
114
-
115
- // // private classifyError(error: any): string {
116
- // // const msg: string = error?.message || String(error);
117
-
118
- // // if (msg.includes('Element not found') || msg.includes('not visible')) {
119
- // // return `Element not found or not visible: ${msg}`;
120
- // // }
121
- // // if (msg.includes('Timeout') || msg.includes('timeout')) {
122
- // // return `Timeout error - element took too long to respond: ${msg}`;
123
- // // }
124
- // // if (msg.includes('intercepts pointer events') || msg.includes('not visible within')) {
125
- // // return `Element is covered by another element: ${msg}`;
126
- // // }
127
- // // if (msg.includes('not enabled')) {
128
- // // return `Element is disabled: ${msg}`;
129
- // // }
130
- // // if (msg.includes('detached')) {
131
- // // return `Element got detached from DOM: ${msg}`;
132
- // // }
133
- // // if (msg.includes('Target closed') || msg.includes('has been closed')) {
134
- // // return `Browser or page closed unexpectedly: ${msg}`;
135
- // // }
136
- // // if (msg.includes('Navigation') && msg.includes('timeout')) {
137
- // // return `Navigation after click timed out: ${msg}`;
138
- // // }
139
-
140
- // // return `Unexpected error: ${msg}`;
141
- // // }
142
-
143
- // // private appendMatchedLocatorInfo(comments: string, matchedIndex: number, matchedXPath: string): string {
144
- // // if (matchedIndex > 0) {
145
- // // return `${comments} (Matched locator at position ${matchedIndex}: ${matchedXPath})`;
146
- // // }
147
- // // return comments;
148
- // // }
149
-
150
- // // ─── click ─────────────────────────────────────────────────────────────────
151
-
152
- // // async click(label: string, locators: string[], step_name: string = 'Click element'): Promise<StepResult> {
153
- // // const startMs = Date.now();
154
- // // const startTime = this.getStartTime();
155
- // // const expected = `'${label}' clicked successfully`;
156
-
157
- // // try {
158
- // // const resolved = await LocatorService.resolveElement(this.page, locators);
159
- // // await resolved.element.click();
160
-
161
- // // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
162
- // // return this.buildResult('pass', expected, comments, startMs, startTime, step_name);
163
- // // } catch (error: any) {
164
- // // const { screenshot, pageSource } = await this.captureFailureMetadata();
165
- // // return this.buildResult('fail', expected, this.classifyError(error), startMs, startTime, step_name, screenshot, pageSource);
166
- // // }
167
- // // }
168
- // async click(label: string, locators: string[], step_name: string = 'Click element'): Promise<StepResult> {
169
- // const startMs = Date.now();
170
- // const startTime = this.getStartTime();
171
- // const expected = `'${label}' clicked successfully`;
172
-
173
- // try {
174
- // const resolved = await LocatorService.resolveElement(this.page, locators);
175
- // await resolved.element.click();
176
-
177
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
178
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
179
- // } catch (error: any) {
180
- // const sc = await this.captureScreenshot(true);
181
- // const msg = (error?.message || String(error)).toLowerCase();
182
-
183
- // if (
184
- // msg.includes('waiting for locator') ||
185
- // msg.includes('timeout') ||
186
- // msg.includes('no element') ||
187
- // msg.includes('not found') ||
188
- // msg.includes('not visible') ||
189
- // msg.includes('not attached')
190
- // ) {
191
- // const captured = this.getLastApiResponse();
192
- // if (captured) {
193
- // const bodyText = typeof captured.body === 'object' ? JSON.stringify(captured.body, null, 2) : String(captured.body);
194
- // const comments = `Element "${label}" not found on page.\nNetwork response [HTTP ${captured.status}] from ${captured.url}:\n${bodyText}`;
195
- // return this.buildResult('FAIL', expected, comments, startMs, startTime, step_name, sc);
196
- // }
197
- // return this.buildResult('FAIL', expected, `"${label}" not found`, startMs, startTime, step_name, sc);
198
- // }
199
-
200
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
201
- // }
202
- // }
203
-
204
- // // ─── doubleClick ───────────────────────────────────────────────────────────
205
-
206
- // async doubleClick(label: string, locators: string[], step_name: string = 'Double click element'): Promise<StepResult> {
207
- // const startMs = Date.now();
208
- // const startTime = this.getStartTime();
209
- // const expected = `'${label}' double-clicked successfully`;
210
-
211
- // try {
212
- // const resolved = await LocatorService.resolveElement(this.page, locators);
213
- // await resolved.element.dblclick();
214
-
215
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
216
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
217
- // } catch (error: any) {
218
- // const { screenshot, pageSource } = await this.captureFailureMetadata();
219
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, screenshot, pageSource);
220
- // }
221
- // }
222
-
223
- // // ─── rightClick ────────────────────────────────────────────────────────────
224
-
225
- // async rightClick(label: string, locators: string[], step_name: string = 'Right click element'): Promise<StepResult> {
226
- // const startMs = Date.now();
227
- // const startTime = this.getStartTime();
228
- // const expected = `'${label}' right-clicked successfully`;
229
-
230
- // try {
231
- // const resolved = await LocatorService.resolveElement(this.page, locators);
232
- // await resolved.element.click({ button: 'right' });
233
-
234
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
235
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
236
- // } catch (error: any) {
237
- // const { screenshot, pageSource } = await this.captureFailureMetadata();
238
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, screenshot, pageSource);
239
- // }
240
- // }
241
-
242
- // // ─── clickAndWaitForNavigation ─────────────────────────────────────────────
243
-
244
- // async clickAndWaitForNavigation(label: string, locators: string[], step_name: string = 'Click and wait for navigation'): Promise<StepResult> {
245
- // const startMs = Date.now();
246
- // const startTime = this.getStartTime();
247
- // const expected = `'${label}' clicked and navigation completed successfully`;
248
-
249
- // try {
250
- // const resolved = await LocatorService.resolveElement(this.page, locators);
251
- // await Promise.all([
252
- // this.page.waitForNavigation({ waitUntil: 'load', timeout: 30000 }),
253
- // resolved.element.click()
254
- // ]);
255
-
256
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
257
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
258
- // } catch (error: any) {
259
- // const { screenshot, pageSource } = await this.captureFailureMetadata();
260
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, screenshot, pageSource);
261
- // }
262
- // }
263
-
264
- // // ─── hover ─────────────────────────────────────────────────────────────────
265
-
266
- // async hover(label: string, locators: string[], step_name: string = 'Hover element'): Promise<StepResult> {
267
- // const startMs = Date.now();
268
- // const startTime = this.getStartTime();
269
- // const expected = `Hovered over '${label}' successfully`;
270
-
271
- // try {
272
- // const resolved = await LocatorService.resolveElement(this.page, locators);
273
- // await resolved.element.hover();
274
-
275
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
276
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
277
- // } catch (error: any) {
278
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name);
279
- // }
280
- // }
281
-
282
- // // ─── isClickable ───────────────────────────────────────────────────────────
283
-
284
- // async isClickable(label: string, locators: string[], step_name: string = 'Check element is clickable'): Promise<StepResult> {
285
- // const startMs = Date.now();
286
- // const startTime = this.getStartTime();
287
- // const expected = `'${label}' is clickable`;
288
-
289
- // try {
290
- // const resolved = await LocatorService.resolveElement(this.page, locators);
291
- // const isVisible = await resolved.element.isVisible();
292
- // const isEnabled = await resolved.element.isEnabled();
293
-
294
- // if (!isVisible || !isEnabled) {
295
- // const failComments = this.appendMatchedLocatorInfo(
296
- // `'${label}' is not clickable. Visible: ${isVisible}, Enabled: ${isEnabled}`,
297
- // resolved.matchedIndex,
298
- // resolved.matchedXPath
299
- // );
300
- // const { screenshot, pageSource } = await this.captureFailureMetadata();
301
- // return this.buildResult('FAIL', expected, failComments, startMs, startTime, step_name, screenshot, pageSource);
302
- // }
303
-
304
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
305
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
306
- // } catch (error: any) {
307
- // const { screenshot, pageSource } = await this.captureFailureMetadata();
308
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, screenshot, pageSource);
309
- // }
310
- // }
311
-
312
- // // ─── forceClick ────────────────────────────────────────────────────────────
313
-
314
- // async forceClick(label: string, locators: string[], step_name: string = 'Force click element'): Promise<StepResult> {
315
- // const startMs = Date.now();
316
- // const startTime = this.getStartTime();
317
- // const expected = `'${label}' force-clicked successfully`;
318
-
319
- // try {
320
- // const resolved = await LocatorService.resolveElement(this.page, locators);
321
- // await resolved.element.click({ force: true });
322
-
323
- // const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
324
- // return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
325
- // } catch (error: any) {
326
- // const { screenshot, pageSource } = await this.captureFailureMetadata();
327
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, screenshot, pageSource);
328
- // }
329
- // }
330
- // }
331
- import { Page } from 'playwright';
332
- import { StepResult, ScreenshotMode } from '../types/types';
333
- import { DEFAULT_SCREENSHOT_MODE } from '../config';
334
- import { LocatorService } from '../utils/locatorService';
335
- import { BaseHandler } from './baseHandler';
336
-
337
- export class ClickHandler extends BaseHandler {
338
- protected page: Page;
339
-
340
- constructor(page: Page, screenshotMode: ScreenshotMode = DEFAULT_SCREENSHOT_MODE) {
341
- super();
342
- this.page = page;
343
- this.screenshotMode = screenshotMode;
344
- this.setupNetworkCapture(page);
345
- }
346
-
347
- // ─── click ─────────────────────────────────────────────────────────────────
348
-
349
- async click(label: string, locators: string[], step_name: string = 'Click element'): Promise<StepResult> {
350
- const startMs = Date.now();
351
- const startTime = this.getStartTime();
352
- const expected = `'${label}' clicked successfully`;
353
-
354
- try {
355
- const resolved = await LocatorService.resolveElement(this.page, locators);
356
- await resolved.element.click();
357
-
358
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
359
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
360
- } catch (error: any) {
361
- const sc = await this.captureScreenshot(true);
362
- const msg = (error?.message || String(error)).toLowerCase();
363
-
364
- if (
365
- msg.includes('waiting for locator') ||
366
- msg.includes('timeout') ||
367
- msg.includes('no element') ||
368
- msg.includes('not found') ||
369
- msg.includes('not visible') ||
370
- msg.includes('not attached')
371
- ) {
372
- const captured = this.getLastApiResponse();
373
- if (captured) {
374
- const bodyText = typeof captured.body === 'object'
375
- ? JSON.stringify(captured.body, null, 2)
376
- : String(captured.body);
377
- const comments = `Element "${label}" not found on page.\nNetwork response [HTTP ${captured.status}] from ${captured.url}:\n${bodyText}`;
378
- return this.buildResult('FAIL', expected, comments, startMs, startTime, step_name, sc);
379
- }
380
- return this.buildResult('FAIL', expected, `"${label}" not found`, startMs, startTime, step_name, sc);
381
- }
382
-
383
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
384
- }
385
- }
386
-
387
- // ─── doubleClick ───────────────────────────────────────────────────────────
388
-
389
- async doubleClick(label: string, locators: string[], step_name: string = 'Double click element'): Promise<StepResult> {
390
- const startMs = Date.now();
391
- const startTime = this.getStartTime();
392
- const expected = `'${label}' double-clicked successfully`;
393
-
394
- try {
395
- const resolved = await LocatorService.resolveElement(this.page, locators);
396
- await resolved.element.dblclick();
397
-
398
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
399
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
400
- } catch (error: any) {
401
- const sc = await this.captureScreenshot(true);
402
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
403
- }
404
- }
405
-
406
- // ─── rightClick ────────────────────────────────────────────────────────────
407
-
408
- async rightClick(label: string, locators: string[], step_name: string = 'Right click element'): Promise<StepResult> {
409
- const startMs = Date.now();
410
- const startTime = this.getStartTime();
411
- const expected = `'${label}' right-clicked successfully`;
412
-
413
- try {
414
- const resolved = await LocatorService.resolveElement(this.page, locators);
415
- await resolved.element.click({ button: 'right' });
416
-
417
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
418
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
419
- } catch (error: any) {
420
- const sc = await this.captureScreenshot(true);
421
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
422
- }
423
- }
424
-
425
- // ─── clickAndWaitForNavigation ─────────────────────────────────────────────
426
-
427
- async clickAndWaitForNavigation(label: string, locators: string[], step_name: string = 'Click and wait for navigation'): Promise<StepResult> {
428
- const startMs = Date.now();
429
- const startTime = this.getStartTime();
430
- const expected = `'${label}' clicked and navigation completed successfully`;
431
-
432
- try {
433
- const resolved = await LocatorService.resolveElement(this.page, locators);
434
- await Promise.all([
435
- this.page.waitForNavigation({ waitUntil: 'load', timeout: 30000 }),
436
- resolved.element.click()
437
- ]);
438
-
439
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
440
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
441
- } catch (error: any) {
442
- const sc = await this.captureScreenshot(true);
443
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
444
- }
445
- }
446
-
447
- // ─── hover ─────────────────────────────────────────────────────────────────
448
-
449
- async hover(label: string, locators: string[], step_name: string = 'Hover element'): Promise<StepResult> {
450
- const startMs = Date.now();
451
- const startTime = this.getStartTime();
452
- const expected = `Hovered over '${label}' successfully`;
453
-
454
- try {
455
- const resolved = await LocatorService.resolveElement(this.page, locators);
456
- await resolved.element.hover();
457
-
458
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
459
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
460
- } catch (error: any) {
461
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name);
462
- }
463
- }
464
-
465
- // ─── isClickable ───────────────────────────────────────────────────────────
466
-
467
- async isClickable(label: string, locators: string[], step_name: string = 'Check element is clickable'): Promise<StepResult> {
468
- const startMs = Date.now();
469
- const startTime = this.getStartTime();
470
- const expected = `'${label}' is clickable`;
471
-
472
- try {
473
- const resolved = await LocatorService.resolveElement(this.page, locators);
474
- const isVisible = await resolved.element.isVisible();
475
- const isEnabled = await resolved.element.isEnabled();
476
-
477
- if (!isVisible || !isEnabled) {
478
- const sc = await this.captureScreenshot(true);
479
- const failComments = this.appendMatchedLocatorInfo(
480
- `'${label}' is not clickable. Visible: ${isVisible}, Enabled: ${isEnabled}`,
481
- resolved.matchedIndex,
482
- resolved.matchedXPath
483
- );
484
- return this.buildResult('FAIL', expected, failComments, startMs, startTime, step_name, sc);
485
- }
486
-
487
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
488
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
489
- } catch (error: any) {
490
- const sc = await this.captureScreenshot(true);
491
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
492
- }
493
- }
494
-
495
- // ─── forceClick ────────────────────────────────────────────────────────────
496
-
497
- async forceClick(label: string, locators: string[], step_name: string = 'Force click element'): Promise<StepResult> {
498
- const startMs = Date.now();
499
- const startTime = this.getStartTime();
500
- const expected = `'${label}' force-clicked successfully`;
501
-
502
- try {
503
- const resolved = await LocatorService.resolveElement(this.page, locators);
504
- await resolved.element.click({ force: true });
505
-
506
- const comments = this.appendMatchedLocatorInfo(expected, resolved.matchedIndex, resolved.matchedXPath);
507
- return this.buildResult('PASS', expected, comments, startMs, startTime, step_name);
508
- } catch (error: any) {
509
- const sc = await this.captureScreenshot(true);
510
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, step_name, sc);
511
- }
512
- }
513
- }