Skip to content

Commit

Permalink
feat: new window
Browse files Browse the repository at this point in the history
  • Loading branch information
iamkenos committed Oct 2, 2023
1 parent aefa263 commit e7e574a
Show file tree
Hide file tree
Showing 41 changed files with 659 additions and 105 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules/
results/
**/snapshots/**/actual
**/snapshots/**/diff
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- check locales support
- parameterize headless and browser options
- fix html reports
- check if expected conditions page and locators prop can be reworked
- config file jsdocs
- see if expect timeouts can be reworked: https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/timeouts.md#disable-timeouts
- move files to src
Expand Down
2 changes: 1 addition & 1 deletion demo/test/features/ii-form-elements/1-input.feature
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Feature: II. Form Elements - Input
Scenario: S05: Input file
When I upload the "fixtures/files/demo.txt" file to the "#input-file" field
Then I expect the "#input-file" field value to contain "demo.txt"
@debug

Scenario: S06: Request interception
When I type on the fields:
| Field | Value |
Expand Down
22 changes: 11 additions & 11 deletions demo/test/features/ii-form-elements/3-checkbox.feature
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Feature: II. Form Elements - Checkbox
Feature: II. Form Elements - Checkbox

# Background:
# Given I am on the "demo" site
# And I click the "II. Form Elements" navigation item
# And I expect the section header "II. Form Elements" to exist
Background:
Given I am on the "demo" site
And I click the "II. Form Elements" navigation item
And I expect the section header "II. Form Elements" to exist

# Scenario: S01: Checkboxes
# When I select the "#input-checkbox-1" check box
# Then I expect the "#input-checkbox-1" check box to be selected
# But I deselect the "#input-checkbox-1" check box
# Then I expect the "#input-checkbox-1" check box to not be selected
# And I expect the "#input-checkbox-2" check box to be selected
Scenario: S01: Checkboxes
When I select the "#input-checkbox-1" check box
Then I expect the "#input-checkbox-1" check box to be selected
But I deselect the "#input-checkbox-1" check box
Then I expect the "#input-checkbox-1" check box to not be selected
And I expect the "#input-checkbox-2" check box to be selected
13 changes: 13 additions & 0 deletions demo/test/features/ii-form-elements/4-radio.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Feature: II. Form Elements - Radio

Background:
Given I am on the "demo" site
And I click the "II. Form Elements" navigation item
And I expect the section header "II. Form Elements" to exist

Scenario: S01: Radio options
When I select the "#input-radio-1" radio button
Then I expect the "#input-radio-1" radio button to be selected
But I select the "#input-radio-2" radio button
Then I expect the "#input-radio-1" radio button to not be selected
And I expect the "#input-radio-2" radio button to be selected
37 changes: 37 additions & 0 deletions demo/test/features/iii-browser-context/4-browser-windows.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Feature: III. Browser Context - Browser windows

Background:
Given I am on the "demo" site
And I click the "III. Browser Context" navigation item
And I expect the section header "III. Browser Context" to exist

Scenario: S01: Open on same window
When I click the "#open-same-window" button
Then I expect the tab count to be 1
And I expect to be on the "iframe" page
But I navigate back from the current page
Then I expect to be on the "demo" site
When I navigate forward from the current page
Then I expect to be back on the "iframe" page

Scenario: S02: Open on new window
When I open the "demo" page's url on a new window
Then I expect the tab count to be more than 1
And I expect the tab count to be less than 3
But I close the last opened window
Then I expect the tab count to not be more than 1
And I expect the tab count to not be less than 1
When I click the "#open-new-window" button
Then I expect to still be on the "demo" page
But I focus on the last opened window
Then I expect to be on the "iframe" page
And I expect the page title to be "Demo Iframe"
And I expect the page title to be the "iframe" page's title
And I expect the url to be the "iframe" page's url
And I expect the "#card-1" element to match the snapshot "iii-browser-context/3-browser-windows/card"
And I expect the viewport to match the snapshot "iii-browser-context/3-browser-windows/viewport"
But I close all other windows
Then I expect the page title to not be "Demo Iframe"
And I expect the page title to not be the "iframe" page's title
And I expect the url to not be the "iframe" page's url
And I expect the page to match the snapshot "iii-browser-context/3-browser-windows/page"
24 changes: 24 additions & 0 deletions demo/test/fixtures/commands/context/add-page-commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as playwright from "@playwright/test";

import {
expect,
given,
locator,
scrollTo,
scrollToBottom,
scrollToTop
} from "@commands/page";
import { Page } from "@generics";

