Skip to content

Commit e2e9fe5

Browse files
added locator.as method to define top level components (like pages) (#142)
* added `locator.as` method to define top level components (like pages)
1 parent 3014577 commit e2e9fe5

File tree

6 files changed

+72
-21
lines changed

6 files changed

+72
-21
lines changed

CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,22 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
1414

1515
:microscope: - experimental
1616

17+
## [2.2.0]
18+
- :rocket: added `locator.as` method to define top level components (like pages)
19+
```typescript
20+
export class App {
21+
LoginPage = locator.as(LoginPage);
22+
}
23+
24+
class LoginPage {
25+
username = locator('#username');
26+
password = locator('#password');
27+
}
28+
```
29+
1730
## [2.1.0]
1831
- :rocket: added grouping by steps in traces
19-
- :beetle: added `FrameLocator` as possible return type for `locator.native`
32+
- :rocket: added `FrameLocator` as possible return type for `locator.native`
2033

2134
## [2.0.0]
2235
- :pencil: added memory processor to playwrightLocator parameter type

package-lock.json

Lines changed: 33 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@qavajs/steps-playwright",
3-
"version": "2.1.0",
3+
"version": "2.2.0",
44
"description": "steps to interact with playwright",
55
"main": "./index.js",
66
"scripts": {
@@ -41,7 +41,7 @@
4141
"ts-node": "^10.9.2",
4242
"typescript": "^5.7.2",
4343
"vitest": "^2.1.8",
44-
"@qavajs/validation": "^0.10.0"
44+
"@qavajs/validation": "^1.0.0"
4545
},
4646
"dependencies": {
4747
"@playwright/test": "^1.49.1"

src/pageObject.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import {type Browser, type BrowserContext, type Page, Locator, FrameLocator} from '@playwright/test';
22

3+
type SelectorDefinition = string | ((argument: string) => string) | ((argument: any) => any) | null;
4+
35
export class Selector {
4-
selector: string | ((argument: string) => string) | ((argument: any) => any);
6+
selector: SelectorDefinition;
57
component!: Function;
68
type: string = 'simple';
79

8-
constructor(selector: string | ((argument: string) => string) | ((argument: any) => any), type?: string) {
10+
constructor(selector: SelectorDefinition, type?: string) {
911
this.selector = selector;
1012
if (type) {
1113
this.type = type;
@@ -48,6 +50,12 @@ export interface LocatorDefinition {
4850
* @param {(argument: string) => string} selector - selector function
4951
*/
5052
native: (selector: (params: NativeSelectorParams) => Locator | FrameLocator) => Selector;
53+
54+
/**
55+
* Define component
56+
* @param { new () => void } component
57+
*/
58+
as: (component: new () => void) => Selector;
5159
}
5260

5361
export const locator: LocatorDefinition = function locator(selector: any): Selector {
@@ -62,6 +70,12 @@ locator.native = function(selector: (params: NativeSelectorParams) => Locator |
6270
return new Selector(selector, 'native');
6371
}
6472

73+
locator.as = function (component: new () => void) {
74+
const selector = new Selector(null);
75+
selector.component = component;
76+
return selector;
77+
}
78+
6579
export class ChainItem {
6680
alias: string;
6781
argument?: string;
@@ -80,7 +94,7 @@ export function query(root: any, path: string) {
8094
const elements = path.split(/\s*>\s*/);
8195
const tokens = [];
8296
let currentComponent = new root();
83-
let currentAlias = 'root';
97+
let currentAlias = 'page object root';
8498
for (const element of elements) {
8599
const groups = element.match(/^(?<alias>.+?)(?:\((?<argument>.+)\))?$/)?.groups as { alias: string, argument: string };
86100
const alias = groups.alias.replace(/\s/g, '');
@@ -106,7 +120,7 @@ export function element(this: any, path: string): Locator {
106120
let current = page as unknown as Locator;
107121
for (const item of chain) {
108122
switch (item.type) {
109-
case 'simple': current = current.locator(item.selector); break;
123+
case 'simple': current = item.selector ? current.locator(item.selector) : current; break;
110124
case 'template': current = current.locator(item.selector(item.argument)); break;
111125
case 'native': current = item.selector({
112126
driver: this.playwright.driver,

test-e2e/features/pageObject.feature

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ Feature: page object
2121
Scenario: template with memory
2222
When I save '#textValue' to memory as 'selector'
2323
Then I expect text of 'Simple Text Element Template ({$selector})' to be equal 'text value'
24+
25+
Scenario: top level component
26+
Then I expect text of 'Top Level Component > Text Element' to be equal 'text value'

test-e2e/page_object/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ export default class App {
7777
//JS Selector
7878
SimpleTextElementByJS = locator('js=document.querySelectorAll("#textValue")');
7979
SimpleTextListItemsByJS = locator('js=document.querySelectorAll("#textValueList li")');
80+
81+
TopLevelComponent = locator.as(BodyComponent);
8082
}
8183

8284
class BodyComponent {

0 commit comments

Comments
 (0)