1. What is the role of Selectors in Playwright, and how do they differ from Selenium selectors?
Role of Selectors: Selectors in Playwright are used to locate and interact with elements on a web page. Playwright supports a wide range of selectors, including CSS, XPath, text-based, and even custom selectors.
Difference from Selenium:
Auto-Waiting: Playwright automatically waits for elements to be actionable (visible, enabled, etc.), reducing flaky tests. Selenium requires explicit waits.
Selector Engine: Playwright’s selector engine is more robust and supports advanced features like
:has-text()and:nth-match().Strict Mode: Playwright selectors are strict by default, meaning they throw an error if multiple elements match, whereas Selenium may return the first match.
2. How does Playwright handle browser context isolation?
Browser Contexts: Playwright uses browser contexts to create isolated environments within the same browser instance. Each context has its own cookies, cache, and storage, enabling parallel test execution without interference.
Isolation Benefits: This allows for faster and more efficient testing, as multiple tests can run simultaneously in separate contexts without sharing state.
3. What are the key differences between Page, Frame, and Worker in Playwright?
Page: Represents a single tab or window in the browser. It is the main entry point for interacting with the web content.
Frame: Represents an iframe or frame within a page. Playwright allows interaction with nested frames using the
frameobject.Worker: Represents a Web Worker, which runs scripts in the background. Playwright can interact with workers to test service workers or other background tasks.
4. How does Playwright support parallel test execution, and how does it differ from Selenium?
Parallel Execution: Playwright supports parallel execution out-of-the-box using browser contexts. Each test can run in its own isolated context, enabling true parallelism.
Difference from Selenium: Selenium requires additional tools like TestNG or JUnit for parallel execution, and it often involves managing multiple browser instances, which can be resource-intensive.
5. Explain how to intercept and mock network requests in Playwright.
Intercepting Requests: Use
page.route()to intercept network requests. You can modify or mock the response usingroute.fulfill().Example:
await page.route('**/api/data', route => route.fulfill({ status: 200, body: 'Mocked response' }));
6. Techniques for handling authentication in Playwright?
Storage State: Use
browserContext.storageState()to save and reuse authentication cookies or tokens.API Authentication: Authenticate via API and inject the token into the browser context.
Manual Login: Automate the login process once and reuse the session for subsequent tests.
7. How does Playwright handle multi-tab scenarios?
Multiple Pages: Playwright allows you to create and manage multiple pages (tabs) within the same browser context.
Example:
const [newPage] = await Promise.all([ context.waitForEvent('page'), page.click('a[target="_blank"]') // Opens a new tab ]);
8. How to manage browser-specific behaviors in Playwright?
Browser-Specific Code: Use conditional logic based on the browser type (
chromium,firefox,webkit).Example:
if (browserName === 'firefox') { // Firefox-specific code }
9. Disadvantages of Playwright?
Learning Curve: Requires familiarity with modern JavaScript/TypeScript.
Limited Community: Smaller community compared to Selenium, though it’s growing.
Browser Support: While it supports Chromium, Firefox, and WebKit, it may not cover all legacy browsers.
10. How do you handle auto-waiting and synchronization in Playwright?
Auto-Waiting: Playwright waits for elements to be visible, enabled, and stable before interacting with them.
Example:
await page.click('button'); // Waits for the button to be clickable
11. How do you handle file uploads and downloads in Playwright?
File Upload:
await page.setInputFiles('input[type="file"]', 'path/to/file');
File Download:
const [download] = await Promise.all([ page.waitForEvent('download'), page.click('a#download-link') ]); const path = await download.path();
12. What are some best practices for structuring Playwright tests?
Modularize Tests: Break tests into smaller, reusable functions.
Use Fixtures: Leverage Playwright’s fixtures for setup and teardown.
Page Object Model: Use POM to separate test logic from UI selectors.
CI/CD Integration: Run tests in CI/CD pipelines for automated feedback.
13. How do you leverage Playwright's tracing and debugging features?
Tracing:
await context.tracing.start({ screenshots: true, snapshots: true }); await context.tracing.stop({ path: 'trace.zip' });
Debugging: Use
playwright inspectorto step through tests and debug issues.
14 Explain Playwright folder Structure
1) Default Folder Structure with npm init playwright
npm init playwright
it comes with a default folder structure and some example files to help you get started. However, this structure is minimal and may not include all the folders or organizational patterns
my-playwright-project/ ├── tests/ │ ├── example.spec.ts ├── tests-examples/ │ ├── demo-todo-app.spec.ts ├── playwright.config.ts ├── package.json ├── package-lock.json ├── .gitignore
Key Files and Folders
1) tests/Contains a basic example test file (
example.spec.ts).This is where you’ll write your actual test cases.
2) tests-examples/
Contains additional example tests (e.g.,
demo-todo-app.spec.ts) to demonstrate Playwright’s capabilities.These are for learning purposes and can be deleted later.
3) playwright.config.tsThe default configuration file for Playwright.
Preconfigured with common settings like browsers, timeouts, and reporters.
4) package.jsonLists Playwright as a dependency and includes scripts for running tests (e.g.,
npx playwright test).
5) .gitignorePreconfigured to ignore unnecessary files like
node_modules/and test artifacts.
What’s Missing in the Default Structure?
The default structure is minimal and doesn’t include some of the advanced organizational patterns I mentioned earlier. For example:
No
src/orpages/folder for Page Object Model (POM).No
data/folder for test data.No
fixtures/folder for custom fixtures.No
reports/folder (though reports are generated in a temporary directory by default).No
global-setup/orglobal-teardown/folders.
Do You Need to Customize the Structure?
Yes, for most real-world projects, you’ll want to customize the folder structure to suit your needs. Here’s why:
Scalability: The default structure is fine for small projects, but as your test suite grows, you’ll need better organization.
Reusability: Adding a
src/orpages/folder for POM improves code reuse and maintainability.Maintainability: Separating test data, utilities, and configurations into dedicated folders makes the project easier to manage.
Team Collaboration: A well-organized structure helps team members navigate the codebase and follow best practices.
How to Customize the Structure
Add a
src/orpages/folder for Page Object Model (POM) classes.Example:
src/pages/LoginPage.js.
Create a
data/folder for test data.Example:
data/test-data.json.
Add a
fixtures/folder for custom fixtures.Example:
fixtures/customFixtures.js.
Set up a
reports/folder for storing test reports.Configure this in
playwright.config.js.
Add
global-setup/andglobal-teardown/scripts if needed.Example:
global-setup/global-setup.js.
Organize tests by feature or module within the
tests/folder.Example:
tests/login/,tests/checkout/.
Example Structure
Here’s what the folder structure might look like:
playwright-project/ ├── playwright.config.js ├── package.json ├── node_modules/ ├── tests/ │ ├── example.spec.js │ ├── __snapshots__/ ├── src/ │ ├── pages/ │ │ ├── LoginPage.js │ │ ├── HomePage.js │ ├── utils/ │ │ ├── helpers.ts ├── fixtures/ │ ├── customFixtures.js ├── data/ │ ├── test-data.json │ ├── env-config.json ├── reports/ │ ├── html/ │ ├── json/ ├── global-setup/ │ ├── global-setup.js ├── global-teardown/ │ ├── global-teardown.js ├── .github/ │ ├── workflows/ │ │ ├── playwright.yml
15 Cypress vs Playwright
1. Cypress Limitations (Where Playwright Wins)
Single Browser Limitation – Cypress mainly supports Chromium; Playwright supports Chrome, Firefox, Safari, and Edge.
No Native Multi-Tab & Multi-Window Support – Playwright handles multi-tab/multi-window scenarios easily.
Limited Mobile Testing – Cypress can only emulate, while Playwright supports real mobile browsers.
iFrame & Shadow DOM Challenges – Playwright interacts with iframes and shadow DOM more reliably.
Limited Network Control – Playwright has advanced request/response interception and network throttling.
Parallel Execution Requires Paid Dashboard – Playwright offers parallel execution natively.
2. Playwright Drawbacks (Where Cypress Wins)
Steeper Learning Curve – Playwright requires
async/await, making tests more complex.No Built-In UI Test Runner – Cypress has an interactive Test Runner with time-travel debugging.
Setup Can Be More Involved – Cypress has a plug-and-play setup, while Playwright requires additional configurations.
Weaker Community & Plugin Support – Cypress has been around longer, leading to more community-driven plugins.
No Native Time-Travel Debugging – Cypress allows step-by-step test execution in its Test Runner.
3. When to Choose What?
| Use Case | Choose |
|---|---|
| Fast UI testing & simple setup | Cypress |
| Multi-browser support | Playwright |
| Mobile browser testing | Playwright |
| Debugging & Dev-Friendly Experience | Cypress |
| Advanced network & API control | Playwright |
| Parallel execution without extra cost | Playwright |
Cypress is better for fast debugging, simple UI tests, and developer-friendly experience.
Playwright is better for complex E2E testing requiring multi-browser, multi-tab, and network control.
Cypress is easier to start with, but Playwright provides more flexibility and scalability.
If unsure, use both: Cypress for quick UI tests, Playwright for deep cross-browser E2E testing.
16. Explain core annotation in playwright
1. test
Purpose: Defines a test case.
Usage:
const { test } = require('@playwright/test'); test('Test Case Name', async ({ page }) => { // Test logic here });
2. test.describe
Purpose: Groups related test cases together.
Usage:
const { test } = require('@playwright/test'); test.describe('Test Suite Name', () => { test('Test Case 1', async ({ page }) => { // Test logic here }); test('Test Case 2', async ({ page }) => { // Test logic here }); });
3. test.beforeAll
Purpose: Runs a setup function once before all tests in a test suite.
Usage:
const { test } = require('@playwright/test'); test.describe('Test Suite', () => { test.beforeAll(async ({ page }) => { // Setup logic here (e.g., login) }); test('Test Case', async ({ page }) => { // Test logic here }); });
4. test.afterAll
Purpose: Runs a teardown function once after all tests in a test suite.
Usage:
const { test } = require('@playwright/test'); test.describe('Test Suite', () => { test.afterAll(async ({ page }) => { // Teardown logic here (e.g., logout) }); test('Test Case', async ({ page }) => { // Test logic here }); });
5. test.beforeEach
Purpose: Runs a setup function before each test in a test suite.
Usage:
const { test } = require('@playwright/test'); test.describe('Test Suite', () => { test.beforeEach(async ({ page }) => { // Setup logic here (e.g., navigate to a page) }); test('Test Case', async ({ page }) => { // Test logic here }); });
6. test.afterEach
Purpose: Runs a teardown function after each test in a test suite.
Usage:
const { test } = require('@playwright/test'); test.describe('Test Suite', () => { test.afterEach(async ({ page }) => { // Teardown logic here (e.g., clear state) }); test('Test Case', async ({ page }) => { // Test logic here }); });
7. test.skip
Purpose: Skips a specific test or test suite.
Usage:
const { test } = require('@playwright/test'); test.skip('Skipped Test Case', async ({ page }) => { // This test will be skipped });
8. test.fixme
Purpose: Marks a test as "to be fixed" and skips it.
Usage:
const { test } = require('@playwright/test'); test.fixme('Test Case to be Fixed', async ({ page }) => { // This test will be skipped });
9. test.only
Purpose: Runs only the specified test or test suite, skipping all others.
Usage:
const { test } = require('@playwright/test'); test.only('Run Only This Test', async ({ page }) => { // Only this test will run });
10. test.slow
Purpose: Marks a test as "slow," increasing its timeout.
Usage:
const { test } = require('@playwright/test'); test.slow('Slow Test Case', async ({ page }) => { // This test will have a longer timeout });
11. test.fail
Purpose: Marks a test as expected to fail. If the test passes, it will be reported as a failure.
Usage:
const { test } = require('@playwright/test'); test.fail('Failing Test Case', async ({ page }) => { // This test is expected to fail });
12. test.setTimeout
Purpose: Sets a custom timeout for a specific test.
Usage:
const { test } = require('@playwright/test'); test('Test with Custom Timeout', async ({ page }) => { test.setTimeout(120000); // 2 minutes // Test logic here });
13. test.step
Purpose: Groups actions within a test into logical steps for better reporting.
Usage:
const { test } = require('@playwright/test'); test('Test with Steps', async ({ page }) => { await test.step('Step 1: Navigate to Page', async () => { await page.goto('https://example.com'); }); await test.step('Step 2: Perform Action', async () => { await page.click('button'); }); });
14. test.use
Purpose: Overrides default options (e.g., browser, viewport) for a specific test or suite.
Usage:
const { test } = require('@playwright/test'); test.use({ viewport: { width: 1280, height: 1024 } }); test('Test with Custom Viewport', async ({ page }) => { // Test logic here });
15. test.extend
Purpose: Extends the
testobject with custom fixtures or options.Usage:
const { test } = require('@playwright/test'); const customTest = test.extend({ customFixture: async ({}, use) => { // Custom fixture logic await use('Custom Value'); }, }); customTest('Test with Custom Fixture', async ({ customFixture }) => { console.log(customFixture); // Output: Custom Value });
16. test.info
Purpose: Provides metadata about the current test (e.g., title, file path).
Usage:
const { test } = require('@playwright/test'); test('Test with Info', async ({ page }) => { console.log(test.info().title); // Output: Test with Info });
17. Explain user-defined annotations or decorators
Examples of Custom Annotations
Example 1: Custom Fixture Annotation
You can create a custom fixture and use it as an annotation-like feature.
const { test } = require('@playwright/test'); // Define a custom fixture const customTest = test.extend({ myCustomFixture: async ({}, use) => { console.log('Setting up custom fixture...'); await use('Custom Value'); console.log('Tearing down custom fixture...'); }, }); // Use the custom fixture as an annotation customTest('Test with Custom Fixture', async ({ myCustomFixture }) => { console.log(myCustomFixture); // Output: Custom Value });
Here, myCustomFixture acts like a custom annotation.
Example 2: Custom Decorator Function
You can create a custom decorator function to wrap test logic.
const { test } = require('@playwright/test'); // Custom decorator function function myCustomAnnotation(testFn) { return async (args) => { console.log('Before test'); await testFn(args); console.log('After test'); }; } // Use the custom decorator test('Test with Custom Annotation', myCustomAnnotation(async ({ page }) => { await page.goto('https://example.com'); console.log('Test logic'); }));
Here, myCustomAnnotation acts like a custom annotation.
Example 3: Third-Party Annotations
You can integrate third-party libraries that provide their own annotations. For example:
@babel/plugin-proposal-decorators: Allows you to use decorators in JavaScript/TypeScript.@storybook/testing-library: Provides annotations for testing Storybook components.@testing-library/react: Provides annotations for React component testing.
How to Add Custom Annotations
Define Custom Fixtures: Use
test.extendto create reusable fixtures.Write Decorator Functions: Create functions that wrap test logic.
Use Third-Party Libraries: Integrate libraries that provide annotations.
Example Folder Structure with Custom Annotations
Here’s how you might organize a project with custom annotations:
my-playwright-project/ ├── tests/ │ ├── example.spec.ts ├── src/ │ ├── annotations/ │ │ ├── myCustomAnnotation.ts │ ├── fixtures/ │ │ ├── myCustomFixture.ts ├── playwright.config.ts ├── package.json
No comments:
Post a Comment