export function addPageCommands(this: playwright.BrowserContext | any, ...args: any) {
const [page] = args;
page[expect.name] = (...args: Parameters<typeof expect>) => expect.call(page, ...args);
page[given.name] = () => given.call(page);
page[locator.name] = (...args: Parameters<typeof locator>) => locator.call(page, ...args);
page[scrollToBottom.name] = (...args: Parameters<typeof scrollToBottom>) => scrollToBottom.call(page, ...args);
page[scrollToTop.name] = (...args: Parameters<typeof scrollToTop>) => scrollToTop.call(page, ...args);
page[scrollTo.name] = (...args: Parameters<typeof scrollTo>) => scrollTo.call(page, ...args);
page.config = this.config;
return page as Page;
}

12 changes: 12 additions & 0 deletions demo/test/fixtures/commands/context/close-last-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as playwright from "@playwright/test";

import { Page } from "@generics";

export async function closeLastPage(this: playwright.BrowserContext) {
const pages = this.pages();
const [page] = pages.slice(-1);
await page.close();

return pages[0] as Page;
}

17 changes: 17 additions & 0 deletions demo/test/fixtures/commands/context/close-other-pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as playwright from "@playwright/test";

import { Page } from "@generics";

export async function closeOtherPages(this: playwright.BrowserContext) {
let pages = this.pages();

while (pages.length > 1) {
const last = pages.slice(-1)[0];

await last.close();
pages = this.pages();
}

return pages[0] as Page;
}

5 changes: 5 additions & 0 deletions demo/test/fixtures/commands/context/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./add-page-commands";
export * from "./close-last-page";
export * from "./close-other-pages";
export * from "./last-page";
export * from "./new-page";
8 changes: 8 additions & 0 deletions demo/test/fixtures/commands/context/last-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { BrowserContext } from "@generics";

export function lastPage(this: BrowserContext) {
const pages = this.pages();
const [page] = pages.slice(-1);
return this.addPageCommands(page);
}

10 changes: 10 additions & 0 deletions demo/test/fixtures/commands/context/new-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as playwright from "@playwright/test";

export async function newPage(this: playwright.BrowserContext | any) {
if (this._ownerPage) throw new Error("Please use browser.newContext()");
const { Page } = require("node_modules/playwright-core/lib/client/page.js");

const page = Page.from((await this._channel.newPage()).page);
return this.addPageCommands(page);
}

15 changes: 10 additions & 5 deletions demo/test/fixtures/commands/locator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as path from "path";

import { Locator as PlaywrightLocator } from "@playwright/test";

import { ExpectedConditionOptions, LocatorConditions } from "@conditions";
import { ExpectedConditionOptions, ExpectedConditions, LocatorConditions } from "@conditions";
import { Page } from "@generics";

