Skip to content

Commit

Permalink
Advancing in page objects
Browse files Browse the repository at this point in the history
  • Loading branch information
itaiag committed Feb 4, 2024
1 parent 4a8fcf4 commit c6760f2
Show file tree
Hide file tree
Showing 19 changed files with 530 additions and 143 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,5 @@ dist
/playwright-report/
/blob-report/
/playwright/.cache/
/*-snapshots/
*.png
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"cs50.vscode-presentation-mode"
]
}
171 changes: 164 additions & 7 deletions infra/po/pages.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,137 @@
import { Locator, Page } from "@playwright/test";

export abstract class AbstractPage {
protected page: Page;
export abstract class BaseComponent {
constructor(protected page: Page, protected rootLocator?: Locator) {

}

protected searcher() : Page | Locator {
if (this.rootLocator) {
return this.rootLocator;
} else {
return this.page;
}
}
}

export abstract class BasePage extends BaseComponent{
constructor(page: Page) {
super(page);
}
}

export class MainMenuComponent extends BaseComponent {
private readonly workPackages: Locator;

constructor(page: Page) {
this.page = page;
super(page);
this.workPackages = page.locator("#main-menu-work-packages");
}

async clickOnWorkPackagesItm(): Promise<AllOpenWpPage> {
await this.workPackages.click();
return new AllOpenWpPage(this.page);
}
}

export class OverviewPage extends AbstractPage {
export class OverviewPage extends BasePage {
public readonly mainMenu: MainMenuComponent;

constructor(page: Page) {
super(page);
this.mainMenu = new MainMenuComponent(page);
}

}

export class NewTaskPage extends BasePage {
private readonly subjectTb: Locator;
private readonly estimatedTimeTb: Locator;
private readonly saveBtn: Locator;

constructor(page: Page) {
super(page);
this.subjectTb = page.getByLabel('Subject', { exact: true });
this.estimatedTimeTb = page.getByLabel('Estimated time', { exact: true })
this.saveBtn = page.getByRole('button', { name: 'Save' });
}

async fillSubject(subject: string): Promise<NewTaskPage> {
await this.subjectTb.fill(subject);
return this;
}

async fillEstimatedTime(estimatedTime: string): Promise<NewTaskPage> {
// await page.locator('#wp-new-inline-edit--field-assignee').getByRole('combobox').click();
await this.estimatedTimeTb.fill(estimatedTime);
return this;
}

async clickOnSaveBtn(): Promise<OverviewPage> {
await this.saveBtn.click();
return new OverviewPage(this.page);
}

}

export class OpenProjectPage extends AbstractPage {

export class FilterComponent extends BaseComponent {

private readonly filterByTextTb: Locator;

constructor(page: Page) {
super(page);
this.filterByTextTb = page.getByPlaceholder('Subject, description, comments, ...');
}

async fillFilterByText(filterText: string): Promise<FilterComponent> {
const responsePromise = this.page.waitForResponse('**/queries/**');
await this.filterByTextTb.fill(filterText);
const response = await responsePromise
return this;
}

}

export class Table extends BaseComponent {
constructor(page: Page, rootLocator: Locator) {
super(page, rootLocator);
}

async containsText(text: string): Promise<boolean> {
return await this.searcher().locator('text=' + text).first().isVisible();
}
}

export class ApplicationMenu extends BaseComponent {

private readonly signOutBtn: Locator;

constructor(page: Page, rootLocator: Locator) {
super(page, rootLocator);
this.signOutBtn = this.searcher().getByRole('link', { name: 'Sign out' });
}

async clickOnSignOutBtn(): Promise<LoginPage> {
await this.signOutBtn.click();
return new LoginPage(this.page);
}
}


export class OpenProjectPage extends BasePage {

private readonly selectAProjectToggle: Locator;
private readonly applicationMenuLnk: Locator;
private readonly applicationMenuRoot: Locator;



constructor(page: Page) {
super(page);
this.selectAProjectToggle = page.locator("#projects-menu i");
this.applicationMenuLnk = page.locator("a[title='OpenProject Admin']").locator(".op-app-menu--item-title");
this.applicationMenuRoot = page.locator("#user-menu");
}

async clickOnSelectAProjectToggle(): Promise<OpenProjectPage> {
Expand All @@ -28,10 +140,15 @@ export class OpenProjectPage extends AbstractPage {
}

async clickOnProjectName(projectName: string): Promise<OverviewPage> {
await this.page.locator(`#ui-id-5 >> text=${projectName}`).click()
await this.page.locator('.project-search-results').getByRole('link', { name: projectName }).click();
return new OverviewPage(this.page);
}

async clickOnUserMenu(): Promise<ApplicationMenu> {
await this.applicationMenuLnk.click();
return new ApplicationMenu(this.page, this.applicationMenuRoot);
}

async doSelectProject(projectName: string): Promise<OverviewPage> {
await this.clickOnSelectAProjectToggle();
await this.clickOnProjectName(projectName);
Expand All @@ -40,7 +157,47 @@ export class OpenProjectPage extends AbstractPage {

}

export class LoginPage extends AbstractPage {

export class AllOpenWpPage extends OpenProjectPage {

private readonly createNewWpBtn: Locator;
private readonly taskBtn: Locator;
private readonly activateFilterBtn: Locator;
private readonly deactivateFilterBtn: Locator;
public readonly table: Table;


constructor(page: Page) {
super(page);
this.createNewWpBtn = page.locator('wp-create-button').getByLabel('Create new work package');
this.taskBtn = page.locator('#types-context-menu').getByLabel('Task' ,{ exact: true });
this.activateFilterBtn = page.getByRole('button', { name: 'Activate Filter' });
this.deactivateFilterBtn = page.getByRole('button', { name: 'Deactivate Filter' });
this.table = new Table(page, page.locator('.work-package-table'));
}

async clickOnCreateNewWorkPackageBtn(): Promise<NewTaskPage> {
await this.createNewWpBtn.click();
await this.taskBtn.click();
return new NewTaskPage(this.page);
}

async clickOnActivateFilterBtn(): Promise<FilterComponent> {
await this.activateFilterBtn.click();
return new FilterComponent(this.page);
}

async clickOnDeactivateFilterBtn(): Promise<AllOpenWpPage> {
await this.deactivateFilterBtn.click();
return new AllOpenWpPage(this.page);
}


}



export class LoginPage extends BasePage {
/**
* @param {import('playwright').Page} page
*/
Expand Down
7 changes: 4 additions & 3 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ export default defineConfig({
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
retries: 1,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
workers: 4,
// workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
Expand All @@ -28,7 +29,7 @@ export default defineConfig({
// baseURL: 'http://127.0.0.1:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
trace: 'on',
},

/* Configure projects for major browsers */
Expand Down
35 changes: 35 additions & 0 deletions tests/acme-bank/test-parallel-acme-bank.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { test, expect } from '@playwright/test';

test.describe.configure({ mode: 'parallel' });

// Workers #Tests Duration - All Tests Duration - Single Test
// 1 8 29 3.625
// 4 8 23 2.875
// 8 8 32 4


for (const counter of ['0', '1', '2', '3', '4', '5', '6', '7']) {
test(`testing with ${counter}`, async ({ page }) => {
await page.goto('https://demo.applitools.com/');
await page.getByPlaceholder('Enter your username').click();
await page.getByPlaceholder('Enter your username').fill('user');
await page.getByPlaceholder('Enter your password').click();
await page.getByPlaceholder('Enter your password').fill('password');
await page.getByRole('link', { name: 'Sign in' }).click();
await page.locator('.os-icon').first().click();
await page.getByRole('link', { name: ' Make Payment' }).click();
await page.getByRole('link', { name: ' Add Account' }).click();
await page.locator('.avatar-w > img').first().click();
await page.locator('.menu-w > .logged-user-w > .logged-user-i > .avatar-w > img').click();
await page.locator('.logged-user-toggler-arrow > .os-icon').click();
await page.getByRole('link', { name: '  Credit cards' }).click();
await page.getByRole('link', { name: '  Debit cards' }).click();
await page.getByRole('link', { name: '  Loans' }).click();
await page.getByRole('link', { name: '  Mortgages' }).click();
await page.getByRole('link', { name: 'View Statement ' }).click();
await expect(page.locator('body')).toContainText('$350');
await page.locator('.logged-user-w').first().click();
});

}

Loading

0 comments on commit c6760f2

Please sign in to comment.