Skip to content

Commit c0ea85a

Browse files
Merge pull request #1 from qavajs/implementing-features
implemented actions, waits, validation steps
2 parents 3d2bad6 + 19c5954 commit c0ea85a

File tree

10 files changed

+316
-11
lines changed

10 files changed

+316
-11
lines changed

index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1+
require('./lib/types.js');
12
require('./lib/hooks.js');
23
require('./lib/actions.js');
4+
require('./lib/waits.js');
5+
require('./lib/validations.js');

package-lock.json

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

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"ts-jest": "^28.0.5"
2828
},
2929
"dependencies": {
30+
"@playwright/test": "^1.26.1",
3031
"@qavajs/memory": "^1.1.0",
3132
"@qavajs/po-playwright": "^0.0.1",
3233
"@qavajs/validation": "^0.0.2",

src/conditionWait.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Locator } from "playwright";
2+
3+
export const conditionValidations = {
4+
PRESENT: 'present',
5+
// CLICKABLE: 'clickable',
6+
VISIBLE: 'visible',
7+
INVISIBLE: 'invisible',
8+
// ENABLED: 'enabled',
9+
// DISABLED: 'disabled'
10+
}
11+
12+
const notClause = '(not )?';
13+
const toBeClause = 'to (?:be )?';
14+
const validationClause = `(${Object.values(conditionValidations).join('|')})`;
15+
16+
export const conditionWaitExtractRegexp = new RegExp(`^${notClause}${toBeClause}${validationClause}$`);
17+
export const conditionWaitRegexp = new RegExp(`(${notClause}${toBeClause}${validationClause})`);
18+
19+
const waits = {
20+
[conditionValidations.PRESENT]: (
21+
element: Locator,
22+
reverse: boolean,
23+
timeout: number,
24+
timeoutMsg: string
25+
) => element.waitFor({state: reverse ? 'detached' : 'attached', timeout}),
26+
[conditionValidations.VISIBLE]: (
27+
element: Locator,
28+
reverse: boolean,
29+
timeout: number,
30+
timeoutMsg: string
31+
) => element.waitFor({state: reverse ? 'hidden' : 'visible', timeout}),
32+
[conditionValidations.INVISIBLE]: (
33+
element: Locator,
34+
reverse: boolean,
35+
timeout: number,
36+
timeoutMsg: string
37+
) => element.waitFor({state: reverse ? 'visible' : 'hidden', timeout})
38+
}
39+
/**
40+
* Wait for condition
41+
* @param {Locator} element - element
42+
* @param {string} validationType - validation to perform
43+
* @param {number} [timeout] - timeout to wait
44+
* @param {boolean} [reverse] - negate flag
45+
* @return {Promise<void>}
46+
*/
47+
export async function conditionWait(
48+
element: Locator,
49+
validationType: string,
50+
timeout: number = 10000,
51+
reverse: boolean = false
52+
) {
53+
const timeoutMsg: string = `Element is${reverse ? '' : ' not'} ${validationType}`;
54+
const waitFn = waits[validationType];
55+
await waitFn(element, reverse, timeout, timeoutMsg);
56+
}

src/hooks.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { After, AfterStep, Before, BeforeStep, Status } from '@cucumber/cucumber';
22
import defaultTimeouts from './defaultTimeouts';
3-
import { chromium, Browser, BrowserContext, Page } from 'playwright';
3+
import { chromium, firefox, webkit, Browser, BrowserContext, Page, BrowserType } from 'playwright';
44
import { po } from '@qavajs/po-playwright';
55
import { ScreenshotEvent } from './screenshotEvent';
6+
const browsers: any = { chromium, firefox, webkit };
67

78
declare global {
89
var browser: Browser;
@@ -18,11 +19,12 @@ Before(async function () {
1819
defaultTimeouts,
1920
...driverConfig.timeout
2021
}
21-
global.browser = await chromium.launch();
22+
const browserName: string = driverConfig?.capabilities?.browserName ?? 'chromium';
23+
global.browser = await (browsers[browserName] as BrowserType).launch(driverConfig.capabilities);
2224
global.context = await browser.newContext();
2325
global.page = await browser.newPage();
2426
global.driver = global.browser;
25-
po.init(browser, { timeout: driverConfig.timeout.present });
27+
po.init(page, { timeout: driverConfig.timeout.present });
2628
po.register(config.pageObject);
2729
});
2830