export class Locator implements PlaywrightLocator {
Expand Down Expand Up @@ -79,6 +79,11 @@ export class Locator implements PlaywrightLocator {
await this.evaluate((node: HTMLElement) => node.click());
}

async clickUntil(conditions: ExpectedConditions, ...args: Parameters<PlaywrightLocator["click"]>) {
const fn = async() => await this.click(...args);
await this.doUntil({ name: this.clickUntil.name, fn }, conditions);
}

async location() {
// gets element location relative to the top of the document
// see: https://stackoverflow.com/a/51283627/2285470
Expand All @@ -93,10 +98,6 @@ export class Locator implements PlaywrightLocator {
await this.evaluate((node: HTMLElement) => node.scrollIntoView({ behavior: "auto", block: "center", inline: "center" }));
}

then() {
return this.expect();
}

toString() {
return `${(this._locator as any)._selector}`;
}
Expand All @@ -110,6 +111,10 @@ export class Locator implements PlaywrightLocator {
await fileChooser.setFiles(mapped);
}

async doUntil(action: { fn: Function, name: string }, conditions: ExpectedConditions) {
await conditions.setName(action.name).setAction(action.fn).poll();
}

// locator actions ---------------------------------------------------------------------------------------------------

evaluate(...args: Parameters<PlaywrightLocator["evaluate"]>) {
Expand Down
1 change: 0 additions & 1 deletion demo/test/fixtures/commands/page/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ export * from "./locator";
export * from "./scroll-to-bottom";
export * from "./scroll-to-top";
export * from "./scroll-to";
export * from "./then";
5 changes: 0 additions & 5 deletions demo/test/fixtures/commands/page/then.ts

This file was deleted.

1 change: 1 addition & 0 deletions demo/test/fixtures/common/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as string from "./string";
18 changes: 18 additions & 0 deletions demo/test/fixtures/common/utils/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export function isURL(str: string) {
try {
const url = new URL(str);
return ["http:", "https:"].includes(url.protocol);
} catch (e) {
return false;
}
}

export function isJSON(str: string) {
if (typeof str !== "string") return false;
try {
const result = JSON.parse(str);
return result instanceof Array || result instanceof Object;
} catch (e) {
return false;
}
}
13 changes: 13 additions & 0 deletions demo/test/fixtures/conditions/expected-conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export class ExpectedConditions {

private timeout: number;

private action: Function;

private soft: boolean;

constructor(options?: ExpectedConditionOptions) {
Expand Down Expand Up @@ -57,9 +59,20 @@ export class ExpectedConditions {
return this;
}

setAction(action: Function) {
this.action = action;
return this;
}

setName(name: string) {
this.name = name;
return this;
}

async poll() {
try {
await expect.poll(async() => {
this.action !== undefined && await this.action();
await this.evaluateAll();
return this.result.passed;
}, { intervals: [250], timeout: this.timeout }).toBe(true);
Expand Down
7 changes: 6 additions & 1 deletion demo/test/fixtures/conditions/locator/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ExpectedConditionOptions } from "../types";

import { Locator } from "@generics";
import { Locator, LocatorSnapshotOptions } from "@generics";
import { Axis, SizeContext } from "@gherkin";
import { ExpectedConditions } from "../expected-conditions";
import { AttributeContains } from "./attribute-contains";
Expand All @@ -16,6 +16,7 @@ import { DisplayedInViewport } from "./displayed-in-viewport";
import { Enabled } from "./enabled";
import { Exists } from "./exists";
import { Selected } from "./selected";
import { SnapshotMatch } from "./snapshot-match";
import { TextContains } from "./text-contains";
import { TextEquals } from "./text-equals";
import { ValueContains } from "./value-contains";
Expand Down Expand Up @@ -81,6 +82,10 @@ export class LocatorConditions extends ExpectedConditions {
return this.addCondition(new Selected(preferred).setLocator(this.locator));
}

snapshotMatch(filename: string, options?: LocatorSnapshotOptions, preferred?: boolean) {
return this.addCondition(new SnapshotMatch(filename, options, preferred).setLocator(this.locator));
}

textContains(expected: string, preferred?: boolean) {
return this.addCondition(new TextContains(expected, preferred).setLocator(this.locator));
}
Expand Down
14 changes: 14 additions & 0 deletions demo/test/fixtures/conditions/locator/snapshot-match.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { SnapshotMatch as ExpectedCondition } from "@conditions/page/snapshot-match";
import { LocatorSnapshotOptions } from "@generics";

export class SnapshotMatch extends ExpectedCondition {

public constructor(filename: string, options?: LocatorSnapshotOptions, preferred?: boolean) {
super(filename, options, preferred);
}

async evaluate() {
this.page = this.locator.page();
return super.evaluate();
}
}
42 changes: 41 additions & 1 deletion demo/test/fixtures/conditions/page/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import type { ExpectedConditionOptions } from "../types";

import { Page } from "@generics";
import { Page, PageSnapshotOptions } from "@generics";
import { ExpectedConditions } from "../expected-conditions";
import { DomContentLoaded } from "./dom-content-loaded";
import { SnapshotMatch } from "./snapshot-match";
import { TitleContains } from "./title-contains";
import { TitleEquals } from "./title-equals";
import { UrlContains } from "./url-contains";
import { UrlEquals } from "./url-equals";
import { WindowCountEquals } from "./window-count-equals";
import { WindowCountLessThan } from "./window-count-less-than";
import { WindowCountMoreThan } from "./window-count-more-than";

export class PageConditions extends ExpectedConditions {
private readonly page: Page;
Expand All @@ -15,4 +23,36 @@ export class PageConditions extends ExpectedConditions {
domContentLoaded(preferred?: boolean) {
return this.addCondition(new DomContentLoaded(preferred).setPage(this.page));
}

snapshotMatch(filename: string, options?: PageSnapshotOptions, preferred?: boolean) {
return this.addCondition(new SnapshotMatch(filename, options, preferred).setPage(this.page));
}

titleContains(expected: string, preferred?: boolean) {
return this.addCondition(new TitleContains(expected, preferred).setPage(this.page));
}

titleEquals(expected: string, preferred?: boolean) {
return this.addCondition(new TitleEquals(expected, preferred).setPage(this.page));
}

urlContains(expected: string, preferred?: boolean) {
return this.addCondition(new UrlContains(expected, preferred).setPage(this.page));
}

urlEquals(expected: string, preferred?: boolean) {
return this.addCondition(new UrlEquals(expected, preferred).setPage(this.page));
}

windowCountEquals(count:number, preferred?: boolean) {
return this.addCondition(new WindowCountEquals(count, preferred).setPage(this.page));
}

windowCountLessThan(count:number, preferred?: boolean) {
return this.addCondition(new WindowCountLessThan(count, preferred).setPage(this.page));
}

windowCountMoreThan(count:number, preferred?: boolean) {
return this.addCondition(new WindowCountMoreThan(count, preferred).setPage(this.page));
}
}
Loading

0 comments on commit e7e574a

Please sign in to comment.