pomwright
Version:
POMWright is a complementary test framework for Playwright written in TypeScript.
911 lines (673 loc) • 31.9 kB
Markdown
# pomwright
## 1.2.0
### Minor Changes
- [#31](https://github.com/DyHex/POMWright/pull/31) [`bc29062`](https://github.com/DyHex/POMWright/commit/bc2906258a88acde1dd1479d7a000d036912f45a) Thanks [@DyHex](https://github.com/DyHex)! - # LocatorSchema Enhancements: `filter` Property, `.addFilter()`, Updated `.update()`, and Enhanced `getNestedLocator()`
## Overview
This release introduces several key enhancements to the POMWright. These improvements aim to provide greater flexibility, maintainability, and type safety when constructing and managing locators in your Page Object Models (POMs). The main updates include:
- **New `filter` Property**: Extends filtering capabilities beyond the `locator` method.
- **New `.addFilter()` Method**: Facilitates dynamic addition of filters to locators.
- **Updated `.update()` Method**: Replaces deprecated `.update` and `.updates` methods with a more intuitive interface (none-breaking).
- **Enhanced `getNestedLocator()` Method**: Shifts from index-based to subPath-based indexing for better readability and maintainability.
- **Export of `LocatorSchemaWithoutPath`**: Enables partial or full reuse of locator schemas across different contexts.
## Changes
### 1. New `filter` Property for `LocatorSchema`
#### Purpose
The existing `locatorOptions` property in `LocatorSchema` is specific to the `locator` method, limiting its applicability. The newly introduced `filter` property extends filtering capabilities to all locator types (e.g., `role`, `label`, `placeholder`, `testid`, `id`, etc.), excluding `frameLocator`.
#### Behavior
- **Global Applicability**: Unlike `locatorOptions`, the `filter` property can be applied to various locator methods, enhancing versatility.
- **Priority Application**: When a `filter` is defined, it is always applied and will always be the first filter applied to the locator created from that LocatorSchema, the only exception is `locatorOptions` used with `locator`. This ensures consistent and prioritized filtering across different locator types.
#### Usage Examples
**Before: Using `locatorOptions` (Limited to `locator` method)**
```typescript
this.locators.addSchema("main.products.radio@junior", {
locator: "radio",
locatorOptions: { hasText: "some text" },
locatorMethod: GetByMethod.locator,
});
```
**After: Using `filter` (Applicable to Multiple Locator Methods)**
```typescript
this.locators.addSchema("main.products.radio@junior", {
locator: "input",
filter: { hasText: "some text" },
locatorMethod: GetByMethod.locator,
});
```
**With `role` Locator Method:**
```typescript
this.locators.addSchema("main.products.radio@junior", {
role: "radio",
filter: { hasText: "some text" },
locatorMethod: GetByMethod.role,
});
```
**Combined Example:**
```typescript
this.locators.addSchema("main.subscription.form.item.section@header", {
role: "region",
roleOptions: { name: "Subscription Details" },
filter: { hasText: "Mobile 2 GB" },
locatorMethod: GetByMethod.role,
});
```
#### Benefits
- **Enhanced Flexibility**: Apply default filters to various LocatorSchema.
- **Improved Locator Precision**: Chain multiple filters to narrow down locators based on complex criteria.
- **Backward Compatibility**: Existing `locatorOptions` works the same way as before, ensuring no disruption to current implementations.
### 2. New `.addFilter()` Method for `.getLocatorSchema()`
#### Purpose
The `.addFilter()` method allows dynamic addition of filters to any part of the locator chain, enhancing flexibility in locator construction without modifying the original `LocatorSchema` at any point in a test.
#### Method Signature
```typescript
.addFilter(
subPath: SubPaths<LocatorSchemaPathType, LocatorSubstring>,
filterData: FilterEntry
): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>
```
#### Parameters
- `subPath`: A valid sub-path within the `LocatorSchemaPath` argument to .getLocatorSchema().
- `filterData`: An object defining the filter criteria, which can include:
- `has?: Locator`
- `hasNot?: Locator`
- `hasText?: string | RegExp`
- `hasNotText?: string | RegExp`
#### Usage Examples
**Adding Filters to Specific Sub-Paths:**
```typescript
const allCheckboxesForBrandFilters = await poc
.getLocatorSchema("main.products.searchControls.filterType.label.checkbox")
.addFilter("main.products.searchControls.filterType", {
hasText: /Producer/i,
})
.getNestedLocator();
```
**Chaining Multiple Filters:**
```typescript
const refinedCheckboxes = await poc
.getLocatorSchema("main.products.searchControls.filterType.label.checkbox")
.addFilter("main.products.searchControls.filterType", {
hasText: /Producer/i,
hasNotText: /discontinued/i,
})
.addFilter("main.products.searchControls.filterType.label", {
hasText: "Samsung",
})
.addFilter("main.products.searchControls.filterType.label", {
has: poc.page.getByRole("checkbox"),
})
.getNestedLocator();
```
**Combining `filter` Property and `.addFilter()`:**
```typescript
this.locators.addSchema("main.subscription.form.item.section@header", {
role: "region",
roleOptions: { name: "Subscription Details" },
filter: { hasText: "Mobile 2 GB" },
locatorMethod: GetByMethod.role,
});
const specificSection = await poc
.getLocatorSchema("main.subscription.form.item.section@header")
.addFilter("main.subscription.form.item.section@header", {
hasText: "Additional Services",
})
.getNestedLocator();
```
#### Benefits
- **Dynamic Filtering**: Add or modify filters on-the-fly without altering the original schema definitions.
- **Chainability**: Easily chain multiple `.addFilter()` calls to build complex locator chains.
- **Error Handling**: Attempts to add filters to invalid sub-paths will throw descriptive errors (compile & run-time), ensuring only valid paths are modified.
### 3. Updated `.update()` Method
#### Purpose
The existing `.update` and `.updates` methods are deprecated and will be removed in version 2.0.0. `.update` could only update the last LocatorSchema in the chain and `.updates` relied on index-based updates, which posed maintainability challenges, especially when renaming `LocatorSchemaPath` strings. The new `.update` method leverages valid `subPaths` of `LocatorSchemaPath` instead of indices, enhancing readability and reducing manual maintenance.
#### New Method Signature
```typescript
.update(
subPath: SubPaths<LocatorSchemaPathType, LocatorSubstring>,
modifiedSchema: Partial<LocatorSchemaWithoutPath>
): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>
```
#### Deprecation of Old Methods
- **Old `.update(updates: Partial<LocatorSchemaWithoutPath>): LocatorSchemaWithMethods`**
- **Old `.updates(indexedUpdates: { [index: number]: Partial<LocatorSchemaWithoutPath> | null }): LocatorSchemaWithMethods`**
These methods are marked as deprecated and will be removed in version 2.0.0.
#### Usage Examples
**Case A: Update the Last `LocatorSchema` in the Chain**
```typescript
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.update("content.region.details.button.edit", {
roleOptions: { name: "new accessibility name" },
})
.getNestedLocator();
```
**Case B: Update a `LocatorSchema` Earlier in the Chain**
```typescript
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.update("content.region.details", {
roleOptions: { name: "new accessibility name" },
})
.getNestedLocator();
```
**Case C: Update Multiple `LocatorSchema` in the Chain**
```typescript
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.update("content", { roleOptions: { name: "new accessibility name" } })
.update("content.region", {
roleOptions: { name: "new accessibility name" },
})
.update("content.region.details", {
roleOptions: { name: "new accessibility name" },
})
.update("content.region.details.button", {
roleOptions: { name: "new accessibility name" },
})
.update("content.region.details.button.edit", {
roleOptions: { name: "new accessibility name" },
})
.getNestedLocator();
```
#### Benefits
- **Enhanced Readability**: Using `LocatorSchemaPath` strings makes the code more intuitive and easier to understand.
- **Reduced Maintenance**: Eliminates the need to manage index-based references, especially when `LocatorSchemaPath` strings are renamed or restructured.
- **Type Safety**: Leverages TypeScript's type system to ensure only valid `subPath` strings are used, enhancing developer experience with accurate Intellisense suggestions.
### 4. Enhanced `getNestedLocator()` Method
#### Purpose
The `getNestedLocator()` method has been updated to utilize valid `subPath`'s of `LocatorSchemaPath` instead of numeric indices when specifying `.nth(n)` occurrences within a locator chain. The old index-based method is deprecated and will be removed in version 2.0.0.
#### New Method Signature
```typescript
getNestedLocator(
subPathIndices?: { [K in SubPaths<LocatorSchemaPathType, LocatorSubstring>]: number | null }
): Promise<Locator>
```
#### Deprecation of Old Method
- **Old `getNestedLocator(indices?: { [key: number]: number | null }): Promise<Locator>`**
This method is marked as deprecated and will be removed in version 2.0.0.
#### Usage Examples
**Old Usage (Deprecated):**
```typescript
const saveBtn = await profile.getNestedLocator(
"content.region.details.button.save",
{ 4: 2 }
);
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.getNestedLocator({ 2: index });
```
**New Usage:**
```typescript
const saveBtn = await profile.getNestedLocator(
"content.region.details.button.save",
{
"content.region.details.button.save": 2,
}
);
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.getNestedLocator({ "content.region.details": index });
```
#### Benefits
- **Improved Readability**: SubPath-based indexing is more intuitive and aligns with the hierarchical nature of locator paths.
- **Enhanced Maintainability**: Reduces confusion and manual updates when `LocatorSchemaPath` strings are modified.
- **Type Safety and Intellisense**: TypeScript provides accurate suggestions for valid `subPath` keys, enhancing the developer experience and reducing errors.
### 5. Export of `LocatorSchemaWithoutPath`
#### Purpose
The `LocatorSchemaWithoutPath` type is now exported through `index.ts`, enabling full or partial reuse of `LocatorSchema` definitions across different `addSchema` calls within the same or different `initLocatorSchemas` functions.
#### Usage Example
```typescript
import { GetByMethod, LocatorSchemaWithoutPath } from "pomwright";
import { missingInputError } from "@common/page-components/errors.locatorSchema.ts";
export type LocatorSchemaPath =
| "body"
| "body.main"
| "body.main.section"
| "body.main.section@products"
| "body.main.section@userInfo"
| "body.main.section@userInfo.input@email"
| "body.main.section@userInfo.inputError"
| "body.main.section@deliveryInfo";
export function initLocatorSchemas(
locators: GetLocatorBase<LocatorSchemaPath>
) {
locators.addSchema("body", {
locator: "body",
locatorMethod: GetByMethod.locator,
});
locators.addSchema("body.main", {
locator: "main",
locatorMethod: GetByMethod.locator,
});
const region: LocatorSchemaWithoutPath = {
role: "region",
locatorMethod: GetByMethod.role,
};
locators.addSchema("body.main.section", {
...region,
});
locators.addSchema("body.main.section@products", {
...region,
roleOptions: { name: "Products" },
});
locators.addSchema("body.main.section@userInfo", {
...region,
roleOptions: { name: "Contact Info" },
filter: { hasText: /e-mail/i },
});
locators.addSchema("body.main.section@userInfo.input@email", {
role: "textbox",
roleOptions: { name: "Input your e-mail" },
locatorMethod: GetByMethod.role,
});
locators.addSchema("body.main.section@userInfo.inputError", {
...missingInputError,
});
locators.addSchema("body.main.section@deliveryInfo", {
...region,
roleOptions: { name: "Delivery Info" },
});
}
```
#### Benefits
- **Code Reusability**: Facilitates the reuse of common locator schema fragments across different contexts, reducing redundancy.
- **Modular Definitions**: Encourages a modular approach to defining locators, enhancing organization and scalability.
## Deprecations
### 1. Deprecated `.update` and `.updates` Methods
- **Old `.update(updates: Partial<LocatorSchemaWithoutPath>): LocatorSchemaWithMethods`**
- **Old `.updates(indexedUpdates: { [index: number]: Partial<LocatorSchemaWithoutPath> | null }): LocatorSchemaWithMethods`**
**Reason:**
`.updates` relied on index-based updates, which are prone to errors and require manual maintenance, especially when `LocatorSchemaPath` strings are renamed or restructured. While the old `.update` method could only update the last LocatorSchema in the path. Confusing with multiple methods instead of just one.
**Replacement:**
Use the new `.update(subPath, modifiedSchema)` method, which leverages `subpath`'s of valid `LocatorSchemaPath` strings for more intuitive and maintainable updates.
**Removal Schedule:**
These methods are deprecated and will be removed in version 2.0.0.
### 2. Deprecated Old `getNestedLocator` Method
- **Old `getNestedLocator(indices?: { [key: number]: number | null }): Promise<Locator>`**
**Reason:**
Index-based indexing is less readable and requires manual updates when `LocatorSchemaPath` strings change.
**Replacement:**
Use the updated `getNestedLocator(subPathIndices?: { [K in SubPaths<LocatorSchemaPathType, LocatorSubstring>]: number | null }): Promise<Locator>` method, which utilizes `LocatorSchemaPath` strings for indexing.
**Removal Schedule:**
This method is deprecated and will be removed in version 2.0.0.
## Migration Guide
### Updating `.update` and `.updates` Methods
**Old Usage:**
```typescript
const allCheckboxes = await poc
.getLocatorSchema("main.products.searchControls.filterType.label.checkbox")
.updates({ 3: { locatorOptions: { hasText: /Producer/i } } })
.getNestedLocator();
```
**New Usage:**
```typescript
const allCheckboxes = await poc
.getLocatorSchema("main.products.searchControls.filterType.label.checkbox")
.update("main.products.searchControls.filterType", {
locatorOptions: { hasText: /Producer/i },
})
.getNestedLocator();
```
### Updating `getNestedLocator` Method
**Old Usage (Deprecated):**
```typescript
const saveBtn = await profile.getNestedLocator(
"content.region.details.button.save",
{ 4: 2 }
);
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.getNestedLocator({ 2: index });
```
**New Usage:**
```typescript
const saveBtn = await profile.getNestedLocator(
"content.region.details.button.save",
{
"content.region.details.button.save": 2,
}
);
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.getNestedLocator({ "content.region.details": index });
```
### Utilizing `LocatorSchemaPath` Instead of Indices
Transition from index-based to `LocatorSchemaPath`-based indexing to improve code readability and maintainability.
**Old Example:**
```typescript
const allCheckboxes = await poc
.getLocatorSchema("main.form.item.checkbox")
.updates({ 3: { locatorOptions: { hasText: /Producer/i } } })
.getNestedLocator();
```
**New Example:**
```typescript
const allCheckboxes = await poc
.getLocatorSchema("main.form.item.checkbox")
.update("main.form.item", { locatorOptions: { hasText: /Producer/i } })
.getNestedLocator();
```
## Example in Context
### Defining a LocatorSchema with `filter` and Using `.addFilter()`
```typescript
// Defining LocatorSchemas
this.locators.addSchema("body.main.section@userInfo", {
role: "region",
roleOptions: { name: "Contact Info" },
filter: { hasText: /e-mail/i },
locatorMethod: GetByMethod.role,
});
// Dynamically adding additional filters using `.addFilter()`
const specificSection = await poc
.getLocatorSchema("body.main.section@userInfo")
.addFilter("body.main.section@userInfo", { hasText: "Additional Services" })
.getNestedLocator();
```
### Updating LocatorSchemas with the New `.update()` Method
```typescript
const editBtn = await profile
.getLocatorSchema("content.region.details.button.edit")
.update("content.region.details.button.edit", {
roleOptions: { name: "new accessibility name" },
})
.getNestedLocator();
```
### Reusing LocatorSchemas with `LocatorSchemaWithoutPath`
```typescript
import { GetByMethod, LocatorSchemaWithoutPath } from "pomwright";
import { missingInputError } from "@common/page-components/errors.locatorSchema.ts";
export type LocatorSchemaPath =
| "body"
| "body.main"
| "body.main.section"
| "body.main.section@products"
| "body.main.section@userInfo"
| "body.main.section@userInfo.input@email"
| "body.main.section@userInfo.inputError"
| "body.main.section@deliveryInfo";
export function initLocatorSchemas(
locators: GetLocatorBase<LocatorSchemaPath>
) {
locators.addSchema("body", {
locator: "body",
locatorMethod: GetByMethod.locator,
});
locators.addSchema("body.main", {
locator: "main",
locatorMethod: GetByMethod.locator,
});
const region: LocatorSchemaWithoutPath = {
role: "region",
locatorMethod: GetByMethod.role,
};
locators.addSchema("body.main.section", {
...region,
});
locators.addSchema("body.main.section@products", {
...region,
roleOptions: { name: "Products" },
});
locators.addSchema("body.main.section@userInfo", {
...region,
roleOptions: { name: "Contact Info" },
filter: { hasText: /e-mail/i },
});
locators.addSchema("body.main.section@userInfo.input@email", {
role: "textbox",
roleOptions: { name: "Input your e-mail" },
locatorMethod: GetByMethod.role,
});
locators.addSchema("body.main.section@userInfo.inputError", {
...missingInputError,
});
locators.addSchema("body.main.section@deliveryInfo", {
...region,
roleOptions: { name: "Delivery Info" },
});
}
```
## Notes
- **Filter Application Order:**
The `filter` property in `LocatorSchema` is always applied first, followed by any filters added via `.addFilter()`. This ensures that predefined filters have priority over dynamically added ones.
- **Exclusion of `frameLocator`:**
The `filter` property does not apply to `frameLocator` locators. If you need to filter within frames, use the appropriate Playwright frame methods.
- **Type Safety and Intellisense:**
The new `.update()` and enhanced `getNestedLocator()` methods leverage TypeScript's type system to provide accurate Intellisense suggestions, enhancing developer experience and reducing errors.
## Conclusion
These enhancements to `LocatorSchema` and its associated methods significantly improve the flexibility, readability, and maintainability of locator management within your POMs. By adopting the new `filter` property, `.addFilter()` method, and updated `.update()` & `getNestedLocator()` methods, you can construct more precise and adaptable locators, facilitating robust and scalable test automation.
**Note:**
Ensure to migrate away from the deprecated `.update`, `.updates`, and old `getNestedLocator` methods before upgrading to version 2.0.0 to maintain compatibility and leverage the full benefits of these enhancements.
## 1.1.1
### Patch Changes
- [#29](https://github.com/DyHex/POMWright/pull/29) [`14b9bff`](https://github.com/DyHex/POMWright/commit/14b9bff99ec337a4d8b8940c9904620892faae3a) Thanks [@DyHex](https://github.com/DyHex)! - Exports ExtractFullUrlType, updates devDeps and adds additional keywords
## 1.1.0
### Minor Changes
- [#27](https://github.com/DyHex/POMWright/pull/27) [`ab778b2`](https://github.com/DyHex/POMWright/commit/ab778b268fcc77c03289f24617efa74518dcbe12) Thanks [@DyHex](https://github.com/DyHex)! - **Added optional support for dynamic URL types (`string` and/or `RegExp`) for `baseUrl` and `urlPath` via an options-based approach.**
- **WHAT**: This update allows `baseUrl` and `urlPath` to be defined as either `string` or `RegExp` using `BasePageOptions`. The `fullUrl` is automatically inferred based on the types of `baseUrl` and `urlPath`. If either `baseUrl` or `urlPath` is a `RegExp`, `fullUrl` will also be a `RegExp`.
- **WHY**: This change provides flexibility for handling dynamic URLs, such as those containing variables or patterns. It allows validating URLs that follow a predictable format but may have dynamic values that are not known before navigation.
- **HOW**:
- No changes are required for existing implementations since `string` remains the default type.
- To use `RegExp` for `baseUrl` or `urlPath`, define them explicitly in the POC using `BasePageOptions`, which will automatically infer `fullUrl`.
- **Note**: POCs using `RegExp` for `baseUrl` or `urlPath` cannot use `page.goto(fullUrl)` since it requires a `string`. Instead, methods like `page.waitForURL()`, which accept `RegExp`, can be used to validate navigation. This feature is ideal for scenarios where URL values are dynamic and can only be validated by format.
# Examples
## Example: Abstract Base Class extending BasePage without BasePageOptions (default, same as prior versions)
```ts
import { type Page, type TestInfo } from "@playwright/test";
import { BasePage, PlaywrightReportLogger } from "pomwright";
// import helper methods / classes etc, here... (To be used in the Base POC)
export default abstract class Base<
LocatorSchemaPathType extends string
> extends BasePage<LocatorSchemaPathType> {
// add properties here (available to all POCs extending this abstract Base POC)
constructor(
page: Page,
testInfo: TestInfo,
urlPath: string,
pocName: string,
pwrl: PlaywrightReportLogger
) {
super(page, testInfo, "http://localhost:8080", urlPath, pocName, pwrl);
// initialize properties here (available to all POCs extending this abstract Base POC)
}
// add helper methods here (available to all POCs extending this abstract Base POC)
}
```
## Example: POC extending abstract Base Class without BasePageOptions (default, same as prior versions)
```ts
import { type Page, type TestInfo } from "@playwright/test";
import { PlaywrightReportLogger } from "pomwright";
import Base from "../base/base.page";
import {
type LocatorSchemaPath,
initLocatorSchemas,
} from "./testPage.locatorSchema";
export default class TestPage extends Base<LocatorSchemaPath> {
constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
super(page, testInfo, "/", TestPage.name, pwrl);
}
protected initLocatorSchemas() {
initLocatorSchemas(this.locators);
}
// add your helper methods here...
}
```
## Example: Abstract Base Class extending BasePage with BasePageOptions, allows urlPath type as string xOR RegExp
```ts
import { type Page, type TestInfo } from "@playwright/test";
import {
BasePage,
type BasePageOptions,
type ExtractUrlPathType,
PlaywrightReportLogger,
} from "pomwright";
// BaseWithOptions extends BasePage and enforces baseUrlType as string
export default abstract class BaseWithOptions<
LocatorSchemaPathType extends string,
Options extends BasePageOptions = {
urlOptions: { baseUrlType: string; urlPathType: string };
}
> extends BasePage<
LocatorSchemaPathType,
{
urlOptions: {
baseUrlType: string;
urlPathType: ExtractUrlPathType<Options>;
};
}
> {
constructor(
page: Page,
testInfo: TestInfo,
urlPath: ExtractUrlPathType<{
urlOptions: { urlPathType: ExtractUrlPathType<Options> };
}>, // Ensure the correct type for urlPath
pocName: string,
pwrl: PlaywrightReportLogger
) {
// Pass baseUrl as a string and let urlPath be flexible
super(page, testInfo, "http://localhost:8080", urlPath, pocName, pwrl);
// Initialize additional properties if needed
}
// Add any helper methods here, if needed
}
```
## Example: POC extending abstract Base Class with BasePageOptions, but uses defaults (type string)
```ts
import {
type LocatorSchemaPath,
initLocatorSchemas,
} from "@page-object-models/testApp/without-options/pages/testPage.locatorSchema"; // same page & same locator schema as above
import { type Page, type TestInfo } from "@playwright/test";
import { PlaywrightReportLogger } from "pomwright";
import BaseWithOptions from "../base/baseWithOptions.page";
// Note, if BasePageOptions aren't specified, default options are used
export default class TestPage extends BaseWithOptions<LocatorSchemaPath> {
constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
super(page, testInfo, "/", TestPage.name, pwrl);
}
protected initLocatorSchemas() {
initLocatorSchemas(this.locators);
}
// add your helper methods here...
}
```
## Example: POC extending abstract Base Class with BasePageOptions, and defines urlPath type as RegExp
```ts
import { test } from "@fixtures/withOptions";
import BaseWithOptions from "@page-object-models/testApp/with-options/base/baseWithOptions.page";
import { type Page, type TestInfo, expect } from "@playwright/test";
import { PlaywrightReportLogger } from "pomwright";
import {
type LocatorSchemaPath,
initLocatorSchemas,
} from "./color.locatorSchema";
// By providing the urlOptions, the urlPath property now has RegExp type instead of string type (default) for this POC
export default class Color extends BaseWithOptions<
LocatorSchemaPath,
{ urlOptions: { urlPathType: RegExp } }
> {
constructor(page: Page, testInfo: TestInfo, pwrl: PlaywrightReportLogger) {
/**
* Matches "/testpath/randomcolor/" followed by a valid 3 or 6-character hex color code.
*/
const urlPathRegex = /\/testpath\/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
super(page, testInfo, urlPathRegex, Color.name, pwrl);
}
protected initLocatorSchemas() {
initLocatorSchemas(this.locators);
}
async expectThisPage() {
await test.step("Expect color page", async () => {
await this.page.waitForURL(this.fullUrl);
const heading = await this.getNestedLocator("body.heading");
await heading.waitFor({ state: "visible" });
});
}
// add your helper methods here...
}
```
# Summary of Changes
- **Dynamic URL Support**: You can now define `baseUrl` and `urlPath` as `RegExp` for dynamic URL handling.
- **Backward Compatibility**: No changes are required for existing implementations using `string`.
- **Restructuring of tests**: Unit tests moved from ./src to ./test, integration tests moved from ./test to ./intTest
- **New unit tests**: To cover optional-dynamic-url-types (string xOR RegExp)
- **New integration tests with Playwright/test**: To cover optional-dynamic-url-types (string xOR RegExp)
- **peerDependencies change**: Bumped minimum Playwright/test version from 1.39.0 to 1.41.0 as everything below 1.41.0 is deprecated. Also excluded v. 2.x.x as they have known bugs for chaining of locators. Limited max version to <2.0.0
Changes have additionally been tested with two seperate playwright/test projects (130+ E2E tests) without issues, and against the latest Playwright/test versions.
## 1.0.2
### Patch Changes
- [#25](https://github.com/DyHex/POMWright/pull/25) [`993b0ad`](https://github.com/DyHex/POMWright/commit/993b0adc0f437c2c30b436ef6583a59811e0a6a5) Thanks [@DyHex](https://github.com/DyHex)! - # Change
buildNestedLocator will no longer attempt to auto-scroll to the final nested locator
Was done previously in an attempt to improve test recordings, but it sometimes causes tearing in screenshots and isn't ideal when using nested locators for visual regression tests.
## Playwright/test compatibility
Tested with the following Playwright/test versions:
- 1.43.1
- 1.43.0
- 1.42.1
- 1.42.0 (not recommended)
- 1.41.2
- 1.41.1
- 1.41.0
- 1.40.1
- 1.40.0
- 1.39.0
## 1.0.1
### Patch Changes
- [#23](https://github.com/DyHex/POMWright/pull/23) [`0cfc19f`](https://github.com/DyHex/POMWright/commit/0cfc19f057575365853f9df41bbd661bf45172e2) Thanks [@DyHex](https://github.com/DyHex)! - # Continuous testing & bug fixes
## Bug fixes
- getLocatorBase.applyUpdate() now correctly updates the LocatorSchemaWithMethod and maintains a circular ref. for the entry representing itself in schemasMap
- getLocatorBase.applyUpdates() now correctly updates the LocatorSchemaWithMethod and maintains a circular ref. for the entry representing itself in schemasMap while updating other LocatorSchema in SchemasMap directly.
- getLocatorBase.deepMerge() now correctly validates valid nested properties of LocatorSchema
## Continuous testing
- Build workflow now runs unit tests (vitest)
- New shell script enabling testing new packages before release
- New test workflow for POMWright integration tests (Playwright/test)
- 52 new unit tests, more to come..
- 4 new integration tests, more to come..
New release has also been tested with a seperate Playwright/test project leveraging POMWright (~100 E2E tests)
## Playwright/test compatibility
Tested with the following Playwright/test versions:
- 1.43.1
- 1.43.0
- 1.42.1
- 1.42.0 (not recommended)
- 1.41.2
- 1.41.1
- 1.41.0
- 1.40.1
- 1.40.0
- 1.39.0
## 1.0.0
### Major Changes
- 130784f: BREAKING: The following index.ts exports have been renamed:
- "POMWright" changed to "BasePage"
- "POMWrightTestFixture" changed to "test"
- "POMWrightLogger" changed to "PlaywrightReportLogger"
- "POMWrightGetLocatorBase" changed to "GetLocatorBase"
- "POMWrightApi" changed to "BaseApi"
Documentation updated
README updated
## 0.0.9
### Patch Changes
- 7e8b7d1: removes an abstract method from POMWright/BasePage which should have been removed previously
## 0.0.8
### Patch Changes
- 0d4924e: adds additional inforamtion to package.json and shields in readme
## 0.0.7
### Patch Changes
- 5b7ed8a: Update README
## 0.0.6
### Patch Changes
- 8c2af7d: fix: ensure base fixture log follows playwright's api
## 0.0.5
### Patch Changes
- 0c96ab7: Add Biome for linting and formatting
- 0c96ab7: Move indices with default value to the end of arguments for buildNestedLocator
## 0.0.4
### Patch Changes
- f2fea3b: add codeowners
## 0.0.3
### Patch Changes
- fa2a954: adds release script to package.json
## 0.0.2
### Patch Changes
- 1e5433a: Adds changeset to repository