Dynamic Page Object Model (POM) is a design pattern used in test automation to create reusable and maintainable code for interacting with web pages. Using Playwright with TypeScript, you can create a dynamic POM structure that adapts to different pages or components dynamically.
Here’s how you can create a Dynamic POM using TypeScript in Playwright:
## **1. Project Setup**
1. **Initialize a Playwright project**:
npm init playwright@latest
Choose TypeScript as the language during setup.
2. **Install dependencies**:
Playwright is already installed, but ensure TypeScript and related tools are installed:
npm install --save-dev typescript @playwright/test
3. **Folder structure**:
Create a folder structure for your POM:
my-playwright-project/
├── pages/ # Page Object files
│ ├── BasePage.ts # Base class for all pages
│ ├── HomePage.ts # Example page object
│ └── LoginPage.ts # Example page object
├── tests/ # Test files
│ └── example.spec.ts # Example test
├── playwright.config.ts # Playwright configuration
└── tsconfig.json # TypeScript configuration
## **2. Create a Base Page Class**
The `BasePage` class will contain common methods and properties that all pages can inherit.
import { Page } from '@playwright/test';
export class BasePage {
protected page: Page;
constructor(page: Page) {
this.page = page;
}
// Navigate to a URL
async navigateTo(url: string): Promise<void> {
await this.page.goto(url);
}
// Generic method to click an element
async click(selector: string): Promise<void> {
await this.page.click(selector);
}
// Generic method to type into an input field
async type(selector: string, text: string): Promise<void> {
await this.page.fill(selector, text);
}
// Generic method to get text from an element
async getText(selector: string): Promise<string> {
return await this.page.textContent(selector) || '';
}
// Generic method to check if an element is visible
async isVisible(selector: string): Promise<boolean> {
return await this.page.isVisible(selector);
}
}
## **3. Create Specific Page Classes**
Extend the `BasePage` class to create specific page objects for different pages.
### **HomePage.ts**
import { BasePage } from './BasePage';
export class HomePage extends BasePage {
// Selectors for elements on the home page
private readonly headerSelector = 'h1';
private readonly loginButtonSelector = 'text=Login';
// Get the header text
async getHeaderText(): Promise<string> {
return await this.getText(this.headerSelector);
}
// Click the login button
async clickLoginButton(): Promise<void> {
await this.click(this.loginButtonSelector);
}
}
### **LoginPage.ts**
import { BasePage } from './BasePage';
export class LoginPage extends BasePage {
// Selectors for elements on the login page
private readonly usernameInput = '#username';
private readonly passwordInput = '#password';
private readonly submitButton = 'button[type="submit"]';
// Log in with username and password
async login(username: string, password: string): Promise<void> {
await this.type(this.usernameInput, username);
await this.type(this.passwordInput, password);
await this.click(this.submitButton);
}
}
## **4. Write a Test Using Dynamic POM**
Now, you can use the page objects in your test files.
### **example.spec.ts**
```typescript
import { test, expect } from '@playwright/test';
import { HomePage } from '../pages/HomePage';
import { LoginPage } from '../pages/LoginPage';
test('Dynamic POM example', async ({ page }) => {
// Create instances of page objects
const homePage = new HomePage(page);
const loginPage = new LoginPage(page);
// Navigate to the home page
await homePage.navigateTo('https://example.com');
// Verify the header text
const headerText = await homePage.getHeaderText();
expect(headerText).toBe('Example Domain');
// Click the login button
await homePage.clickLoginButton();
// Log in with credentials
await loginPage.login('testuser', 'password123');
// Verify successful login (example)
const isLoggedIn = await loginPage.isVisible('text=Welcome, testuser');
expect(isLoggedIn).toBeTruthy();
});
## **5. Run the Test**
Run the test using the Playwright CLI:
npx playwright test
## **6. Advantages of Dynamic POM**
- **Reusability**: Common methods are defined in the `BasePage` class, reducing code duplication.
- **Maintainability**: Changes to selectors or methods are isolated to specific page objects.
- **Scalability**: Easily add new page objects for additional pages or components.
## **7. Tips for Dynamic POM**
- Use **TypeScript interfaces** or types to define reusable data structures.
- Use **Playwright locators** for better performance and readability:
```typescript
async click(locator: Locator): Promise<void> {
await locator.click();
}
ADDITIONAL NOTE: Use Playwright's **test fixtures** to initialize page objects dynamically.
By following this structure, you can create a robust and scalable test automation framework using Playwright and TypeScript. 🎉
No comments:
Post a Comment