@flash-ai-team/flash-test-framework 0.0.16 → 0.0.18
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/README.md +9 -0
- package/dist/core/ObjectRepository.d.ts +4 -3
- package/dist/keywords/WebUI.d.ts +39 -0
- package/dist/keywords/WebUI.js +86 -3
- package/dist/reporting/HtmlReporter.js +25 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -134,6 +134,12 @@ test.describe('AI Scenario', () => {
|
|
|
134
134
|
|
|
135
135
|
## Keywords
|
|
136
136
|
|
|
137
|
+
### Core Helpers
|
|
138
|
+
|
|
139
|
+
* `el(selector, description?)`: Creates a Test Object.
|
|
140
|
+
* `selector` (string): The CSS selector, XPath, or Playwright selector (e.g. `text=Submit`, `role=button[name="Login"]`).
|
|
141
|
+
* `description` (string): Optional description for reporting logs.
|
|
142
|
+
|
|
137
143
|
### Web
|
|
138
144
|
|
|
139
145
|
#### Navigation
|
|
@@ -168,12 +174,15 @@ test.describe('AI Scenario', () => {
|
|
|
168
174
|
* `verifyElementText(testObject, expectedText)`: Assert element text matches.
|
|
169
175
|
* `verifyElementAttributeValue(testObject, attribute, value)`: Assert element attribute matches.
|
|
170
176
|
* `verifyElementChecked(testObject, checked?)`: Assert element checked state.
|
|
177
|
+
* `verifyElementClickable(testObject, timeout?)`: Assert element is visible and enabled.
|
|
171
178
|
* `verifyTextPresent(text)`: Assert text exists on the page.
|
|
172
179
|
|
|
173
180
|
#### Synchonization
|
|
174
181
|
* `waitForElementVisible(testObject, timeout?)`: Wait for element to be visible.
|
|
175
182
|
* `waitForElementNotVisible(testObject, timeout?)`: Wait for element to disappear.
|
|
176
183
|
* `waitForElementClickable(testObject, timeout?)`: Wait for element to be clickable.
|
|
184
|
+
* `waitForPageLoad(timeout?, state?)`: Wait for page load state ('load', 'domcontentloaded', 'networkidle').
|
|
185
|
+
* `waitForNextPageLoaded(timeout?, waitUntil?)`: Wait for next navigation to complete.
|
|
177
186
|
* `waitForAngularLoad()`: Wait for Angular stability (if applicable).
|
|
178
187
|
* `delay(seconds)`: Hard wait (use sparingly).
|
|
179
188
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
1
2
|
/**
|
|
2
3
|
* Represents a Test Object wrapper around Playwright Locators
|
|
3
4
|
*/
|
|
4
5
|
export declare class TestObject {
|
|
5
|
-
selector: string;
|
|
6
|
+
selector: string | Locator;
|
|
6
7
|
description: string;
|
|
7
|
-
constructor(selector: string, description?: string);
|
|
8
|
+
constructor(selector: string | Locator, description?: string);
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* Helper to create Test Objects easily
|
|
11
12
|
*/
|
|
12
|
-
export declare function el(selector: string, description?: string): TestObject;
|
|
13
|
+
export declare function el(selector: string | Locator, description?: string): TestObject;
|
package/dist/keywords/WebUI.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ export declare class Web {
|
|
|
24
24
|
*/
|
|
25
25
|
static click(to: TestObject, options?: {
|
|
26
26
|
description?: string;
|
|
27
|
+
position?: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
};
|
|
27
31
|
}): Promise<void>;
|
|
28
32
|
/**
|
|
29
33
|
* Sets the text of an input element.
|
|
@@ -33,6 +37,14 @@ export declare class Web {
|
|
|
33
37
|
static setText(to: TestObject, text: string, options?: {
|
|
34
38
|
description?: string;
|
|
35
39
|
}): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Sets the text of a password input element.
|
|
42
|
+
* @param to - The TestObject representing the input element.
|
|
43
|
+
* @param text - The text to set.
|
|
44
|
+
*/
|
|
45
|
+
static setPassword(to: TestObject, text: string, options?: {
|
|
46
|
+
description?: string;
|
|
47
|
+
}): Promise<void>;
|
|
36
48
|
/**
|
|
37
49
|
* Searches for the specified text using heuristic selectors.
|
|
38
50
|
* @param text - The text to search for.
|
|
@@ -68,6 +80,10 @@ export declare class Web {
|
|
|
68
80
|
*/
|
|
69
81
|
static doubleClick(to: TestObject, options?: {
|
|
70
82
|
description?: string;
|
|
83
|
+
position?: {
|
|
84
|
+
x: number;
|
|
85
|
+
y: number;
|
|
86
|
+
};
|
|
71
87
|
}): Promise<void>;
|
|
72
88
|
/**
|
|
73
89
|
* Right clicks (context click) on the specified element.
|
|
@@ -166,6 +182,12 @@ export declare class Web {
|
|
|
166
182
|
* @param checked - True to verify checked, false to verify unchecked (default: true).
|
|
167
183
|
*/
|
|
168
184
|
static verifyElementChecked(to: TestObject, checked?: boolean): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Verifies that the element is clickable (visible and enabled).
|
|
187
|
+
* @param to - The TestObject representing the element.
|
|
188
|
+
* @param timeout - The maximum time to wait in milliseconds (default: 5000).
|
|
189
|
+
*/
|
|
190
|
+
static verifyElementClickable(to: TestObject, timeout?: number): Promise<void>;
|
|
169
191
|
/**
|
|
170
192
|
* Waits for the specified element to be visible.
|
|
171
193
|
* @param to - The TestObject representing the element.
|
|
@@ -184,6 +206,18 @@ export declare class Web {
|
|
|
184
206
|
* @param timeout - The maximum time to wait in milliseconds (default: 5000).
|
|
185
207
|
*/
|
|
186
208
|
static waitForElementNotVisible(to: TestObject, timeout?: number): Promise<void>;
|
|
209
|
+
/**
|
|
210
|
+
* Waits for the page to load.
|
|
211
|
+
* @param timeout - The maximum time to wait in milliseconds (default: 30000).
|
|
212
|
+
* @param state - The load state to wait for ('load' | 'domcontentloaded' | 'networkidle'). Default is 'load'.
|
|
213
|
+
*/
|
|
214
|
+
static waitForPageLoad(timeout?: number, state?: 'load' | 'domcontentloaded' | 'networkidle'): Promise<void>;
|
|
215
|
+
/**
|
|
216
|
+
* Waits for the next navigation to complete.
|
|
217
|
+
* @param timeout - The maximum time to wait in milliseconds (default: 30000).
|
|
218
|
+
* @param waitUntil - The event to wait for ('load' | 'domcontentloaded' | 'networkidle' | 'commit'). Default is 'load'.
|
|
219
|
+
*/
|
|
220
|
+
static waitForNextPageLoaded(timeout?: number, waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit'): Promise<void>;
|
|
187
221
|
/**
|
|
188
222
|
* Delays execution for a specified number of seconds.
|
|
189
223
|
* @param seconds - The number of seconds to wait.
|
|
@@ -224,4 +258,9 @@ export declare class Web {
|
|
|
224
258
|
* Waits for Angular to finish rendering.
|
|
225
259
|
*/
|
|
226
260
|
static waitForAngularLoad(): Promise<void>;
|
|
261
|
+
/**
|
|
262
|
+
* Switches to the window/tab with the specified title.
|
|
263
|
+
* @param title - The title of the window to switch to.
|
|
264
|
+
*/
|
|
265
|
+
static switchToTabTitle(title: string): Promise<void>;
|
|
227
266
|
}
|
package/dist/keywords/WebUI.js
CHANGED
|
@@ -22,7 +22,10 @@ class Web {
|
|
|
22
22
|
return Keyword_1.KeywordContext.page;
|
|
23
23
|
}
|
|
24
24
|
static getLocator(to) {
|
|
25
|
-
|
|
25
|
+
if (typeof to.selector === 'string') {
|
|
26
|
+
return this.page.locator(to.selector);
|
|
27
|
+
}
|
|
28
|
+
return to.selector;
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
31
|
* Navigates to the specified URL.
|
|
@@ -45,7 +48,7 @@ class Web {
|
|
|
45
48
|
* @param options - Optional parameters (description).
|
|
46
49
|
*/
|
|
47
50
|
static async click(to, options) {
|
|
48
|
-
await this.getLocator(to).click();
|
|
51
|
+
await this.getLocator(to).click({ position: options?.position });
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
51
54
|
* Sets the text of an input element.
|
|
@@ -55,6 +58,14 @@ class Web {
|
|
|
55
58
|
static async setText(to, text, options) {
|
|
56
59
|
await this.getLocator(to).fill(text);
|
|
57
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Sets the text of a password input element.
|
|
63
|
+
* @param to - The TestObject representing the input element.
|
|
64
|
+
* @param text - The text to set.
|
|
65
|
+
*/
|
|
66
|
+
static async setPassword(to, text, options) {
|
|
67
|
+
await this.getLocator(to).fill(text);
|
|
68
|
+
}
|
|
58
69
|
/**
|
|
59
70
|
* Searches for the specified text using heuristic selectors.
|
|
60
71
|
* @param text - The text to search for.
|
|
@@ -102,7 +113,7 @@ class Web {
|
|
|
102
113
|
* @param to - The TestObject representing the element.
|
|
103
114
|
*/
|
|
104
115
|
static async doubleClick(to, options) {
|
|
105
|
-
await this.getLocator(to).dblclick();
|
|
116
|
+
await this.getLocator(to).dblclick({ position: options?.position });
|
|
106
117
|
}
|
|
107
118
|
/**
|
|
108
119
|
* Right clicks (context click) on the specified element.
|
|
@@ -292,6 +303,16 @@ class Web {
|
|
|
292
303
|
await (0, test_1.expect)(this.getLocator(to)).not.toBeChecked();
|
|
293
304
|
}
|
|
294
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Verifies that the element is clickable (visible and enabled).
|
|
308
|
+
* @param to - The TestObject representing the element.
|
|
309
|
+
* @param timeout - The maximum time to wait in milliseconds (default: 5000).
|
|
310
|
+
*/
|
|
311
|
+
static async verifyElementClickable(to, timeout = 5000) {
|
|
312
|
+
const locator = this.getLocator(to);
|
|
313
|
+
await (0, test_1.expect)(locator).toBeVisible({ timeout });
|
|
314
|
+
await (0, test_1.expect)(locator).toBeEnabled({ timeout });
|
|
315
|
+
}
|
|
295
316
|
// --- Wait Keywords ---
|
|
296
317
|
/**
|
|
297
318
|
* Waits for the specified element to be visible.
|
|
@@ -321,6 +342,22 @@ class Web {
|
|
|
321
342
|
static async waitForElementNotVisible(to, timeout = 5000) {
|
|
322
343
|
await this.getLocator(to).waitFor({ state: 'hidden', timeout });
|
|
323
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Waits for the page to load.
|
|
347
|
+
* @param timeout - The maximum time to wait in milliseconds (default: 30000).
|
|
348
|
+
* @param state - The load state to wait for ('load' | 'domcontentloaded' | 'networkidle'). Default is 'load'.
|
|
349
|
+
*/
|
|
350
|
+
static async waitForPageLoad(timeout = 30000, state = 'load') {
|
|
351
|
+
await this.page.waitForLoadState(state, { timeout });
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Waits for the next navigation to complete.
|
|
355
|
+
* @param timeout - The maximum time to wait in milliseconds (default: 30000).
|
|
356
|
+
* @param waitUntil - The event to wait for ('load' | 'domcontentloaded' | 'networkidle' | 'commit'). Default is 'load'.
|
|
357
|
+
*/
|
|
358
|
+
static async waitForNextPageLoaded(timeout = 30000, waitUntil = 'load') {
|
|
359
|
+
await this.page.waitForNavigation({ timeout, waitUntil });
|
|
360
|
+
}
|
|
324
361
|
/**
|
|
325
362
|
* Delays execution for a specified number of seconds.
|
|
326
363
|
* @param seconds - The number of seconds to wait.
|
|
@@ -387,6 +424,22 @@ class Web {
|
|
|
387
424
|
}
|
|
388
425
|
});
|
|
389
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Switches to the window/tab with the specified title.
|
|
429
|
+
* @param title - The title of the window to switch to.
|
|
430
|
+
*/
|
|
431
|
+
static async switchToTabTitle(title) {
|
|
432
|
+
const pages = this.page.context().pages();
|
|
433
|
+
for (const p of pages) {
|
|
434
|
+
const pageTitle = await p.title();
|
|
435
|
+
if (pageTitle === title || pageTitle.includes(title)) {
|
|
436
|
+
await p.bringToFront();
|
|
437
|
+
Keyword_1.KeywordContext.page = p;
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
throw new Error(`Tab with title '${title}' not found`);
|
|
442
|
+
}
|
|
390
443
|
}
|
|
391
444
|
exports.Web = Web;
|
|
392
445
|
__decorate([
|
|
@@ -413,6 +466,12 @@ __decorate([
|
|
|
413
466
|
__metadata("design:paramtypes", [ObjectRepository_1.TestObject, String, Object]),
|
|
414
467
|
__metadata("design:returntype", Promise)
|
|
415
468
|
], Web, "setText", null);
|
|
469
|
+
__decorate([
|
|
470
|
+
(0, Keyword_1.Keyword)("Set Password"),
|
|
471
|
+
__metadata("design:type", Function),
|
|
472
|
+
__metadata("design:paramtypes", [ObjectRepository_1.TestObject, String, Object]),
|
|
473
|
+
__metadata("design:returntype", Promise)
|
|
474
|
+
], Web, "setPassword", null);
|
|
416
475
|
__decorate([
|
|
417
476
|
(0, Keyword_1.Keyword)("Search"),
|
|
418
477
|
__metadata("design:type", Function),
|
|
@@ -539,6 +598,12 @@ __decorate([
|
|
|
539
598
|
__metadata("design:paramtypes", [ObjectRepository_1.TestObject, Boolean]),
|
|
540
599
|
__metadata("design:returntype", Promise)
|
|
541
600
|
], Web, "verifyElementChecked", null);
|
|
601
|
+
__decorate([
|
|
602
|
+
(0, Keyword_1.Keyword)("Verify Element Clickable"),
|
|
603
|
+
__metadata("design:type", Function),
|
|
604
|
+
__metadata("design:paramtypes", [ObjectRepository_1.TestObject, Number]),
|
|
605
|
+
__metadata("design:returntype", Promise)
|
|
606
|
+
], Web, "verifyElementClickable", null);
|
|
542
607
|
__decorate([
|
|
543
608
|
(0, Keyword_1.Keyword)("Wait For Element Visible"),
|
|
544
609
|
__metadata("design:type", Function),
|
|
@@ -557,6 +622,18 @@ __decorate([
|
|
|
557
622
|
__metadata("design:paramtypes", [ObjectRepository_1.TestObject, Number]),
|
|
558
623
|
__metadata("design:returntype", Promise)
|
|
559
624
|
], Web, "waitForElementNotVisible", null);
|
|
625
|
+
__decorate([
|
|
626
|
+
(0, Keyword_1.Keyword)("Wait For Page Load"),
|
|
627
|
+
__metadata("design:type", Function),
|
|
628
|
+
__metadata("design:paramtypes", [Number, String]),
|
|
629
|
+
__metadata("design:returntype", Promise)
|
|
630
|
+
], Web, "waitForPageLoad", null);
|
|
631
|
+
__decorate([
|
|
632
|
+
(0, Keyword_1.Keyword)("Wait For Next Page Loaded"),
|
|
633
|
+
__metadata("design:type", Function),
|
|
634
|
+
__metadata("design:paramtypes", [Number, String]),
|
|
635
|
+
__metadata("design:returntype", Promise)
|
|
636
|
+
], Web, "waitForNextPageLoaded", null);
|
|
560
637
|
__decorate([
|
|
561
638
|
(0, Keyword_1.Keyword)("Delay"),
|
|
562
639
|
__metadata("design:type", Function),
|
|
@@ -605,3 +682,9 @@ __decorate([
|
|
|
605
682
|
__metadata("design:paramtypes", []),
|
|
606
683
|
__metadata("design:returntype", Promise)
|
|
607
684
|
], Web, "waitForAngularLoad", null);
|
|
685
|
+
__decorate([
|
|
686
|
+
(0, Keyword_1.Keyword)("Switch To Tab Title"),
|
|
687
|
+
__metadata("design:type", Function),
|
|
688
|
+
__metadata("design:paramtypes", [String]),
|
|
689
|
+
__metadata("design:returntype", Promise)
|
|
690
|
+
], Web, "switchToTabTitle", null);
|
|
@@ -86,6 +86,31 @@ class HtmlReporter {
|
|
|
86
86
|
}
|
|
87
87
|
fs.writeFileSync(this.reportPath, html);
|
|
88
88
|
console.log(`HTML Report generated at: ${this.reportPath}`);
|
|
89
|
+
// Check if we should open the report
|
|
90
|
+
let openReport = true; // Default to true
|
|
91
|
+
try {
|
|
92
|
+
const configPath = path.join(process.cwd(), 'report.config.json');
|
|
93
|
+
if (fs.existsSync(configPath)) {
|
|
94
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
95
|
+
if (config.openReport === false) {
|
|
96
|
+
openReport = false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (e) { /* ignore */ }
|
|
101
|
+
if (openReport) {
|
|
102
|
+
try {
|
|
103
|
+
// Write a marker file for VS Code extension to detect and open Latest Run view
|
|
104
|
+
const markerPath = path.join(process.cwd(), '.flash-report-ready');
|
|
105
|
+
fs.writeFileSync(markerPath, JSON.stringify({
|
|
106
|
+
reportPath: this.reportPath,
|
|
107
|
+
timestamp: Date.now()
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
console.log('Could not write report marker file.');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
89
114
|
}
|
|
90
115
|
onTestEnd(test, result) {
|
|
91
116
|
let suite = test.parent;
|