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,432 +0,0 @@
1
- import { Browser, BrowserContext, Page, chromium, firefox } from 'playwright';
2
- import { StepResult } from '../types/types';
3
- import * as path from 'path';
4
- import * as fs from 'fs';
5
-
6
- const VIDEO_DIR = path.resolve(__dirname, '../../videos');
7
-
8
- export class BrowserManager {
9
- private browser: Browser | null = null;
10
- private context: BrowserContext | null = null;
11
- private page: Page | null = null;
12
- private videoEnabled: boolean = false;
13
-
14
- // ─── Helpers ───────────────────────────────────────────────────────────────
15
-
16
- private getStartTime(): string {
17
- return new Date().toISOString();
18
- }
19
-
20
- private getDuration(startMs: number): number {
21
- return Date.now() - startMs;
22
- }
23
-
24
- private buildResult(
25
- status: 'PASS' | 'FAIL',
26
- expected_result: string,
27
- comments: string,
28
- startMs: number,
29
- startTime: string,
30
- step_name: string = '',
31
- step_script: string = '',
32
- uid: string | null = null,
33
- obj_uid: string | null = null,
34
- page_uid: string | null = null
35
- ): StepResult {
36
- return {
37
- uid,
38
- obj_uid,
39
- page_uid,
40
- step_name,
41
- step_script,
42
- status,
43
- expected_result,
44
- comments,
45
- duration: this.getDuration(startMs),
46
- start_time: startTime
47
- };
48
- }
49
- async captureScreenshot(screenshotMode: 'on_failure' | 'always' | 'never', isFailure: boolean): Promise<string> {
50
- if (screenshotMode === 'never') return '';
51
- if (screenshotMode === 'on_failure' && !isFailure) return '';
52
- try {
53
- if (!this.page || this.page.isClosed()) return '';
54
- const buf = await this.page.screenshot({ type: 'png', fullPage: false });
55
- return buf.toString('base64');
56
- } catch {
57
- return '';
58
- }
59
- }
60
- private ensureVideoDir(): void {
61
- if (!fs.existsSync(VIDEO_DIR)) {
62
- fs.mkdirSync(VIDEO_DIR, { recursive: true });
63
- }
64
- }
65
-
66
- private classifyError(error: any): string {
67
- const msg: string = error?.message || String(error);
68
-
69
- if (msg.includes('net::ERR_NAME_NOT_RESOLVED') || msg.includes('net::ERR_CONNECTION_REFUSED')) {
70
- return `Network error - URL unreachable: ${msg}`;
71
- }
72
- if (msg.includes('net::ERR_INTERNET_DISCONNECTED')) {
73
- return `No internet connection: ${msg}`;
74
- }
75
- if (msg.includes('Timeout') || msg.includes('timeout')) {
76
- return `Timeout error - page took too long to respond: ${msg}`;
77
- }
78
- if (msg.includes('Target closed') || msg.includes('Target page, context or browser has been closed')) {
79
- return `Browser or page was closed unexpectedly: ${msg}`;
80
- }
81
- if (msg.includes('net::ERR_CERT') || msg.includes('SSL')) {
82
- return `SSL/Certificate error: ${msg}`;
83
- }
84
- if (msg.includes('executable doesn\'t exist') || msg.includes('Failed to launch')) {
85
- return `Browser launch failed - browser executable not found: ${msg}`;
86
- }
87
- if (msg.includes('msedge') || msg.includes('edge')) {
88
- return `Edge browser error - ensure Microsoft Edge is installed: ${msg}`;
89
- }
90
- if (msg.includes('Permission denied') || msg.includes('EACCES')) {
91
- return `Permission denied - check folder/file permissions: ${msg}`;
92
- }
93
- if (msg.includes('ENOENT')) {
94
- return `File or directory not found: ${msg}`;
95
- }
96
- if (msg.includes('Navigation failed')) {
97
- return `Navigation failed - page may have crashed or redirected incorrectly: ${msg}`;
98
- }
99
- if (msg.includes('Page is not initialized') || msg.includes('Browser is not open')) {
100
- return `Browser not initialized - call openBrowser first: ${msg}`;
101
- }
102
-
103
- return `Unexpected error: ${msg}`;
104
- }
105
-
106
- getPage(): Page {
107
- if (!this.page) throw new Error('Page is not initialized. Call openBrowser first.');
108
- return this.page;
109
- }
110
-
111
- // ─── openBrowser ───────────────────────────────────────────────────────────
112
-
113
- // async openBrowser(
114
- // browserType: 'chromium' | 'firefox' | 'edge',
115
- // headless: boolean = false,
116
- // videoEnabled: boolean = false
117
- // ): Promise<StepResult> {
118
- // const startMs = Date.now();
119
- // const startTime = this.getStartTime();
120
- // const expected = `${browserType} browser opened successfully`;
121
- // this.videoEnabled = videoEnabled;
122
-
123
- // try {
124
- // if (browserType === 'firefox') {
125
- // this.browser = await firefox.launch({ headless });
126
- // } else if (browserType === 'edge') {
127
- // this.browser = await chromium.launch({ channel: 'msedge', headless });
128
- // } else {
129
- // this.browser = await chromium.launch({ headless });
130
- // }
131
-
132
- // const contextOptions: any = {};
133
-
134
- // if (this.videoEnabled) {
135
- // this.ensureVideoDir();
136
- // contextOptions.recordVideo = {
137
- // dir: VIDEO_DIR,
138
- // size: { width: 1280, height: 720 }
139
- // };
140
- // }
141
-
142
- // this.context = await this.browser.newContext(contextOptions);
143
- // this.page = await this.context.newPage();
144
-
145
- // return this.buildResult('PASS', expected, expected, startMs, startTime, `Open ${browserType}`);
146
- // } catch (error: any) {
147
- // return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, `Open ${browserType}`);
148
- // }
149
- // }
150
- async openBrowser(
151
- browserType: 'chromium' | 'chrome' | 'firefox' | 'edge',
152
- headless: boolean = false,
153
- videoEnabled: boolean = false
154
- ): Promise<StepResult> {
155
- const startMs = Date.now();
156
- const startTime = this.getStartTime();
157
- const expected = `${browserType} browser opened successfully`;
158
- this.videoEnabled = videoEnabled;
159
-
160
- try {
161
- if (browserType === 'firefox') {
162
- this.browser = await firefox.launch({ headless });
163
- } else if (browserType === 'edge') {
164
- this.browser = await chromium.launch({ channel: 'msedge', headless });
165
- } else if (browserType === 'chrome') {
166
- this.browser = await chromium.launch({ channel: 'chrome', headless });
167
- } else {
168
- this.browser = await chromium.launch({ headless });
169
- }
170
-
171
- const contextOptions: any = {};
172
-
173
- if (this.videoEnabled) {
174
- this.ensureVideoDir();
175
- contextOptions.recordVideo = {
176
- dir: VIDEO_DIR,
177
- size: { width: 1280, height: 720 }
178
- };
179
- }
180
-
181
- this.context = await this.browser.newContext(contextOptions);
182
- this.page = await this.context.newPage();
183
-
184
- return this.buildResult('PASS', expected, expected, startMs, startTime, `Open ${browserType}`);
185
- } catch (error: any) {
186
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, `Open ${browserType}`);
187
- }
188
- }
189
- // ─── closeBrowser ──────────────────────────────────────────────────────────
190
-
191
- async closeBrowser(testScriptUid: string = ''): Promise<StepResult> {
192
- const startMs = Date.now();
193
- const startTime = this.getStartTime();
194
- const expected = 'Browser closed successfully';
195
-
196
- try {
197
- if (this.videoEnabled && this.page) {
198
- const video = this.page.video();
199
-
200
- if (video) {
201
- const destPath = path.join(VIDEO_DIR, `${testScriptUid || 'recording'}_${Date.now()}.webm`);
202
- await this.context?.close();
203
- await video.saveAs(destPath);
204
- await video.delete();
205
- this.savedVideoPath = destPath;
206
- } else {
207
- await this.context?.close();
208
- }
209
- } else {
210
- await this.context?.close();
211
- }
212
-
213
- await this.browser?.close();
214
- this.browser = null;
215
- this.context = null;
216
- this.page = null;
217
-
218
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Close browser');
219
- } catch (error: any) {
220
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Close browser');
221
- }
222
-
223
- }
224
-
225
-
226
- // ─── navigateToURL ─────────────────────────────────────────────────────────
227
-
228
- async navigateToURL(url: string): Promise<StepResult> {
229
- const startMs = Date.now();
230
- const startTime = this.getStartTime();
231
- const expected = `${url} opened successfully`;
232
-
233
- try {
234
- if (!this.page) throw new Error('Browser is not open');
235
- await this.page.goto(url, { waitUntil: 'load', timeout: 30000 });
236
-
237
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Navigate to URL');
238
- } catch (error: any) {
239
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Navigate to URL');
240
- }
241
- }
242
-
243
- // ─── getTitle ──────────────────────────────────────────────────────────────
244
-
245
- async getTitle(): Promise<StepResult> {
246
- const startMs = Date.now();
247
- const startTime = this.getStartTime();
248
- const expected = 'Page title retrieved successfully';
249
-
250
- try {
251
- if (!this.page) throw new Error('Browser is not open');
252
- const title = await this.page.title();
253
-
254
- return this.buildResult('PASS', expected, `Page title is: ${title}`, startMs, startTime, 'Get title');
255
- } catch (error: any) {
256
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Get title');
257
- }
258
- }
259
-
260
- // ─── waitUntilLoaded ───────────────────────────────────────────────────────
261
-
262
- async waitUntilLoaded(): Promise<StepResult> {
263
- const startMs = Date.now();
264
- const startTime = this.getStartTime();
265
- const expected = 'Page loaded successfully';
266
-
267
- try {
268
- if (!this.page) throw new Error('Browser is not open');
269
- await this.page.waitForLoadState('load', { timeout: 30000 });
270
-
271
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Wait until loaded');
272
- } catch (error: any) {
273
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Wait until loaded');
274
- }
275
- }
276
-
277
- // ─── waitForNetworkIdle ────────────────────────────────────────────────────
278
-
279
- async waitForNetworkIdle(): Promise<StepResult> {
280
- const startMs = Date.now();
281
- const startTime = this.getStartTime();
282
- const expected = 'Network is idle';
283
-
284
- try {
285
- if (!this.page) throw new Error('Browser is not open');
286
- await this.page.waitForLoadState('networkidle', { timeout: 30000 });
287
-
288
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Wait for network idle');
289
- } catch (error: any) {
290
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Wait for network idle');
291
- }
292
- }
293
-
294
- // ─── reloadPage ────────────────────────────────────────────────────────────
295
-
296
- async reloadPage(): Promise<StepResult> {
297
- const startMs = Date.now();
298
- const startTime = this.getStartTime();
299
- const expected = 'Page reloaded successfully';
300
-
301
- try {
302
- if (!this.page) throw new Error('Browser is not open');
303
- await this.page.reload({ waitUntil: 'load', timeout: 30000 });
304
-
305
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Reload page');
306
- } catch (error: any) {
307
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Reload page');
308
- }
309
- }
310
-
311
- // ─── goBack ────────────────────────────────────────────────────────────────
312
-
313
- async goBack(): Promise<StepResult> {
314
- const startMs = Date.now();
315
- const startTime = this.getStartTime();
316
- const expected = 'Navigated back successfully';
317
-
318
- try {
319
- if (!this.page) throw new Error('Browser is not open');
320
- await this.page.goBack({ waitUntil: 'load', timeout: 30000 });
321
-
322
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Go back');
323
- } catch (error: any) {
324
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Go back');
325
- }
326
- }
327
-
328
- // ─── goForward ─────────────────────────────────────────────────────────────
329
-
330
- async goForward(): Promise<StepResult> {
331
- const startMs = Date.now();
332
- const startTime = this.getStartTime();
333
- const expected = 'Navigated forward successfully';
334
-
335
- try {
336
- if (!this.page) throw new Error('Browser is not open');
337
- await this.page.goForward({ waitUntil: 'load', timeout: 30000 });
338
-
339
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Go forward');
340
- } catch (error: any) {
341
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Go forward');
342
- }
343
- }
344
-
345
- // ─── getCurrentURL ─────────────────────────────────────────────────────────
346
-
347
- async getCurrentURL(): Promise<StepResult> {
348
- const startMs = Date.now();
349
- const startTime = this.getStartTime();
350
- const expected = 'Current URL retrieved successfully';
351
-
352
- try {
353
- if (!this.page) throw new Error('Browser is not open');
354
- const url = this.page.url();
355
-
356
- return this.buildResult('PASS', expected, `Current URL is: ${url}`, startMs, startTime, 'Get current URL');
357
- } catch (error: any) {
358
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Get current URL');
359
- }
360
- }
361
-
362
- // ─── maximizeWindow ────────────────────────────────────────────────────────
363
-
364
- async maximizeWindow(): Promise<StepResult> {
365
- const startMs = Date.now();
366
- const startTime = this.getStartTime();
367
- const expected = 'Browser window maximized successfully';
368
-
369
- try {
370
- if (!this.page) throw new Error('Browser is not open');
371
- await this.page.setViewportSize({ width: 1920, height: 1080 });
372
-
373
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Maximize window');
374
- } catch (error: any) {
375
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Maximize window');
376
- }
377
- }
378
-
379
- // ─── takeScreenshot ────────────────────────────────────────────────────────
380
-
381
- async takeScreenshot(screenshotPath: string): Promise<StepResult> {
382
- const startMs = Date.now();
383
- const startTime = this.getStartTime();
384
- const expected = `Screenshot saved at ${screenshotPath}`;
385
-
386
- try {
387
- if (!this.page) throw new Error('Browser is not open');
388
- const dir = path.dirname(screenshotPath);
389
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
390
- await this.page.screenshot({ path: screenshotPath, fullPage: true });
391
-
392
- return this.buildResult('PASS', expected, expected, startMs, startTime, 'Take screenshot');
393
- } catch (error: any) {
394
- return this.buildResult('FAIL', expected, this.classifyError(error), startMs, startTime, 'Take screenshot');
395
- }
396
- }
397
-
398
- // ─── getPageSource ────────────────────────────────────────────────────────
399
-
400
- /**
401
- * Get the HTML page source (for auto-healing comparison)
402
- */
403
- async getPageSourceContent(): Promise<string | null> {
404
- try {
405
- if (!this.page) throw new Error('Browser is not open');
406
- return await this.page.content();
407
- } catch (error: any) {
408
- console.error(`Failed to get page source: ${error.message}`);
409
- return null;
410
- }
411
- }
412
- private savedVideoPath: string | null = null;
413
-
414
- getSavedVideoPath(): string | null {
415
- return this.savedVideoPath;
416
- }
417
-
418
- // ─── getCurrentURLString ────────────────────────────────────────────────────
419
-
420
- /**
421
- * Get the current URL as a string (for auto-healing context)
422
- */
423
- async getCurrentURLString(): Promise<string> {
424
- try {
425
- if (!this.page) throw new Error('Browser is not open');
426
- return this.page.url();
427
- } catch (error: any) {
428
- console.error(`Failed to get current URL: ${error.message}`);
429
- return 'unknown';
430
- }
431
- }
432
- }