pw-element-interactions 0.0.1
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 +116 -0
- package/dist/ElementInteractions.d.ts +10 -0
- package/dist/ElementInteractions.js +17 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/interactions/Interaction.d.ts +77 -0
- package/dist/interactions/Interaction.js +116 -0
- package/dist/interactions/Navigation.d.ts +37 -0
- package/dist/interactions/Navigation.js +59 -0
- package/dist/interactions/Verification.d.ts +68 -0
- package/dist/interactions/Verification.js +123 -0
- package/dist/steps/CommonSteps.d.ts +107 -0
- package/dist/steps/CommonSteps.js +175 -0
- package/dist/utils/DateUtilities.d.ts +7 -0
- package/dist/utils/DateUtilities.js +39 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Playwright Element Interactions
|
|
2
|
+
|
|
3
|
+
[)](https://www.npmjs.com/package/pw-element-interactions)
|
|
4
|
+
|
|
5
|
+
A robust set of Playwright steps for readable interaction and assertions.
|
|
6
|
+
|
|
7
|
+
`pw-element-interactions` pairs perfectly with `pw-element-repository` to achieve a fully decoupled test automation architecture. By separating **Element Acquisition** from **Element Interaction**, your test scripts become highly readable, easily maintainable, and completely free of raw locators.
|
|
8
|
+
|
|
9
|
+
### ✨ The Unified Steps API
|
|
10
|
+
With the introduction of the `Steps` class, you can now combine your element repository and interactions into a single, flattened Facade. This eliminates repetitive locator fetching and transforms your tests into clean, plain-English steps.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 📦 Installation
|
|
15
|
+
|
|
16
|
+
Install the package via your preferred package manager:
|
|
17
|
+
|
|
18
|
+
``` bash
|
|
19
|
+
npm i pw-element-interactions
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Peer Dependencies:**
|
|
23
|
+
This package requires `@playwright/test` to be installed in your project. If you are using the `Steps` API, you will also need `pw-element-repository`.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🚀 What is it good for?
|
|
28
|
+
|
|
29
|
+
* **Zero Locator Boilerplate:** The new `Steps` API fetches elements and interacts with them in a single method call.
|
|
30
|
+
* **Separation of Concerns:** Keep your interaction logic entirely detached from how elements are found on the page.
|
|
31
|
+
* **Readable Tests:** Abstract away Playwright boilerplate into semantic methods (`clickIfPresent`, `verifyPresence`, `selectDropdown`).
|
|
32
|
+
* **Advanced Visual Checks:** Includes a highly reliable `verifyImages` method that evaluates actual browser decoding and `naturalWidth` to ensure images aren't just in the DOM, but are properly rendered.
|
|
33
|
+
* **Smart Dropdowns:** Easily select dropdown options by value, index, or completely randomly (skipping disabled or empty options automatically).
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 💻 Usage: The `Steps` API (Recommended)
|
|
38
|
+
|
|
39
|
+
Initialize the `Steps` class by passing the current Playwright `page` object and your `ElementRepository` instance.
|
|
40
|
+
|
|
41
|
+
### Example Scenario
|
|
42
|
+
|
|
43
|
+
``` ts
|
|
44
|
+
import { test } from '@playwright/test';
|
|
45
|
+
import { ElementRepository } from 'pw-element-repository';
|
|
46
|
+
import { Steps } from 'pw-element-interactions';
|
|
47
|
+
|
|
48
|
+
test('Add random product and verify image gallery', async ({ page }) => {
|
|
49
|
+
// 1. Initialize Repository & Steps
|
|
50
|
+
const repo = new ElementRepository('tests/data/locators.json');
|
|
51
|
+
const steps = new Steps(page, repo);
|
|
52
|
+
|
|
53
|
+
// 2. Navigate
|
|
54
|
+
await steps.navigateTo('/');
|
|
55
|
+
|
|
56
|
+
// 3. Direct Interaction (Fetches and clicks in one line)
|
|
57
|
+
await steps.click('HomePage', 'category-accessories');
|
|
58
|
+
|
|
59
|
+
// 4. Randomized Acquisition & Action
|
|
60
|
+
await steps.clickRandom('AccessoriesPage', 'product-cards');
|
|
61
|
+
await steps.verifyUrlContains('/product/');
|
|
62
|
+
|
|
63
|
+
// 5. Smart Dropdown Interaction
|
|
64
|
+
const selectedSize = await steps.selectDropdown('ProductDetailsPage', 'size-selector', { type: 'random' });
|
|
65
|
+
console.log(`Selected size: ${selectedSize}`);
|
|
66
|
+
|
|
67
|
+
// 6. Advanced Image Verification
|
|
68
|
+
await steps.verifyImages('ProductDetailsPage', 'gallery-images');
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🛠️ API Reference: `Steps`
|
|
75
|
+
|
|
76
|
+
The `Steps` class automatically handles fetching the Playwright `Locator` using your `pageName` and `elementName` keys from the repository.
|
|
77
|
+
|
|
78
|
+
### 🧭 Navigation Steps
|
|
79
|
+
* **`MapsTo(url)`**: Navigates the browser to the specified URL.
|
|
80
|
+
* **`refresh()`**: Reloads the current page.
|
|
81
|
+
|
|
82
|
+
### 🖱️ Interaction Steps
|
|
83
|
+
* **`click(pageName, elementName)`**: Standard click. Automatically waits for actionability.
|
|
84
|
+
* **`clickRandom(pageName, elementName)`**: Resolves a list of elements and clicks a random one.
|
|
85
|
+
* **`clickIfPresent(pageName, elementName)`**: Safely clicks an element only if it is visible. Prevents failures on optional UI elements like cookie banners.
|
|
86
|
+
* **`fill(pageName, elementName, text)`**: Clears the input and types the provided text.
|
|
87
|
+
* **`uploadFile(pageName, elementName, filePath)`**: Uploads a local file to a specific `<input type="file">`.
|
|
88
|
+
* **`selectDropdown(pageName, elementName, options?)`**: Interacts with `<select>` elements. Returns the selected value. Accepts:
|
|
89
|
+
* `{ type: 'random' }` *(Default)* - Selects a random, non-disabled option with a valid value.
|
|
90
|
+
* `{ type: 'value', value: 'string' }` - Selects by exact value.
|
|
91
|
+
* `{ type: 'index', index: 1 }` - Selects by index.
|
|
92
|
+
|
|
93
|
+
### ✅ Verification Steps
|
|
94
|
+
* **`verifyPresence(pageName, elementName)`**: Asserts the element is visible in the DOM.
|
|
95
|
+
* **`verifyAbsence(pageName, elementName)`**: Asserts the element is hidden or detached.
|
|
96
|
+
* **`verifyText(pageName, elementName, expectedText)`**: Asserts exact text match.
|
|
97
|
+
* **`verifyImages(pageName, elementName, scroll?)`**: Robust image verification. Scrolls into view, checks visibility, asserts `src`, checks `naturalWidth > 0`, and evaluates the native `HTMLImageElement.decode()` promise.
|
|
98
|
+
* **`verifyUrlContains(text)`**: Asserts the active browser URL contains a specific substring.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 🧱 Advanced Usage: Raw Interactions API
|
|
103
|
+
|
|
104
|
+
If you need to bypass the repository or interact with custom locators dynamically generated in your tests, you can use the underlying `ElementInteractions` class directly.
|
|
105
|
+
``` ts
|
|
106
|
+
import { ElementInteractions } from 'pw-element-interactions';
|
|
107
|
+
|
|
108
|
+
// Initialize
|
|
109
|
+
const interactions = new ElementInteractions(page);
|
|
110
|
+
|
|
111
|
+
// Pass Playwright Locators directly
|
|
112
|
+
const customLocator = page.locator('button.dynamic-class');
|
|
113
|
+
await interactions.interact.clickWithoutScrolling(customLocator);
|
|
114
|
+
await interactions.verify.state(customLocator, 'enabled');
|
|
115
|
+
```
|
|
116
|
+
*Note: All core interaction (`interact`), verification (`verify`), and navigation (`Maps`) methods are available when using `ElementInteractions` directly.*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { Interactions } from './interactions/Interaction';
|
|
3
|
+
import { Navigation } from './interactions/Navigation';
|
|
4
|
+
import { Verifications } from './interactions/Verification';
|
|
5
|
+
export declare class ElementInteractions {
|
|
6
|
+
navigate: Navigation;
|
|
7
|
+
interact: Interactions;
|
|
8
|
+
verify: Verifications;
|
|
9
|
+
constructor(page: Page);
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ElementInteractions = void 0;
|
|
4
|
+
const Interaction_1 = require("./interactions/Interaction");
|
|
5
|
+
const Navigation_1 = require("./interactions/Navigation");
|
|
6
|
+
const Verification_1 = require("./interactions/Verification");
|
|
7
|
+
class ElementInteractions {
|
|
8
|
+
navigate;
|
|
9
|
+
interact;
|
|
10
|
+
verify;
|
|
11
|
+
constructor(page) {
|
|
12
|
+
this.navigate = new Navigation_1.Navigation(page);
|
|
13
|
+
this.interact = new Interaction_1.Interactions(page);
|
|
14
|
+
this.verify = new Verification_1.Verifications(page);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.ElementInteractions = ElementInteractions;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ElementInteractions } from './ElementInteractions';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ElementInteractions = void 0;
|
|
4
|
+
var ElementInteractions_1 = require("./ElementInteractions");
|
|
5
|
+
Object.defineProperty(exports, "ElementInteractions", { enumerable: true, get: function () { return ElementInteractions_1.ElementInteractions; } });
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Page, Locator } from '@playwright/test';
|
|
2
|
+
/**
|
|
3
|
+
* Defines the strategy for selecting an option from a dropdown element.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum DropdownSelectType {
|
|
6
|
+
/** Selects a completely random, non-disabled option with a valid value. */
|
|
7
|
+
RANDOM = "random",
|
|
8
|
+
/** Selects an option based on its zero-based index in the dropdown. */
|
|
9
|
+
INDEX = "index",
|
|
10
|
+
/** Selects an option based on its exact 'value' attribute. */
|
|
11
|
+
VALUE = "value"
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for the `selectDropdown` method.
|
|
15
|
+
*/
|
|
16
|
+
export interface DropdownSelectOptions {
|
|
17
|
+
/** The selection strategy to use. Defaults to RANDOM. */
|
|
18
|
+
type?: DropdownSelectType;
|
|
19
|
+
/** The specific value attribute to select (Required if type is VALUE). */
|
|
20
|
+
value?: string;
|
|
21
|
+
/** The index of the option to select (Required if type is INDEX). */
|
|
22
|
+
index?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The `Interactions` class provides a robust set of methods for interacting
|
|
26
|
+
* with DOM elements via Playwright Locators. It abstracts away common boilerplate
|
|
27
|
+
* and handles edge cases like overlapping elements or optional UI components.
|
|
28
|
+
*/
|
|
29
|
+
export declare class Interactions {
|
|
30
|
+
private page;
|
|
31
|
+
/**
|
|
32
|
+
* Initializes the Interactions class.
|
|
33
|
+
* @param page - The current Playwright Page object.
|
|
34
|
+
*/
|
|
35
|
+
constructor(page: Page);
|
|
36
|
+
/**
|
|
37
|
+
* Performs a standard Playwright click on the given locator.
|
|
38
|
+
* Automatically waits for the element to be attached, visible, stable, and actionable.
|
|
39
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
40
|
+
*/
|
|
41
|
+
click(locator: Locator): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Dispatches a native 'click' event directly to the element.
|
|
44
|
+
* This bypasses Playwright's default scrolling and intersection observer checks.
|
|
45
|
+
* Highly useful for clicking elements that might be artificially obscured by sticky headers or transparent overlays.
|
|
46
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
47
|
+
*/
|
|
48
|
+
clickWithoutScrolling(locator: Locator): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Checks if an element is visible before attempting to click it.
|
|
51
|
+
* If the element is hidden or not in the DOM, it safely skips the action and logs a message
|
|
52
|
+
* without failing the test. Great for optional elements like cookie banners or promotional pop-ups.
|
|
53
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
54
|
+
*/
|
|
55
|
+
clickIfPresent(locator: Locator): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Clears any existing value in the target input field and types the provided text.
|
|
58
|
+
* @param locator - The Playwright Locator pointing to the input element.
|
|
59
|
+
* @param text - The string to type into the input field.
|
|
60
|
+
*/
|
|
61
|
+
fill(locator: Locator, text: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Uploads a local file to an `<input type="file">` element.
|
|
64
|
+
* @param locator - The Playwright Locator pointing to the file input element.
|
|
65
|
+
* @param filePath - The local file system path to the file you want to upload.
|
|
66
|
+
*/
|
|
67
|
+
uploadFile(locator: Locator, filePath: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Unified method to interact with `<select>` dropdown elements based on the specified `DropdownSelectType`.
|
|
70
|
+
* If no options are provided, it safely defaults to randomly selecting an enabled, non-empty option.
|
|
71
|
+
* * @param locator - The Playwright Locator pointing to the `<select>` element.
|
|
72
|
+
* @param options - Configuration specifying whether to select by 'random', 'index', or 'value'.
|
|
73
|
+
* @returns A promise that resolves to the exact 'value' attribute of the newly selected option.
|
|
74
|
+
* @throws Error if 'value' or 'index' is missing when their respective types are chosen, or if no enabled options exist.
|
|
75
|
+
*/
|
|
76
|
+
selectDropdown(locator: Locator, options?: DropdownSelectOptions): Promise<string>;
|
|
77
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Interactions = exports.DropdownSelectType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Defines the strategy for selecting an option from a dropdown element.
|
|
6
|
+
*/
|
|
7
|
+
var DropdownSelectType;
|
|
8
|
+
(function (DropdownSelectType) {
|
|
9
|
+
/** Selects a completely random, non-disabled option with a valid value. */
|
|
10
|
+
DropdownSelectType["RANDOM"] = "random";
|
|
11
|
+
/** Selects an option based on its zero-based index in the dropdown. */
|
|
12
|
+
DropdownSelectType["INDEX"] = "index";
|
|
13
|
+
/** Selects an option based on its exact 'value' attribute. */
|
|
14
|
+
DropdownSelectType["VALUE"] = "value";
|
|
15
|
+
})(DropdownSelectType || (exports.DropdownSelectType = DropdownSelectType = {}));
|
|
16
|
+
/**
|
|
17
|
+
* The `Interactions` class provides a robust set of methods for interacting
|
|
18
|
+
* with DOM elements via Playwright Locators. It abstracts away common boilerplate
|
|
19
|
+
* and handles edge cases like overlapping elements or optional UI components.
|
|
20
|
+
*/
|
|
21
|
+
class Interactions {
|
|
22
|
+
page;
|
|
23
|
+
/**
|
|
24
|
+
* Initializes the Interactions class.
|
|
25
|
+
* @param page - The current Playwright Page object.
|
|
26
|
+
*/
|
|
27
|
+
constructor(page) {
|
|
28
|
+
this.page = page;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Performs a standard Playwright click on the given locator.
|
|
32
|
+
* Automatically waits for the element to be attached, visible, stable, and actionable.
|
|
33
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
34
|
+
*/
|
|
35
|
+
async click(locator) {
|
|
36
|
+
await locator.click();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Dispatches a native 'click' event directly to the element.
|
|
40
|
+
* This bypasses Playwright's default scrolling and intersection observer checks.
|
|
41
|
+
* Highly useful for clicking elements that might be artificially obscured by sticky headers or transparent overlays.
|
|
42
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
43
|
+
*/
|
|
44
|
+
async clickWithoutScrolling(locator) {
|
|
45
|
+
await locator.dispatchEvent('click');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Checks if an element is visible before attempting to click it.
|
|
49
|
+
* If the element is hidden or not in the DOM, it safely skips the action and logs a message
|
|
50
|
+
* without failing the test. Great for optional elements like cookie banners or promotional pop-ups.
|
|
51
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
52
|
+
*/
|
|
53
|
+
async clickIfPresent(locator) {
|
|
54
|
+
if (await locator.isVisible()) {
|
|
55
|
+
await locator.click();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.log(`[Action] -> Locator was not visible. Skipping click.`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Clears any existing value in the target input field and types the provided text.
|
|
63
|
+
* @param locator - The Playwright Locator pointing to the input element.
|
|
64
|
+
* @param text - The string to type into the input field.
|
|
65
|
+
*/
|
|
66
|
+
async fill(locator, text) {
|
|
67
|
+
await locator.fill(text);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Uploads a local file to an `<input type="file">` element.
|
|
71
|
+
* @param locator - The Playwright Locator pointing to the file input element.
|
|
72
|
+
* @param filePath - The local file system path to the file you want to upload.
|
|
73
|
+
*/
|
|
74
|
+
async uploadFile(locator, filePath) {
|
|
75
|
+
console.log(`[Action] -> Uploading file from path "${filePath}"`);
|
|
76
|
+
await locator.setInputFiles(filePath);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Unified method to interact with `<select>` dropdown elements based on the specified `DropdownSelectType`.
|
|
80
|
+
* If no options are provided, it safely defaults to randomly selecting an enabled, non-empty option.
|
|
81
|
+
* * @param locator - The Playwright Locator pointing to the `<select>` element.
|
|
82
|
+
* @param options - Configuration specifying whether to select by 'random', 'index', or 'value'.
|
|
83
|
+
* @returns A promise that resolves to the exact 'value' attribute of the newly selected option.
|
|
84
|
+
* @throws Error if 'value' or 'index' is missing when their respective types are chosen, or if no enabled options exist.
|
|
85
|
+
*/
|
|
86
|
+
async selectDropdown(locator, options = { type: DropdownSelectType.RANDOM }) {
|
|
87
|
+
const type = options.type ?? DropdownSelectType.RANDOM;
|
|
88
|
+
if (type === DropdownSelectType.VALUE) {
|
|
89
|
+
if (options.value === undefined) {
|
|
90
|
+
throw new Error('[Action] Error -> "value" must be provided when using DropdownSelectType.VALUE.');
|
|
91
|
+
}
|
|
92
|
+
const selected = await locator.selectOption({ value: options.value });
|
|
93
|
+
return selected[0];
|
|
94
|
+
}
|
|
95
|
+
if (type === DropdownSelectType.INDEX) {
|
|
96
|
+
if (options.index === undefined) {
|
|
97
|
+
throw new Error('[Action] Error -> "index" must be provided when using DropdownSelectType.INDEX.');
|
|
98
|
+
}
|
|
99
|
+
const selected = await locator.selectOption({ index: options.index });
|
|
100
|
+
return selected[0];
|
|
101
|
+
}
|
|
102
|
+
const enabledOptions = locator.locator('option:not([disabled]):not([value=""])');
|
|
103
|
+
const count = await enabledOptions.count();
|
|
104
|
+
if (count === 0) {
|
|
105
|
+
throw new Error('[Action] Error -> No enabled options found to select!');
|
|
106
|
+
}
|
|
107
|
+
const randomIndex = Math.floor(Math.random() * count);
|
|
108
|
+
const valueToSelect = await enabledOptions.nth(randomIndex).getAttribute('value');
|
|
109
|
+
if (valueToSelect === null) {
|
|
110
|
+
throw new Error(`[Action] Error -> Option at index ${randomIndex} is missing a "value" attribute.`);
|
|
111
|
+
}
|
|
112
|
+
const selected = await locator.selectOption({ value: valueToSelect });
|
|
113
|
+
return selected[0];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.Interactions = Interactions;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
/**
|
|
3
|
+
* The `Navigation` class provides a streamlined interface for managing browser
|
|
4
|
+
* navigation, history, and viewport settings within Playwright.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Navigation {
|
|
7
|
+
private page;
|
|
8
|
+
/**
|
|
9
|
+
* Initializes the Navigation class.
|
|
10
|
+
* @param page - The current Playwright Page object.
|
|
11
|
+
*/
|
|
12
|
+
constructor(page: Page);
|
|
13
|
+
/**
|
|
14
|
+
* Navigates the active browser page to the specified URL.
|
|
15
|
+
* Automatically waits for the page to reach the default 'load' state.
|
|
16
|
+
* @param url - The absolute or relative URL to navigate to.
|
|
17
|
+
*/
|
|
18
|
+
toUrl(url: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Reloads the current page.
|
|
21
|
+
* Useful for resetting application state or checking data persistence.
|
|
22
|
+
*/
|
|
23
|
+
reload(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Navigates the browser history stack either backwards or forwards.
|
|
26
|
+
* Mirrors the behavior of the browser's native Back and Forward buttons.
|
|
27
|
+
* @param direction - The direction to move in history: either 'BACKWARDS' or 'FORWARDS'.
|
|
28
|
+
*/
|
|
29
|
+
backOrForward(direction: 'BACKWARDS' | 'FORWARDS'): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Resizes the browser viewport to the specified dimensions.
|
|
32
|
+
* Useful for simulating different device screen sizes or responsive breakpoints.
|
|
33
|
+
* @param width - The desired width of the viewport in pixels.
|
|
34
|
+
* @param height - The desired height of the viewport in pixels.
|
|
35
|
+
*/
|
|
36
|
+
setViewport(width: number, height: number): Promise<void>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Navigation = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The `Navigation` class provides a streamlined interface for managing browser
|
|
6
|
+
* navigation, history, and viewport settings within Playwright.
|
|
7
|
+
*/
|
|
8
|
+
class Navigation {
|
|
9
|
+
page;
|
|
10
|
+
/**
|
|
11
|
+
* Initializes the Navigation class.
|
|
12
|
+
* @param page - The current Playwright Page object.
|
|
13
|
+
*/
|
|
14
|
+
constructor(page) {
|
|
15
|
+
this.page = page;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Navigates the active browser page to the specified URL.
|
|
19
|
+
* Automatically waits for the page to reach the default 'load' state.
|
|
20
|
+
* @param url - The absolute or relative URL to navigate to.
|
|
21
|
+
*/
|
|
22
|
+
async toUrl(url) {
|
|
23
|
+
console.log(`[Navigate] -> Navigating to URL: ${url}`);
|
|
24
|
+
await this.page.goto(url);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Reloads the current page.
|
|
28
|
+
* Useful for resetting application state or checking data persistence.
|
|
29
|
+
*/
|
|
30
|
+
async reload() {
|
|
31
|
+
console.log(`[Navigate] -> Refreshing the current page`);
|
|
32
|
+
await this.page.reload();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Navigates the browser history stack either backwards or forwards.
|
|
36
|
+
* Mirrors the behavior of the browser's native Back and Forward buttons.
|
|
37
|
+
* @param direction - The direction to move in history: either 'BACKWARDS' or 'FORWARDS'.
|
|
38
|
+
*/
|
|
39
|
+
async backOrForward(direction) {
|
|
40
|
+
console.log(`[Navigate] -> Moving browser history ${direction.toLowerCase()}`);
|
|
41
|
+
if (direction === 'BACKWARDS') {
|
|
42
|
+
await this.page.goBack();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await this.page.goForward();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resizes the browser viewport to the specified dimensions.
|
|
50
|
+
* Useful for simulating different device screen sizes or responsive breakpoints.
|
|
51
|
+
* @param width - The desired width of the viewport in pixels.
|
|
52
|
+
* @param height - The desired height of the viewport in pixels.
|
|
53
|
+
*/
|
|
54
|
+
async setViewport(width, height) {
|
|
55
|
+
console.log(`[Navigate] -> Setting viewport size to ${width}x${height}`);
|
|
56
|
+
await this.page.setViewportSize({ width, height });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.Navigation = Navigation;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Page, Locator } from '@playwright/test';
|
|
2
|
+
/**
|
|
3
|
+
* The `Verifications` class provides a unified wrapper around Playwright's `expect` assertions.
|
|
4
|
+
* It standardizes timeouts, adds helpful logging, and includes advanced custom verifications
|
|
5
|
+
* (like image decoding) to keep your test assertions clean and reliable.
|
|
6
|
+
*/
|
|
7
|
+
export declare class Verifications {
|
|
8
|
+
private page;
|
|
9
|
+
/** The standard timeout applied to all verifications in this class. */
|
|
10
|
+
private readonly ELEMENT_TIMEOUT;
|
|
11
|
+
/**
|
|
12
|
+
* Initializes the Verifications class.
|
|
13
|
+
* @param page - The current Playwright Page object.
|
|
14
|
+
*/
|
|
15
|
+
constructor(page: Page);
|
|
16
|
+
/**
|
|
17
|
+
* Asserts that the specified element's text exactly matches the expected text.
|
|
18
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
19
|
+
* @param expectedText - The exact text string expected to be inside the element.
|
|
20
|
+
*/
|
|
21
|
+
text(locator: Locator, expectedText: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Asserts that the specified element contains the expected substring.
|
|
24
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
25
|
+
* @param expectedText - The substring expected to be present within the element's text.
|
|
26
|
+
*/
|
|
27
|
+
textContains(locator: Locator, expectedText: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Asserts that the specified element is attached to the DOM and is visible.
|
|
30
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
31
|
+
*/
|
|
32
|
+
presence(locator: Locator): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Asserts that the specified element is either hidden or completely detached from the DOM.
|
|
35
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
36
|
+
*/
|
|
37
|
+
absence(locator: Locator): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Asserts the interactive state of an element (whether it is enabled or disabled).
|
|
40
|
+
* Useful for checking buttons or input fields.
|
|
41
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
42
|
+
* @param state - The expected state: either 'enabled' or 'disabled'.
|
|
43
|
+
*/
|
|
44
|
+
state(locator: Locator, state: 'enabled' | 'disabled'): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Asserts that the current browser URL contains the expected substring.
|
|
47
|
+
* Evaluates using a case-insensitive regular expression.
|
|
48
|
+
* @param text - The substring expected to be present within the active URL.
|
|
49
|
+
*/
|
|
50
|
+
urlContains(text: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Asserts that an element has a specific HTML attribute with an exact value.
|
|
53
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
54
|
+
* @param attributeName - The name of the HTML attribute to check (e.g., 'href', 'class', 'alt').
|
|
55
|
+
* @param expectedValue - The exact expected value of the attribute.
|
|
56
|
+
*/
|
|
57
|
+
attribute(locator: Locator, attributeName: string, expectedValue: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Performs a rigorous, multi-step verification on one or more images.
|
|
60
|
+
* It checks for visibility, ensures a valid 'src' attribute exists, confirms the
|
|
61
|
+
* 'naturalWidth' is greater than 0, and evaluates the browser's native `decode()`
|
|
62
|
+
* promise to guarantee the image is fully rendered and not a broken link.
|
|
63
|
+
* * @param imagesLocator - The Playwright Locator pointing to the image element(s).
|
|
64
|
+
* @param scroll - Whether to smoothly scroll the image(s) into the viewport before verifying (default: true).
|
|
65
|
+
* @throws Will throw an error if no images are found matching the locator or if any image fails to decode.
|
|
66
|
+
*/
|
|
67
|
+
images(imagesLocator: Locator, scroll?: boolean): Promise<void>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Verifications = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
/**
|
|
6
|
+
* The `Verifications` class provides a unified wrapper around Playwright's `expect` assertions.
|
|
7
|
+
* It standardizes timeouts, adds helpful logging, and includes advanced custom verifications
|
|
8
|
+
* (like image decoding) to keep your test assertions clean and reliable.
|
|
9
|
+
*/
|
|
10
|
+
class Verifications {
|
|
11
|
+
page;
|
|
12
|
+
/** The standard timeout applied to all verifications in this class. */
|
|
13
|
+
ELEMENT_TIMEOUT = 10000;
|
|
14
|
+
/**
|
|
15
|
+
* Initializes the Verifications class.
|
|
16
|
+
* @param page - The current Playwright Page object.
|
|
17
|
+
*/
|
|
18
|
+
constructor(page) {
|
|
19
|
+
this.page = page;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Asserts that the specified element's text exactly matches the expected text.
|
|
23
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
24
|
+
* @param expectedText - The exact text string expected to be inside the element.
|
|
25
|
+
*/
|
|
26
|
+
async text(locator, expectedText) {
|
|
27
|
+
await (0, test_1.expect)(locator).toHaveText(expectedText, { timeout: this.ELEMENT_TIMEOUT });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Asserts that the specified element contains the expected substring.
|
|
31
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
32
|
+
* @param expectedText - The substring expected to be present within the element's text.
|
|
33
|
+
*/
|
|
34
|
+
async textContains(locator, expectedText) {
|
|
35
|
+
await (0, test_1.expect)(locator).toContainText(expectedText, { timeout: this.ELEMENT_TIMEOUT });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Asserts that the specified element is attached to the DOM and is visible.
|
|
39
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
40
|
+
*/
|
|
41
|
+
async presence(locator) {
|
|
42
|
+
await (0, test_1.expect)(locator).toBeVisible({ timeout: this.ELEMENT_TIMEOUT });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Asserts that the specified element is either hidden or completely detached from the DOM.
|
|
46
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
47
|
+
*/
|
|
48
|
+
async absence(locator) {
|
|
49
|
+
console.log(`[Verify] -> Asserting absence of "${locator}"`);
|
|
50
|
+
await (0, test_1.expect)(locator).toBeHidden({ timeout: this.ELEMENT_TIMEOUT });
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Asserts the interactive state of an element (whether it is enabled or disabled).
|
|
54
|
+
* Useful for checking buttons or input fields.
|
|
55
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
56
|
+
* @param state - The expected state: either 'enabled' or 'disabled'.
|
|
57
|
+
*/
|
|
58
|
+
async state(locator, state) {
|
|
59
|
+
console.log(`[Verify] -> Asserting state of "${locator}" is: "${state}"`);
|
|
60
|
+
if (state === 'enabled') {
|
|
61
|
+
await (0, test_1.expect)(locator).toBeEnabled({ timeout: this.ELEMENT_TIMEOUT });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
await (0, test_1.expect)(locator).toBeDisabled({ timeout: this.ELEMENT_TIMEOUT });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Asserts that the current browser URL contains the expected substring.
|
|
69
|
+
* Evaluates using a case-insensitive regular expression.
|
|
70
|
+
* @param text - The substring expected to be present within the active URL.
|
|
71
|
+
*/
|
|
72
|
+
async urlContains(text) {
|
|
73
|
+
console.log(`[Verify] -> Asserting current URL contains: "${text}"`);
|
|
74
|
+
await (0, test_1.expect)(this.page).toHaveURL(new RegExp(text, 'i'), { timeout: this.ELEMENT_TIMEOUT });
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Asserts that an element has a specific HTML attribute with an exact value.
|
|
78
|
+
* @param locator - The Playwright Locator pointing to the target element.
|
|
79
|
+
* @param attributeName - The name of the HTML attribute to check (e.g., 'href', 'class', 'alt').
|
|
80
|
+
* @param expectedValue - The exact expected value of the attribute.
|
|
81
|
+
*/
|
|
82
|
+
async attribute(locator, attributeName, expectedValue) {
|
|
83
|
+
await (0, test_1.expect)(locator).toHaveAttribute(attributeName, expectedValue, { timeout: this.ELEMENT_TIMEOUT });
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Performs a rigorous, multi-step verification on one or more images.
|
|
87
|
+
* It checks for visibility, ensures a valid 'src' attribute exists, confirms the
|
|
88
|
+
* 'naturalWidth' is greater than 0, and evaluates the browser's native `decode()`
|
|
89
|
+
* promise to guarantee the image is fully rendered and not a broken link.
|
|
90
|
+
* * @param imagesLocator - The Playwright Locator pointing to the image element(s).
|
|
91
|
+
* @param scroll - Whether to smoothly scroll the image(s) into the viewport before verifying (default: true).
|
|
92
|
+
* @throws Will throw an error if no images are found matching the locator or if any image fails to decode.
|
|
93
|
+
*/
|
|
94
|
+
async images(imagesLocator, scroll = true) {
|
|
95
|
+
const productImages = await imagesLocator.all();
|
|
96
|
+
if (productImages.length === 0) {
|
|
97
|
+
throw new Error(`[Verify] -> No images found for '${imagesLocator}'.`);
|
|
98
|
+
}
|
|
99
|
+
for (let i = 0; i < productImages.length; i++) {
|
|
100
|
+
const productImage = productImages[i];
|
|
101
|
+
if (scroll) {
|
|
102
|
+
await productImage.scrollIntoViewIfNeeded().catch(() => { });
|
|
103
|
+
}
|
|
104
|
+
await (0, test_1.expect)(productImage).toBeVisible({ timeout: this.ELEMENT_TIMEOUT });
|
|
105
|
+
await (0, test_1.expect)(productImage).toHaveAttribute('src', /.+/, { timeout: this.ELEMENT_TIMEOUT });
|
|
106
|
+
await (0, test_1.expect)(productImage).not.toHaveJSProperty('naturalWidth', 0, { timeout: this.ELEMENT_TIMEOUT });
|
|
107
|
+
const isDecoded = await productImage.evaluate(async (img) => {
|
|
108
|
+
if (!img.src)
|
|
109
|
+
return false;
|
|
110
|
+
try {
|
|
111
|
+
await img.decode();
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
(0, test_1.expect)(isDecoded, `Image ${i + 1} failed to decode for ${imagesLocator}`).toBe(true);
|
|
119
|
+
}
|
|
120
|
+
console.log(`[Verify] -> Successfully verified ${productImages.length} images for "${imagesLocator}"`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.Verifications = Verifications;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { ElementRepository } from 'pw-element-repository';
|
|
3
|
+
import { DropdownSelectOptions } from '../interactions/Interaction';
|
|
4
|
+
/**
|
|
5
|
+
* The `Steps` class serves as a unified Facade for test orchestration.
|
|
6
|
+
* It combines element acquisition (via `pw-element-repository`) with
|
|
7
|
+
* Playwright interactions, navigation, and verifications to keep test files clean,
|
|
8
|
+
* readable, and free of raw locators.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Steps {
|
|
11
|
+
private page;
|
|
12
|
+
private repo;
|
|
13
|
+
private interact;
|
|
14
|
+
private navigate;
|
|
15
|
+
private verify;
|
|
16
|
+
/**
|
|
17
|
+
* Initializes the Steps class with the required Playwright page and element repository.
|
|
18
|
+
* * @param page - The current Playwright Page object.
|
|
19
|
+
* @param repo - An initialized instance of `ElementRepository` containing your locators.
|
|
20
|
+
*/
|
|
21
|
+
constructor(page: Page, repo: ElementRepository);
|
|
22
|
+
/**
|
|
23
|
+
* Navigates the browser to the specified URL.
|
|
24
|
+
* * @param url - The absolute or relative URL to navigate to.
|
|
25
|
+
*/
|
|
26
|
+
navigateTo(url: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Reloads the current page.
|
|
29
|
+
*/
|
|
30
|
+
refresh(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Retrieves an element from the repository and performs a standard click.
|
|
33
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
34
|
+
* @param elementName - The specific element name in your repository.
|
|
35
|
+
*/
|
|
36
|
+
click(pageName: string, elementName: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Retrieves a random element from a resolved list of locators and clicks it.
|
|
39
|
+
* Useful for clicking random items in a list or grid (e.g., product cards).
|
|
40
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
41
|
+
* @param elementName - The specific element name in your repository representing multiple elements.
|
|
42
|
+
*/
|
|
43
|
+
clickRandom(pageName: string, elementName: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves an element and clicks it only if it is visible.
|
|
46
|
+
* Prevents test failures on optional elements like cookie banners or promotional pop-ups.
|
|
47
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
48
|
+
* @param elementName - The specific element name in your repository.
|
|
49
|
+
*/
|
|
50
|
+
clickIfPresent(pageName: string, elementName: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Retrieves an input field and fills it with the provided text, replacing any existing value.
|
|
53
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
54
|
+
* @param elementName - The specific element name in your repository.
|
|
55
|
+
* @param text - The text to type into the input field.
|
|
56
|
+
*/
|
|
57
|
+
fill(pageName: string, elementName: string, text: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Retrieves an input element of type `file` and sets its files.
|
|
60
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
61
|
+
* @param elementName - The specific element name in your repository.
|
|
62
|
+
* @param filePath - The local file path of the file to be uploaded.
|
|
63
|
+
*/
|
|
64
|
+
uploadFile(pageName: string, elementName: string, filePath: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Retrieves a `<select>` dropdown element and selects an option based on the provided strategy.
|
|
67
|
+
* Defaults to selecting a random, non-disabled option if no strategy is specified.
|
|
68
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
69
|
+
* @param elementName - The specific element name in your repository.
|
|
70
|
+
* @param options - Configuration specifying whether to select by 'random', 'index', or 'value'.
|
|
71
|
+
* @returns The exact value attribute of the selected option.
|
|
72
|
+
*/
|
|
73
|
+
selectDropdown(pageName: string, elementName: string, options?: DropdownSelectOptions): Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* Asserts that a specified element is attached to the DOM and is visible.
|
|
76
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
77
|
+
* @param elementName - The specific element name in your repository.
|
|
78
|
+
*/
|
|
79
|
+
verifyPresence(pageName: string, elementName: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Asserts that a specified element is hidden or completely detached from the DOM.
|
|
82
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
83
|
+
* @param elementName - The specific element name in your repository.
|
|
84
|
+
*/
|
|
85
|
+
verifyAbsence(pageName: string, elementName: string): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Asserts that the specified element exactly matches the expected text.
|
|
88
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
89
|
+
* @param elementName - The specific element name in your repository.
|
|
90
|
+
* @param expectedText - The exact string expected inside the element.
|
|
91
|
+
*/
|
|
92
|
+
verifyText(pageName: string, elementName: string, expectedText: string): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Performs a rigorous verification of one or more images.
|
|
95
|
+
* Asserts visibility, checks for a valid 'src' attribute, ensures a positive 'naturalWidth',
|
|
96
|
+
* and evaluates the native browser `decode()` promise to ensure the image isn't broken.
|
|
97
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
98
|
+
* @param elementName - The specific element name in your repository.
|
|
99
|
+
* @param scroll - Whether to smoothly scroll the image(s) into view before verifying (default: true).
|
|
100
|
+
*/
|
|
101
|
+
verifyImages(pageName: string, elementName: string, scroll?: boolean): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Asserts that the current browser URL contains the expected substring.
|
|
104
|
+
* * @param text - The substring expected to be present within the active URL.
|
|
105
|
+
*/
|
|
106
|
+
verifyUrlContains(text: string): Promise<void>;
|
|
107
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Steps = void 0;
|
|
4
|
+
const ElementInteractions_1 = require("../ElementInteractions");
|
|
5
|
+
/**
|
|
6
|
+
* The `Steps` class serves as a unified Facade for test orchestration.
|
|
7
|
+
* It combines element acquisition (via `pw-element-repository`) with
|
|
8
|
+
* Playwright interactions, navigation, and verifications to keep test files clean,
|
|
9
|
+
* readable, and free of raw locators.
|
|
10
|
+
*/
|
|
11
|
+
class Steps {
|
|
12
|
+
page;
|
|
13
|
+
repo;
|
|
14
|
+
interact;
|
|
15
|
+
navigate;
|
|
16
|
+
verify;
|
|
17
|
+
/**
|
|
18
|
+
* Initializes the Steps class with the required Playwright page and element repository.
|
|
19
|
+
* * @param page - The current Playwright Page object.
|
|
20
|
+
* @param repo - An initialized instance of `ElementRepository` containing your locators.
|
|
21
|
+
*/
|
|
22
|
+
constructor(page, repo) {
|
|
23
|
+
this.page = page;
|
|
24
|
+
this.repo = repo;
|
|
25
|
+
const interactions = new ElementInteractions_1.ElementInteractions(page);
|
|
26
|
+
this.interact = interactions.interact;
|
|
27
|
+
this.navigate = interactions.navigate;
|
|
28
|
+
this.verify = interactions.verify;
|
|
29
|
+
}
|
|
30
|
+
// ==========================================
|
|
31
|
+
// 🧭 NAVIGATION STEPS
|
|
32
|
+
// ==========================================
|
|
33
|
+
/**
|
|
34
|
+
* Navigates the browser to the specified URL.
|
|
35
|
+
* * @param url - The absolute or relative URL to navigate to.
|
|
36
|
+
*/
|
|
37
|
+
async navigateTo(url) {
|
|
38
|
+
console.log(`[Step] -> Navigating to URL: "${url}"`);
|
|
39
|
+
await this.navigate.toUrl(url);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reloads the current page.
|
|
43
|
+
*/
|
|
44
|
+
async refresh() {
|
|
45
|
+
console.log(`[Step] -> Refreshing the current page`);
|
|
46
|
+
await this.navigate.reload();
|
|
47
|
+
}
|
|
48
|
+
// ==========================================
|
|
49
|
+
// 🖱️ INTERACTION STEPS
|
|
50
|
+
// ==========================================
|
|
51
|
+
/**
|
|
52
|
+
* Retrieves an element from the repository and performs a standard click.
|
|
53
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
54
|
+
* @param elementName - The specific element name in your repository.
|
|
55
|
+
*/
|
|
56
|
+
async click(pageName, elementName) {
|
|
57
|
+
console.log(`[Step] -> Clicking on '${elementName}' in '${pageName}'`);
|
|
58
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
59
|
+
await this.interact.click(locator);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Retrieves a random element from a resolved list of locators and clicks it.
|
|
63
|
+
* Useful for clicking random items in a list or grid (e.g., product cards).
|
|
64
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
65
|
+
* @param elementName - The specific element name in your repository representing multiple elements.
|
|
66
|
+
*/
|
|
67
|
+
async clickRandom(pageName, elementName) {
|
|
68
|
+
console.log(`[Step] -> Clicking a random element from '${elementName}' in '${pageName}'`);
|
|
69
|
+
const locator = await this.repo.getRandom(this.page, pageName, elementName);
|
|
70
|
+
await this.interact.click(locator);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Retrieves an element and clicks it only if it is visible.
|
|
74
|
+
* Prevents test failures on optional elements like cookie banners or promotional pop-ups.
|
|
75
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
76
|
+
* @param elementName - The specific element name in your repository.
|
|
77
|
+
*/
|
|
78
|
+
async clickIfPresent(pageName, elementName) {
|
|
79
|
+
console.log(`[Step] -> Clicking on '${elementName}' in '${pageName}' (if present)`);
|
|
80
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
81
|
+
await this.interact.clickIfPresent(locator);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Retrieves an input field and fills it with the provided text, replacing any existing value.
|
|
85
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
86
|
+
* @param elementName - The specific element name in your repository.
|
|
87
|
+
* @param text - The text to type into the input field.
|
|
88
|
+
*/
|
|
89
|
+
async fill(pageName, elementName, text) {
|
|
90
|
+
console.log(`[Step] -> Filling '${elementName}' in '${pageName}' with text: "${text}"`);
|
|
91
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
92
|
+
await this.interact.fill(locator, text);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Retrieves an input element of type `file` and sets its files.
|
|
96
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
97
|
+
* @param elementName - The specific element name in your repository.
|
|
98
|
+
* @param filePath - The local file path of the file to be uploaded.
|
|
99
|
+
*/
|
|
100
|
+
async uploadFile(pageName, elementName, filePath) {
|
|
101
|
+
console.log(`[Step] -> Uploading file "${filePath}" to '${elementName}' in '${pageName}'`);
|
|
102
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
103
|
+
await this.interact.uploadFile(locator, filePath);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Retrieves a `<select>` dropdown element and selects an option based on the provided strategy.
|
|
107
|
+
* Defaults to selecting a random, non-disabled option if no strategy is specified.
|
|
108
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
109
|
+
* @param elementName - The specific element name in your repository.
|
|
110
|
+
* @param options - Configuration specifying whether to select by 'random', 'index', or 'value'.
|
|
111
|
+
* @returns The exact value attribute of the selected option.
|
|
112
|
+
*/
|
|
113
|
+
async selectDropdown(pageName, elementName, options) {
|
|
114
|
+
const optLog = options ? JSON.stringify(options) : 'default (random)';
|
|
115
|
+
console.log(`[Step] -> Selecting dropdown option for '${elementName}' in '${pageName}' using options: ${optLog}`);
|
|
116
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
117
|
+
return await this.interact.selectDropdown(locator, options);
|
|
118
|
+
}
|
|
119
|
+
// ==========================================
|
|
120
|
+
// ✅ VERIFICATION STEPS
|
|
121
|
+
// ==========================================
|
|
122
|
+
/**
|
|
123
|
+
* Asserts that a specified element is attached to the DOM and is visible.
|
|
124
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
125
|
+
* @param elementName - The specific element name in your repository.
|
|
126
|
+
*/
|
|
127
|
+
async verifyPresence(pageName, elementName) {
|
|
128
|
+
console.log(`[Step] -> Verifying presence of '${elementName}' in '${pageName}'`);
|
|
129
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
130
|
+
await this.verify.presence(locator);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Asserts that a specified element is hidden or completely detached from the DOM.
|
|
134
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
135
|
+
* @param elementName - The specific element name in your repository.
|
|
136
|
+
*/
|
|
137
|
+
async verifyAbsence(pageName, elementName) {
|
|
138
|
+
console.log(`[Step] -> Verifying absence of '${elementName}' in '${pageName}'`);
|
|
139
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
140
|
+
await this.verify.absence(locator);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Asserts that the specified element exactly matches the expected text.
|
|
144
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
145
|
+
* @param elementName - The specific element name in your repository.
|
|
146
|
+
* @param expectedText - The exact string expected inside the element.
|
|
147
|
+
*/
|
|
148
|
+
async verifyText(pageName, elementName, expectedText) {
|
|
149
|
+
console.log(`[Step] -> Verifying text of '${elementName}' in '${pageName}' matches: "${expectedText}"`);
|
|
150
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
151
|
+
await this.verify.text(locator, expectedText);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Performs a rigorous verification of one or more images.
|
|
155
|
+
* Asserts visibility, checks for a valid 'src' attribute, ensures a positive 'naturalWidth',
|
|
156
|
+
* and evaluates the native browser `decode()` promise to ensure the image isn't broken.
|
|
157
|
+
* * @param pageName - The page or component grouping name in your repository.
|
|
158
|
+
* @param elementName - The specific element name in your repository.
|
|
159
|
+
* @param scroll - Whether to smoothly scroll the image(s) into view before verifying (default: true).
|
|
160
|
+
*/
|
|
161
|
+
async verifyImages(pageName, elementName, scroll = true) {
|
|
162
|
+
console.log(`[Step] -> Verifying images for '${elementName}' in '${pageName}' (Scroll: ${scroll})`);
|
|
163
|
+
const locator = await this.repo.get(this.page, pageName, elementName);
|
|
164
|
+
await this.verify.images(locator, scroll);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Asserts that the current browser URL contains the expected substring.
|
|
168
|
+
* * @param text - The substring expected to be present within the active URL.
|
|
169
|
+
*/
|
|
170
|
+
async verifyUrlContains(text) {
|
|
171
|
+
console.log(`[Step] -> Verifying current URL contains: "${text}"`);
|
|
172
|
+
await this.verify.urlContains(text);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.Steps = Steps;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DateUtilities = void 0;
|
|
4
|
+
class DateUtilities {
|
|
5
|
+
/**
|
|
6
|
+
* Reformats a recognizable date string into a target format.
|
|
7
|
+
* Mirrors the Java DateUtilities.reformatDateString method.
|
|
8
|
+
*/
|
|
9
|
+
static reformatDateString(rawDate, format) {
|
|
10
|
+
// Parse the raw date string into a JS Date object
|
|
11
|
+
const date = new Date(rawDate);
|
|
12
|
+
// Guard clause: Check if the date is valid before formatting
|
|
13
|
+
if (isNaN(date.getTime())) {
|
|
14
|
+
throw new Error(`Invalid date string provided: ${rawDate}`);
|
|
15
|
+
}
|
|
16
|
+
const yyyy = date.getFullYear().toString();
|
|
17
|
+
const MM = String(date.getMonth() + 1).padStart(2, '0');
|
|
18
|
+
const dd = String(date.getDate()).padStart(2, '0');
|
|
19
|
+
// Unpadded variables for single-digit months/days
|
|
20
|
+
const M = String(date.getMonth() + 1);
|
|
21
|
+
const d = String(date.getDate());
|
|
22
|
+
// You can expand this switch/if statement as your framework's formatting needs grow
|
|
23
|
+
switch (format) {
|
|
24
|
+
case 'yyyy-MM-dd':
|
|
25
|
+
return `${yyyy}-${MM}-${dd}`;
|
|
26
|
+
case 'dd-MM-yyyy':
|
|
27
|
+
return `${dd}-${MM}-${yyyy}`;
|
|
28
|
+
case 'dd MMM yyyy':
|
|
29
|
+
const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
30
|
+
return `${dd} ${monthNames[date.getMonth()]} ${yyyy}`;
|
|
31
|
+
case 'yyyy-M-d': // 💡 New format matching the modal's output
|
|
32
|
+
return `${yyyy}-${M}-${d}`;
|
|
33
|
+
default:
|
|
34
|
+
console.warn(`Format ${format} not fully supported, returning ISO date.`);
|
|
35
|
+
return `${yyyy}-${MM}-${dd}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.DateUtilities = DateUtilities;
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pw-element-interactions",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A robust, readable interaction and assertion Facade for Playwright. Abstract away boilerplate into semantic, English-like methods, making your test automation framework cleaner, easier to maintain, and accessible to non-developers.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "rm -rf dist",
|
|
9
|
+
"build": "npm run clean && tsc",
|
|
10
|
+
"test": "npx playwright test",
|
|
11
|
+
"prepublishOnly": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@playwright/test": ">=1.0.0",
|
|
18
|
+
"pw-element-repository": ">=0.0.3"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@playwright/test": "^1.58.2",
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"pw-element-repository": "^0.0.3",
|
|
24
|
+
"typescript": "^5.0.0"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"playwright",
|
|
28
|
+
"automation",
|
|
29
|
+
"interactions",
|
|
30
|
+
"assertions",
|
|
31
|
+
"clean-code",
|
|
32
|
+
"facade-pattern",
|
|
33
|
+
"test-automation",
|
|
34
|
+
"steps-api"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public",
|
|
38
|
+
"provenance": true
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/Umutayb/pw-element-interactions.git"
|
|
43
|
+
},
|
|
44
|
+
"author": "Umut Ay Bora",
|
|
45
|
+
"license": "MIT"
|
|
46
|
+
}
|