src/transformers.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { conditionWait, conditionWaitExtractRegexp } from './conditionWait';
2+
import { valueWait, valueWaitExtractRegexp } from './valueWait';
13
import { po } from '@qavajs/po-playwright';
24
import memory from '@qavajs/memory';
35
import { Locator } from 'playwright';
@@ -9,3 +11,21 @@ export function getValue(alias: string): any {
911
export async function getElement(alias: string): Promise<Locator> {
1012
return po.getElement(await memory.getValue(alias))
1113
}
14+
15+
export function getConditionWait(condition: string): Function {
16+
const match = condition.match(conditionWaitExtractRegexp) as RegExpMatchArray;
17+
if (!match) throw new Error(`${condition} wait is not implemented`);
18+
const [ _, reverse, validation ] = match;
19+
return async function (element: Locator, timeout: number) {
20+
await conditionWait(element, validation, timeout, Boolean(reverse))
21+
}
22+
}
23+
24+
export function getValueWait(condition: string): Function {
25+
const match = condition.match(valueWaitExtractRegexp) as RegExpMatchArray;
26+
if (!match) throw new Error(`${condition} wait is not implemented`);
27+
const [ _, reverse, validation ] = match;
28+
return async function (valueFn: Function, expected: any, timeout: number) {
29+
await valueWait(valueFn, expected, validation, timeout, Boolean(reverse))
30+
}
31+
}

src/types.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { defineParameterType } from '@cucumber/cucumber';
2+
3+
defineParameterType({
4+
name: 'playwrightValidation',
5+
regexp: /((?:is |do |does |to )?(not |to not )?(?:to )?(?:be )?(equal|strictly equal|deeply equal|have member|match|contain|above|below|greater than|less than|have type)(?:s|es)?)/,
6+
transformer: p => p,
7+
useForSnippets: false
8+
});
9+
10+
defineParameterType({
11+
name: 'playwrightValueWait',
12+
regexp: /((not )?to (?:be )?(equal|contain|above|below))/,
13+
transformer: p => p,
14+
useForSnippets: false
15+
});
16+
17+
defineParameterType({
18+
name: 'playwrightConditionWait',
19+
regexp: /((not )?to (?:be )?(present|clickable|visible|invisible|enabled|disabled))/,
20+
transformer: p => p,
21+
useForSnippets: false
22+
});

src/validations.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Then } from '@cucumber/cucumber';
2+
import { getValue, getElement, getConditionWait } from './transformers';
3+
import { getValidation } from '@qavajs/validation';
4+
5+
/**
6+
* Verify element condition
7+
* @param {string} alias - element to wait condition
8+
* @param {string} condition - wait condition
9+
* @example I expect 'Header' to be visible
10+
* @example I expect 'Loading' not to be present
11+
* @example I expect 'Search Bar > Submit Button' to be clickable
12+
*/
13+
Then('I expect {string} {playwrightConditionWait}', async function (alias: string, condition: string) {
14+
const element = await getElement(alias);
15+
const wait = getConditionWait(condition);
16+
await wait(element, config.browser.timeout.page);
17+
});
18+
19+
/**
20+
* Verify that text of element satisfies condition
21+
* @param {string} alias - element to get text
22+
* @param {string} validationType - validation
23+
* @param {string} value - expected result
24+
* @example I expect text of '#1 of Search Results' equals to 'google'
25+
* @example I expect text of '#2 of Search Results' does not contain 'yandex'
26+
*/
27+
Then(
28+
'I expect text of {string} {playwrightValidation} {string}',
29+
async function (alias: string, validationType: string, value: any) {
30+
const expectedValue = await getValue(value);
31+
const element = await getElement(alias);
32+
const validation = getValidation(validationType);
33+
const elementText: string = await element.innerText();
34+
validation(elementText, expectedValue);
35+
}
36+
);

src/valueWait.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { expect } from '@playwright/test';
2+
export const valueValidations = {
3+
EQUAL: 'equal',
4+
CONTAIN: 'contain',
5+
ABOVE: 'above',
6+
BELOW: 'below'
7+
}
8+
9+
const notClause = '(not )?';
10+
const toBeClause = 'to (?:be )?';
11+
const validationClause = `(${Object.values(valueValidations).join('|')})`;
12+
13+
export const valueWaitExtractRegexp = new RegExp(`^${notClause}${toBeClause}${validationClause}$`);
14+
export const valueWaitRegexp = new RegExp(`(${notClause}${toBeClause}${validationClause})`);
15+
16+
const waits = {
17+
[valueValidations.EQUAL]: async (poll: any, expected: any) => poll.toBe(expected),
18+
[valueValidations.CONTAIN]: async (poll: any, expected: any) => poll.toContain(expected),
19+
[valueValidations.ABOVE]: async (poll: any, expected: any) => poll.toBeGreaterThan(expected),
20+
[valueValidations.BELOW]: async (poll: any, expected: any) => poll.toBeLessThan(expected)
21+
}
22+
23+
/**
24+
* Wait for condition
25+
* @param {any} valueFn - function to return value
26+
* @param {any} expected - expected value
27+
* @param {string} validationType - validation to perform
28+
* @param {number} [timeout] - timeout to wait
29+
* @param {boolean} [reverse] - negate flag
30+
* @return {Promise<void>}
31+
*/
32+
export async function valueWait(
33+
valueFn: Function,
34+
expected: any,
35+
validationType: string,
36+
timeout: number = 10000,
37+
reverse: boolean
38+
) {
39+
const message: string = `Value is${reverse ? '' : ' not'} ${validationType} ${expected}`;
40+
const options = { timeout, message };
41+
const waitFn = waits[validationType];
42+
const poll = reverse
43+
? expect.poll(() => valueFn(), options).not
44+
: expect.poll(() => valueFn(), options);
45+
await waitFn(poll, expected);
46+
}

0 commit comments

Comments
 (0)