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.
- package/dist-obf/actions/baseHandler.js +1 -1
- package/dist-obf/actions/browserManager.js +1 -1
- package/dist-obf/actions/checkboxHandler.js +1 -1
- package/dist-obf/actions/clickHandler.js +1 -1
- package/dist-obf/actions/customcodehandler.js +1 -1
- package/dist-obf/actions/dropdownHandler.js +1 -1
- package/dist-obf/actions/radiobuttonHandler.js +1 -1
- package/dist-obf/actions/textHandler.js +1 -1
- package/dist-obf/api/server.js +1 -1
- package/dist-obf/config.js +1 -1
- package/dist-obf/executor/functionMap.js +1 -1
- package/dist-obf/executor/mapping.js +1 -1
- package/dist-obf/executor/scriptExecutor.js +1 -1
- package/dist-obf/executor/stepExecutor.js +1 -1
- package/dist-obf/runner/testRunner.js +1 -1
- package/dist-obf/sse/sseManager.js +1 -1
- package/dist-obf/store/executionStore.js +1 -1
- package/dist-obf/store/testDataStore.js +1 -1
- package/dist-obf/types/types.js +1 -1
- package/dist-obf/utils/healingService.js +1 -1
- package/dist-obf/utils/locatorService.js +1 -1
- package/dist-obf/utils/logger.js +1 -1
- package/dist-obf/utils/metadataService.js +1 -1
- package/dist-obf/utils/waitConditions.js +1 -1
- package/dist-obf/validator/validator.js +1 -1
- package/package.json +5 -2
- package/npmignore +0 -8
- package/public/dashboard.html +0 -591
- package/src/actions/baseHandler.ts +0 -351
- package/src/actions/browserManager.ts +0 -432
- package/src/actions/checkboxHandler.ts +0 -276
- package/src/actions/clickHandler.ts +0 -513
- package/src/actions/customcodehandler.ts +0 -251
- package/src/actions/dropdownHandler.ts +0 -501
- package/src/actions/radiobuttonHandler.ts +0 -286
- package/src/actions/textHandler.ts +0 -498
- package/src/api/server.ts +0 -210
- package/src/config.ts +0 -7
- package/src/executor/functionMap.ts +0 -153
- package/src/executor/mapping.ts +0 -70
- package/src/executor/scriptExecutor.ts +0 -162
- package/src/executor/stepExecutor.ts +0 -289
- package/src/runner/testRunner.ts +0 -78
- package/src/sse/sseManager.ts +0 -130
- package/src/store/executionStore.ts +0 -152
- package/src/store/testDataStore.ts +0 -46
- package/src/types/types.ts +0 -159
- package/src/utils/healingService.ts +0 -210
- package/src/utils/locatorService.ts +0 -73
- package/src/utils/logger.ts +0 -27
- package/src/utils/metadataService.ts +0 -137
- package/src/utils/waitConditions.ts +0 -141
- package/src/validator/validator.ts +0 -140
- package/tsconfig.json +0 -16
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { Page } from 'playwright';
|
|
2
|
-
import { LocatorService } from './locatorService';
|
|
3
|
-
|
|
4
|
-
const DEFAULT_TIMEOUT = 10000;
|
|
5
|
-
|
|
6
|
-
export class WaitConditions {
|
|
7
|
-
// ─── waitForVisible ────────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
static async waitForVisible(page: Page, locators: string[], timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
10
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
11
|
-
await resolved.element.waitFor({ state: 'visible', timeout });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// ─── waitForHidden ─────────────────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
static async waitForHidden(page: Page, locators: string[], timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
17
|
-
const combinedXPath = locators.join(' | ');
|
|
18
|
-
const element = page.locator(`xpath=${combinedXPath}`).first();
|
|
19
|
-
await element.waitFor({ state: 'hidden', timeout });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// ─── waitForEnabled ────────────────────────────────────────────────────────
|
|
23
|
-
|
|
24
|
-
static async waitForEnabled(page: Page, locators: string[], timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
25
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
26
|
-
const handle = await resolved.element.elementHandle();
|
|
27
|
-
|
|
28
|
-
if (!handle) throw new Error('Element handle could not be resolved');
|
|
29
|
-
|
|
30
|
-
await page.waitForFunction(
|
|
31
|
-
(el) => el && !(el as HTMLInputElement).disabled,
|
|
32
|
-
handle,
|
|
33
|
-
{ timeout }
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ─── waitForDisabled ───────────────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
static async waitForDisabled(page: Page, locators: string[], timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
40
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
41
|
-
const handle = await resolved.element.elementHandle();
|
|
42
|
-
|
|
43
|
-
if (!handle) throw new Error('Element handle could not be resolved');
|
|
44
|
-
|
|
45
|
-
await page.waitForFunction(
|
|
46
|
-
(el) => el && (el as HTMLInputElement).disabled,
|
|
47
|
-
handle,
|
|
48
|
-
{ timeout }
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ─── waitForTextEmpty ──────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
static async waitForTextEmpty(page: Page, locators: string[], timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
55
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
56
|
-
const handle = await resolved.element.elementHandle();
|
|
57
|
-
|
|
58
|
-
if (!handle) throw new Error('Element handle could not be resolved');
|
|
59
|
-
|
|
60
|
-
await page.waitForFunction(
|
|
61
|
-
(el) => {
|
|
62
|
-
if (!el) return false;
|
|
63
|
-
const tag = (el as HTMLElement).tagName;
|
|
64
|
-
const text = tag === 'INPUT' || tag === 'TEXTAREA'
|
|
65
|
-
? (el as HTMLInputElement).value
|
|
66
|
-
: (el as HTMLElement).innerText;
|
|
67
|
-
return text.trim() === '';
|
|
68
|
-
},
|
|
69
|
-
handle,
|
|
70
|
-
{ timeout }
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ─── waitForTextNotEmpty ───────────────────────────────────────────────────
|
|
75
|
-
|
|
76
|
-
static async waitForTextNotEmpty(page: Page, locators: string[], timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
77
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
78
|
-
const handle = await resolved.element.elementHandle();
|
|
79
|
-
|
|
80
|
-
if (!handle) throw new Error('Element handle could not be resolved');
|
|
81
|
-
|
|
82
|
-
await page.waitForFunction(
|
|
83
|
-
(el) => {
|
|
84
|
-
if (!el) return false;
|
|
85
|
-
const tag = (el as HTMLElement).tagName;
|
|
86
|
-
const text = tag === 'INPUT' || tag === 'TEXTAREA'
|
|
87
|
-
? (el as HTMLInputElement).value
|
|
88
|
-
: (el as HTMLElement).innerText;
|
|
89
|
-
return text.trim() !== '';
|
|
90
|
-
},
|
|
91
|
-
handle,
|
|
92
|
-
{ timeout }
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ─── waitForTextChange ─────────────────────────────────────────────────────
|
|
97
|
-
|
|
98
|
-
static async waitForTextChange(page: Page, locators: string[], initialText: string, timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
99
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
100
|
-
const handle = await resolved.element.elementHandle();
|
|
101
|
-
|
|
102
|
-
if (!handle) throw new Error('Element handle could not be resolved');
|
|
103
|
-
|
|
104
|
-
await page.waitForFunction(
|
|
105
|
-
(arg) => {
|
|
106
|
-
const el = arg.el as HTMLElement | HTMLInputElement | null;
|
|
107
|
-
if (!el) return false;
|
|
108
|
-
const tag = el.tagName;
|
|
109
|
-
const text = tag === 'INPUT' || tag === 'TEXTAREA'
|
|
110
|
-
? (el as HTMLInputElement).value
|
|
111
|
-
: el.innerText;
|
|
112
|
-
return text.trim() !== arg.oldText.trim();
|
|
113
|
-
},
|
|
114
|
-
{ el: handle, oldText: initialText },
|
|
115
|
-
{ timeout }
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ─── waitForTextContains ───────────────────────────────────────────────────
|
|
120
|
-
|
|
121
|
-
static async waitForTextContains(page: Page, locators: string[], expectedSubstring: string, timeout: number = DEFAULT_TIMEOUT): Promise<void> {
|
|
122
|
-
const resolved = await LocatorService.resolveElement(page, locators, timeout);
|
|
123
|
-
const handle = await resolved.element.elementHandle();
|
|
124
|
-
|
|
125
|
-
if (!handle) throw new Error('Element handle could not be resolved');
|
|
126
|
-
|
|
127
|
-
await page.waitForFunction(
|
|
128
|
-
(arg) => {
|
|
129
|
-
const el = arg.el as HTMLElement | HTMLInputElement | null;
|
|
130
|
-
if (!el) return false;
|
|
131
|
-
const tag = el.tagName;
|
|
132
|
-
const text = tag === 'INPUT' || tag === 'TEXTAREA'
|
|
133
|
-
? (el as HTMLInputElement).value
|
|
134
|
-
: el.innerText;
|
|
135
|
-
return text.includes(arg.substring);
|
|
136
|
-
},
|
|
137
|
-
{ el: handle, substring: expectedSubstring },
|
|
138
|
-
{ timeout }
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
export interface ValidationError {
|
|
2
|
-
level: 'testset' | 'testscript' | 'step';
|
|
3
|
-
field: string;
|
|
4
|
-
message: string;
|
|
5
|
-
test_script_uid?: string;
|
|
6
|
-
step_name?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// ─── Testset Payload Validation ───────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
function validateTestset(payload: any): ValidationError[] {
|
|
12
|
-
const errors: ValidationError[] = [];
|
|
13
|
-
|
|
14
|
-
if (!payload.test_set_name || typeof payload.test_set_name !== 'string') {
|
|
15
|
-
errors.push({ level: 'testset', field: 'test_set_name', message: 'test_set_name is required and must be a string' });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (typeof payload.open_dashboard !== 'boolean') {
|
|
19
|
-
errors.push({ level: 'testset', field: 'open_dashboard', message: 'open_dashboard is required and must be a boolean' });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (typeof payload.parallel !== 'boolean') {
|
|
23
|
-
errors.push({ level: 'testset', field: 'parallel', message: 'parallel is required and must be a boolean' });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (typeof payload.stop_on_failure !== 'boolean') {
|
|
27
|
-
errors.push({ level: 'testset', field: 'stop_on_failure', message: 'stop_on_failure is required and must be a boolean' });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (typeof payload.video_enabled !== 'boolean') {
|
|
31
|
-
errors.push({ level: 'testset', field: 'video_enabled', message: 'video_enabled is required and must be a boolean' });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (payload.exec_mode !== undefined) {
|
|
35
|
-
if (typeof payload.exec_mode !== 'object' || payload.exec_mode === null) {
|
|
36
|
-
errors.push({ level: 'testset', field: 'exec_mode', message: 'exec_mode must be an object' });
|
|
37
|
-
} else {
|
|
38
|
-
if (!['fast', 'medium', 'slow'].includes(payload.exec_mode.mode)) {
|
|
39
|
-
errors.push({ level: 'testset', field: 'exec_mode.mode', message: 'exec_mode.mode must be one of: fast, medium, slow' });
|
|
40
|
-
}
|
|
41
|
-
if (payload.exec_mode.delay_ms !== undefined && typeof payload.exec_mode.delay_ms !== 'number') {
|
|
42
|
-
errors.push({ level: 'testset', field: 'exec_mode.delay_ms', message: 'exec_mode.delay_ms must be a number' });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (!Array.isArray(payload.scripts) || payload.scripts.length === 0) {
|
|
48
|
-
errors.push({ level: 'testset', field: 'scripts', message: 'scripts is required and must be a non-empty array' });
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return errors;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ─── Testscript Payload Validation ────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
function validateTestscript(script: any): ValidationError[] {
|
|
57
|
-
const errors: ValidationError[] = [];
|
|
58
|
-
const uid = script.test_script_uid || 'unknown';
|
|
59
|
-
|
|
60
|
-
if (!script.test_script_uid || typeof script.test_script_uid !== 'string') {
|
|
61
|
-
errors.push({ level: 'testscript', field: 'test_script_uid', message: 'test_script_uid is required and must be a string', test_script_uid: uid });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!script.test_case_name || typeof script.test_case_name !== 'string') {
|
|
65
|
-
errors.push({ level: 'testscript', field: 'test_case_name', message: 'test_case_name is required and must be a string', test_script_uid: uid });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!script.app_id || typeof script.app_id !== 'string') {
|
|
69
|
-
errors.push({ level: 'testscript', field: 'app_id', message: 'app_id is required and must be a string', test_script_uid: uid });
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// if (!['chromium', 'firefox', 'edge'].includes(script.browser)) {
|
|
73
|
-
if (!['chromium', 'chrome', 'firefox', 'edge'].includes(script.browser)) {
|
|
74
|
-
errors.push({ level: 'testscript', field: 'browser', message: 'browser must be one of: chromium, firefox, edge', test_script_uid: uid });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (typeof script.headless !== 'boolean') {
|
|
78
|
-
errors.push({ level: 'testscript', field: 'headless', message: 'headless is required and must be a boolean', test_script_uid: uid });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (typeof script.voice_enabled !== 'boolean') {
|
|
82
|
-
errors.push({ level: 'testscript', field: 'voice_enabled', message: 'voice_enabled is required and must be a boolean', test_script_uid: uid });
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!['on_failure', 'always', 'never'].includes(script.screenshot_mode)) {
|
|
86
|
-
errors.push({ level: 'testscript', field: 'screenshot_mode', message: 'screenshot_mode must be one of: on_failure, always, never', test_script_uid: uid });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (typeof script.stop_on_failure !== 'boolean') {
|
|
90
|
-
errors.push({ level: 'testscript', field: 'stop_on_failure', message: 'stop_on_failure is required and must be a boolean', test_script_uid: uid });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (!Array.isArray(script.steps) || script.steps.length === 0) {
|
|
94
|
-
errors.push({ level: 'testscript', field: 'steps', message: 'steps is required and must be a non-empty array', test_script_uid: uid });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return errors;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// ─── Step Payload Validation ──────────────────────────────────────────────────
|
|
101
|
-
|
|
102
|
-
function validateStep(step: any, test_script_uid: string): ValidationError[] {
|
|
103
|
-
const errors: ValidationError[] = [];
|
|
104
|
-
const stepName = step.step_name || 'unknown';
|
|
105
|
-
|
|
106
|
-
if (!step.step_name || typeof step.step_name !== 'string') {
|
|
107
|
-
errors.push({ level: 'step', field: 'step_name', message: 'step_name is required and must be a string', test_script_uid, step_name: stepName });
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!step.step_script || typeof step.step_script !== 'string') {
|
|
111
|
-
errors.push({ level: 'step', field: 'step_script', message: 'step_script is required and must be a string', test_script_uid, step_name: stepName });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return errors;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ─── Main Validator ───────────────────────────────────────────────────────────
|
|
118
|
-
|
|
119
|
-
export function validatePayload(payload: any): ValidationError[] {
|
|
120
|
-
const allErrors: ValidationError[] = [];
|
|
121
|
-
|
|
122
|
-
const testsetErrors = validateTestset(payload);
|
|
123
|
-
allErrors.push(...testsetErrors);
|
|
124
|
-
|
|
125
|
-
if (!Array.isArray(payload.scripts)) return allErrors;
|
|
126
|
-
|
|
127
|
-
for (const script of payload.scripts) {
|
|
128
|
-
const scriptErrors = validateTestscript(script);
|
|
129
|
-
allErrors.push(...scriptErrors);
|
|
130
|
-
|
|
131
|
-
if (!Array.isArray(script.steps)) continue;
|
|
132
|
-
|
|
133
|
-
for (const step of script.steps) {
|
|
134
|
-
const stepErrors = validateStep(step, script.test_script_uid || 'unknown');
|
|
135
|
-
allErrors.push(...stepErrors);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return allErrors;
|
|
140
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"lib": ["ES2022", "DOM"],
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"resolveJsonModule": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true
|
|
13
|
-
},
|
|
14
|
-
"include": ["src/**/*"],
|
|
15
|
-
"exclude": ["node_modules", "dist"]
|
|
16
|
-
}
|