diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ece2d9..9dde268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,16 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how :pencil: - chore :microscope: - experimental +## [3.2.0] +- :rocket: Added capability to provide _defaultResolver_ to define default logic to identify element +```typescript +class App { + defaultResolver({ alias }: { alias: string }) { + return ({ parent }: { parent: Locator }) => parent.getByText(alias); + } +} +``` + ## [3.1.0] - :rocket: updated playwright to 1.53.0 - :rocket: added support of `locator.describe()` to log alias and corresponding locator diff --git a/README.md b/README.md index cc4a41b..6c5e3de 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ qavajs implementation for playwright test runner ## Installation -``` -npm install @qavajs/playwright` +```bash +npm install @qavajs/playwright ``` ## Configuration @@ -38,13 +38,21 @@ export default defineConfig({ ## Development and testing Install dependencies -`npm install` +```bash +npm install +``` Install playwright browsers -`install:browsers` +```bash +install:browsers +``` Build lib -`npm run build` +```bash +npm run build +``` Execute e2e browser tests -`npm run test:e2e` +```bash +npm run test:e2e +``` diff --git a/package-lock.json b/package-lock.json index 2255502..b707138 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,22 @@ { "name": "@qavajs/playwright", - "version": "3.1.0", + "version": "3.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@qavajs/playwright", - "version": "3.1.0", + "version": "3.2.0", "license": "MIT", "dependencies": { - "@playwright/test": "^1.53.0", + "@playwright/test": "^1.54.1", "@qavajs/memory": "^1.10.2", "@qavajs/playwright-runner-adapter": "^1.4.3" }, "devDependencies": { "@types/express": "^5.0.3", - "@types/node": "^24.0.1", - "electron": "^36.4.0", + "@types/node": "^24.1.0", + "electron": "^37.2.4", "express": "^5.1.0", "ts-node": "^10.9.2", "typescript": "^5.8.3" @@ -561,12 +561,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0.tgz", - "integrity": "sha512-15hjKreZDcp7t6TL/7jkAo6Df5STZN09jGiv5dbP9A6vMVncXRqE7/B2SncsyOwrkZRBH2i6/TPOL8BVmm3c7w==", + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.1.tgz", + "integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.53.0" + "playwright": "1.54.1" }, "bin": { "playwright": "cli.js" @@ -754,9 +754,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "24.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz", - "integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==", + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", + "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", "dev": true, "license": "MIT", "dependencies": { @@ -1354,9 +1354,9 @@ "license": "MIT" }, "node_modules/electron": { - "version": "36.4.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-36.4.0.tgz", - "integrity": "sha512-LLOOZEuW5oqvnjC7HBQhIqjIIJAZCIFjQxltQGLfEC7XFsBoZgQ3u3iFj+Kzw68Xj97u1n57Jdt7P98qLvUibQ==", + "version": "37.2.4", + "resolved": "https://registry.npmjs.org/electron/-/electron-37.2.4.tgz", + "integrity": "sha512-F1WDDvY60TpFwGyW+evNB5q0Em8PamcDTVIKB2NaiaKEbNC2Fabn8Wyxy5g+Anirr1K40eKGjfSJhWEUbI1TOw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2605,12 +2605,12 @@ "license": "ISC" }, "node_modules/playwright": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0.tgz", - "integrity": "sha512-ghGNnIEYZC4E+YtclRn4/p6oYbdPiASELBIYkBXfaTVKreQUYbMUYQDwS12a8F0/HtIjr/CkGjtwABeFPGcS4Q==", + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz", + "integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.53.0" + "playwright-core": "1.54.1" }, "bin": { "playwright": "cli.js" @@ -2623,9 +2623,9 @@ } }, "node_modules/playwright-core": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0.tgz", - "integrity": "sha512-mGLg8m0pm4+mmtB7M89Xw/GSqoNC+twivl8ITteqvAndachozYe2ZA7srU6uleV1vEdAHYqjq+SV8SNxRRFYBw==", + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz", + "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" diff --git a/package.json b/package.json index 7f7d45d..ab14d83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@qavajs/playwright", - "version": "3.1.0", + "version": "3.2.0", "description": "steps to interact with playwright", "main": "./index.js", "scripts": { @@ -26,14 +26,14 @@ "homepage": "https://github.com/qavajs/playwright#readme", "devDependencies": { "@types/express": "^5.0.3", - "@types/node": "^24.0.1", - "electron": "^36.4.0", + "@types/node": "^24.1.0", + "electron": "^37.2.4", "express": "^5.1.0", "ts-node": "^10.9.2", "typescript": "^5.8.3" }, "dependencies": { - "@playwright/test": "^1.53.0", + "@playwright/test": "^1.54.1", "@qavajs/playwright-runner-adapter": "^1.4.3", "@qavajs/memory": "^1.10.2" } diff --git a/src/pageObject.ts b/src/pageObject.ts index c770a2c..5a01298 100644 --- a/src/pageObject.ts +++ b/src/pageObject.ts @@ -98,11 +98,15 @@ export function query(root: any, path: string) { for (const element of elements) { const groups = element.match(/^(?.+?)(?:\((?.+)\))?$/)?.groups as { alias: string, argument: string }; const alias = groups.alias.replace(/\s/g, ''); - if (!currentComponent) { - throw new Error(`Alias '${currentAlias}' is not a component`); + let currentElement = currentComponent[alias]; + if (!currentElement && (!currentComponent.defaultResolver || typeof currentComponent.defaultResolver !== 'function')) { + throw new Error(`Alias '${alias}' has not been found in '${currentAlias}'`); + } + if (!currentElement && currentComponent.defaultResolver) { + currentElement = {}; + currentElement.selector = currentComponent.defaultResolver({ alias: groups.alias, argument: groups.argument }); + currentElement.type = 'native'; } - const currentElement = currentComponent[alias]; - if (!currentElement) throw new Error(`Alias '${alias}' has not been found in '${currentAlias}'`); currentAlias = groups.alias; currentComponent = currentElement.component ? new currentElement.component() : null; diff --git a/test-e2e/features/pageObject.feature b/test-e2e/features/pageObject.feature index cf3ba88..50a2882 100644 --- a/test-e2e/features/pageObject.feature +++ b/test-e2e/features/pageObject.feature @@ -26,4 +26,7 @@ Feature: page object Then I expect text of 'Simple Text Element ({$selector})' to be equal 'text value' Scenario: top level component - Then I expect text of 'Top Level Component > Text Element' to be equal 'text value' \ No newline at end of file + Then I expect text of 'Top Level Component > Text Element' to be equal 'text value' + + Scenario: default resolver + Then I expect text of 'third value' to be equal 'third value' \ No newline at end of file diff --git a/test-e2e/page_object/index.ts b/test-e2e/page_object/index.ts index 5db8db6..745dfcc 100644 --- a/test-e2e/page_object/index.ts +++ b/test-e2e/page_object/index.ts @@ -1,4 +1,5 @@ import { locator } from '../../src/pageObject'; +import { Locator } from '@playwright/test'; export default class App { SimpleTextElement = locator('#textValue'); @@ -69,6 +70,10 @@ export default class App { BodyComponentNative = locator.native(({ page }) => page.locator('body')).as(BodyComponent); TopLevelComponent = locator.as(BodyComponent); + + defaultResolver({ alias }: { alias: string }) { + return ({ parent }: { parent: Locator }) => parent.getByText(alias); + } } class BodyComponent {