# Playwright Typescript Topics

npx playwright test

you're invoking Playwright’s built-in test runner (called Playwright Test) using npx. Here's a breakdown: ⚙️ What Each Part Does

npx

A Node.js tool that runs locally installed CLI tools without installing them globally.

It ensures you're using the version of playwright that’s installed in your project.

playwright

The package which includes both the browser automation API and the @playwright/test runner YouTube

test

A sub-command that triggers the @playwright/test runner.

Executes all tests in your project as configured in playwright.config.js/ts Wikipedia+4Playwright+4Cuketest+4 .

🏃 What Happens When You Run It

Auto-compilation & discovery The runner compiles TypeScript (if used), finds .spec.\* files in your testDir, and builds a list of tests.

Parallel execution Tests are executed in parallel across multiple browser contexts (Chromium, Firefox, WebKit) unless configured otherwise

Headless by default It runs tests without opening the browser GUI. Use flags (--headed, --debug, or --ui) to override Test Management

Artifacts & reports Automatically captures screenshots, videos, traces, and generates readable output in terminal and optional HTML report.

🔧 Common Flags You Can Add Flag Effect --headed Run with visible browsers, not headless --project=chromium Choose a specific browser project -g "name" Filter tests by name --workers=1 Disable parallel execution --debug Launch Playwright Inspector (slows execution for debugging) --ui Opens an interactive test runner interface --last-failed Rerun only the tests that failed in the last run --only-changed Run tests that were changed since last commit.

```bash
# Run all tests headlessly
npx playwright test

# Run a single spec file in Chrome with browser window visible
npx playwright test tests/login.spec.ts --project=chromium --headed

# Debug one test with Inspector:
npx playwright test tests/login.spec.ts --debug

# Run UI test runner locally:
npx playwright test --ui
```

### Locators

### 🧭 User‐facing (Preferred) Locators

These are recommended for stable and maintainable tests, as they reflect how users and assistive technologies interact with your UI [Stack Overflow+15Playwright+15Medium+15](https://playwright.dev/docs/locators?utm_source=chatgpt.com):

1. **Role** – `page.getByRole(role, { name })`  
    Targets elements by ARIA role (e.g. `"button"`, `"checkbox"`) and accessible name. Ideal for accessibility-aligned selection.
    
    ```bash
    await page.getByRole('button', { name: 'Submit' }).click();
    ```
    
    **Text** – `page.getByText("...")`  
    Finds elements containing visible text. Supports substring, exact match, or regex.
    

```bash
await page.getByText(/welcome/i).click();
```

**Label** – `page.getByLabel("...")`  
Locates form controls by their corresponding `<label>` text.

```bash
await page.getByLabel('Email').fill('user@example.com');
```

**Placeholder** – `page.getByPlaceholder("...")`  
Finds `<input>` or `<textarea>` via placeholder attribute.

```bash
await page.getByPlaceholder('name@example.com').fill('...');
```

**Alt Text** – `page.getByAltText("...")`  
Targets `<img>` (and similar) using its alt-text. Great for clickable images.

```bash
await page.getByAltText('logo').click();
```

**Title** – `page.getByTitle("...")`  
Selects elements with a matching `title="..."` attribute—often tooltips.

```bash
await page.getByTitle('Close dialog').click();
```

**Test ID** – `page.getByTestId("...")`  
Picks elements tagged with `data-testid="..."` (or custom attribute). Useful for projecting test‑only hooks.

```bash
await page.getByTestId('user-menu').click();
```

**CSS** – `page.locator('css=...')`  
Leverages standard CSS selectors and supports Playwright’s powerful pseudo‑classes like `:has-text()` and `:visible`

```bash
await page.locator('ul > li.item:has-text("Table")').click();
```

XPath – page.locator('xpath=...') Enables selecting nodes via XPath expressions.

```bash
await page.locator('xpath=//div[@class="modal"]//button[text()="Close"]').click();
```

### 🛠 Comparison & Best Practices

* **First choice**: Use **role**, then **text**, then **label**, etc.—the *user-first* selection philosophy [HeadSpin+10Checkly+10LinkedIn+10](https://www.checklyhq.com/blog/playwright-user-first-selectors/?utm_source=chatgpt.com).
    
* **Next**, resort to **CSS** when no helpful attributes exist.
    
* **Avoid XPath** unless absolutely needed—it’s harder to maintain and performance may suffer [Medium+2Playwright+2Stack Overflow+2](https://playwright.dev/docs/other-locators?utm_source=chatgpt.com).
    
* **Test IDs** (`data-testid`) are stable hooks, particularly when UI text or structure may change without impacting functionality [Stack Overflow+6Cuketest+6HeadSpin+6](https://www.cuketest.com/playwright/docs/locators/?utm_source=chatgpt.com).
    
* **Chaining & filtering**: You can refine locators further using methods like `.filter()`, `.nth()`, or chaining `locator.getBy...()` for precision.
    

### 📋 Summary Table

| Locator Type | Usage Example | Ideal For |
| --- | --- | --- |
| Role | `getByRole('button', {name: 'OK'})` | Buttons, checkboxes, etc. |
| Text | `getByText(/submit/i)` | Any element with visible text |
| Label | `getByLabel('Username')` | Form inputs with `<label>` |
| Placeholder | `getByPlaceholder('Search')` | Empty inputs with placeholder |
| Alt Text | `getByAltText('Logo')` | Images, icons |
| Title | `getByTitle('Close dialog')` | Elements with `title=...` |
| Test ID | `getByTestId('nav-item')` | Elements with test-specific ids |
| CSS | `locator('div.nav > a')` | Complex selectors |
| XPath | `locator('xpath=...')` | Rare/edge-case structured DOM |

## Assertions

## 👀 `await expect(locator).toBeVisible()`

* **What it checks**
    
    * The element is in the DOM
        
    * Bounding box is non-empty (has size)
        
    * Not `display: none` or `visibility: hidden`
        
    * Visible, but can still be transparent (`opacity: 0`)
        
* **Auto-retries**
    
    * Will poll repeatedly until visible or timeout (default ~5s)
        
* **Use case**
    
    * Validates that content has appeared before interacting (e.g., ensures button is actually visible before clicking)
        

---

## ✍️ `await expect(locator).toHaveText(expected)` & `.toHaveValue(expected)`

* **toHaveText(text or regex)**
    
    * Waits until inner-text equals expected, including normalization of whitespace
        
* **toHaveValue(value or regex)**
    
    * Waits until the input (or select) has that value
        
* **Auto-retries**
    
    * Both methods retry until pass or timeout
        
* **Use case**
    
    * When you need to confirm dynamic content (e.g., after typing or loading)
        

---

## ☑️ `await expect(locator).toBeChecked()`

* **What it checks**
    
    * Applies to checkboxes/radios
        
    * Confirms they are actually checked (`input.checked === true`)
        
* **Auto-retries**
    
    * Retries until the checked state is confirmed or timeout
        
* **Use case**
    
* ```bash
        await page.getByLabel('Subscribe').check();
        await expect(page.getByLabel('Subscribe')).toBeChecked();
    ```
    
    ## ⛔ `await expect(locator).toBeDisabled()`
    
    * **What it checks**
        
        * Checks if a form control (`<button>`, `<input>`, `<select>`, etc.) is disabled (`disabled` attribute OR `aria-disabled`)
            
    * **Auto-retries**
        
        * Retries until disabled state detected, or times out
            
    * **Use case**
        
        * Confirm controls are correctly disabled during processing before further interactions
            
    
    ---
    
    ### 🧠 Behind the curtains — **Auto-Retry & Defaults**
    
    All these are **LocatorAssertions**, meaning they automatically **refetch the locator** and **retry** the assertion until:
    
    * The condition is met, **or**
        
    * The **timeout** is reached (default ~5 seconds, configurable via `expect.setTimeout()` or `playwright.config.ts`)
        
    
    This smart behavior handles timing issues gracefully and hugely reduces flakiness.
    
* ```bash
        import { test, expect } from '@playwright/test';
        
        test('form interaction example', async ({ page }) => {
          await page.goto('/settings');
        
          // wait until form loads
          await expect(page.getByText('Settings')).toBeVisible();
        
          // checkbox toggling
          const notify = page.getByLabel('Email notifications');
          await notify.check();
          await expect(notify).toBeChecked();
        
          // value change
          const input = page.getByPlaceholder('Username');
          await input.fill('newuser');
          await expect(input).toHaveValue('newuser');
        
          // form submission
          const submit = page.getByRole('button', { name: 'Save' });
          await expect(submit).toBeEnabled();
          await submit.click();
        
          // confirmation message
          await expect(page.getByText('Changes saved')).toBeVisible();
        });
    ```
    
    ### 🧩 TL;DR
    
    | Assertion | Checks | Auto-Retry | Use Case |
    | --- | --- | --- | --- |
    | `toBeVisible()` | Element exists and is visible | ✅ | Await dynamic content/display updates |
    | `toHaveText()` | Exact inner text match | ✅ | Validate dynamic or loaded text |
    | `toHaveValue()` | Input/select value match | ✅ | Confirm typing or selection updates |
    | `toBeChecked()` | Checkbox/radio is checked | ✅ | Verify toggles or checkboxes |
    | `toBeDisabled()` | Form control is disabled | ✅ | Ensure controls are correctly disabled |
    

## Element Actions

Here’s a breakdown of the most common **element actions** in Playwright, what they do, and when to use them:

---

## 🎯 Core Actions

### `click()`

* Simulates a human-like click (single by default).
    
* Waits for the element to be visible, stable, and ready.
    
* Supports options like:
    
    * `{ button: 'right' }` for right-click
        
    * `{ modifiers: ['Shift'] }` for shift-click
        
    * `{ force: true }` to bypass visibility and hitability checks [Stack Overflow+9Playwright+9testomat.io+9](https://playwright.dev/docs/input?utm_source=chatgpt.com)[Codoid+5Checkly+5Stack Overflow+5](https://www.checklyhq.com/learn/playwright/clicking-typing-hovering/?utm_source=chatgpt.com)
        

### `dblclick()`

* Performs a double-click on the element.
    
* Equivalent to two rapid clicks. [Playwright](https://playwright.dev/docs/input?utm_source=chatgpt.com)
    

### `hover()`

* Moves the mouse over the element.
    
* Useful for activating hover menus or tooltips. [Codoid](https://codoid.com/automation-testing/playwright-cheatsheet-quick-tips-for-testers/?utm_source=chatgpt.com)
    

### `fill()`

* Clears any existing text and sets the input to the specified string.
    
* Triggers focus, `input`, and `change` events.
    
* Works on `<input>`, `<textarea>`, and content‑editable elements. [Stack Overflow+9Playwright+9Playwright+9](https://playwright.dev/docs/input?utm_source=chatgpt.com)
    

### `type()`

* Types text character by character, triggering `keydown`, `keypress`, `input`, and `keyup`.
    
* Typically used only when text needs to be processed per keystroke. [Playwright](https://playwright.dev/docs/api/class-locator?utm_source=chatgpt.com)
    

### `press()`

* Sends a key or key combination (e.g. `'Enter'`, `'Control+ArrowRight'`).
    
* Simulates keyboard shortcuts. [Playwright](https://playwright.dev/docs/input?utm_source=chatgpt.com)
    

### `check()` / `uncheck()`

* Toggles checkboxes or radio buttons.
    
* Auto-scrolls and ensures correct final state. [Codoid+3Playwright+3Playwright+3](https://playwright.dev/docs/input?utm_source=chatgpt.com)[Playwright+2Stack Overflow+2YouTube+2](https://stackoverflow.com/questions/66702908/how-to-select-a-dropdown-option-using-playwright-in-javascript?utm_source=chatgpt.com)
    

### `selectOption()`

* Selects one or multiple options in a `<select>`.
    
* You can match by value or label. [Stack Overflow+6Playwright+6Playwright+6](https://playwright.dev/docs/input?utm_source=chatgpt.com)
    

---

## 🛠 Additional Element Actions

These are less commonly mentioned but can be very useful:

### `focus()` / `blur()`

* `focus()` gives keyboard and visual focus to an element.
    
* `blur()` removes focus. [Playwright](https://playwright.dev/docs/input?utm_source=chatgpt.com)[Codoid+1Playwright+1](https://codoid.com/automation-testing/playwright-cheatsheet-quick-tips-for-testers/?utm_source=chatgpt.com)[Stack Overflow+2Medium+2YouTube+2](https://medium.com/%40Sudheer_Parishrama/basic-user-interactions-with-playwright-clicks-types-and-more-49f8975b17e5?utm_source=chatgpt.com)
    

### `dispatchEvent()`

* Triggers any DOM event programmatically (e.g. `'click'`, `'dragstart'`).
    
* Useful for simulating events without user interaction. [Playwright](https://playwright.dev/docs/api/class-locator?utm_source=chatgpt.com)
    

### `dragTo()`

* Clicks and drags one element onto another (supports articles/drag-drop).
    

### `scrollIntoViewIfNeeded()`

* Scrolls the element into view if it’s off-screen or hidden beneath the fold.
    
* Often used internally before click or input actions. [Playwright](https://playwright.dev/docs/input?utm_source=chatgpt.com)[Playwright](https://playwright.dev/docs/api/class-locator?utm_source=chatgpt.com)
    

---

## ⏱ Action Flow & Auto-Waiting

Playwright actions automatically incorporate checks like:

1. Waiting for the element to be in the DOM
    
2. Checking visibility and display styles
    
3. Ensuring the element isn’t moving or obscured
    
4. Scrolling it into view
    
5. Retrying if it becomes detached mid-action [Stack Overflow+5Codoid+5Stack Overflow+5](https://codoid.com/automation-testing/playwright-cheatsheet-quick-tips-for-testers/?utm_source=chatgpt.com)[Checkly+9Playwright+9Playwright+9](https://playwright.dev/docs/input?utm_source=chatgpt.com)
    

---

## ✅ When to Use What

| Situation | Action |
| --- | --- |
| Clicking a button/link | `click()` |
| Clicking twice (e.g., selecting text) | `dblclick()` |
| Hovering to reveal menus/tooltips | `hover()` |
| Filling text inputs or textareas | `fill()` |
| Simulating typing per character | `type()` or `press()` |
| Checking/unchecking checkbox/radio | `check()` / `uncheck()` |
| Choosing dropdown options | `selectOption()` |
| Drag-and-drop interactions | `dragTo()` |
| Triggering JS-defined events | `dispatchEvent()` |
| Scrolling into view manually | `scrollIntoViewIfNeeded()` |
| Focusing/blurring input fields | `focus()` / `blur()` |

## Handling Forms and Inputs

Difference between fill() and type() :-

## 🧩 `locator.fill(text)`

* **All‑at‑once**: Clears any existing content and sets the full text immediately.
    
* **Triggers**: Dispatches a single `input` event (and `change` on blur).
    
* **Ideal for**: Filling forms quickly with exact values.
    
* **Under the hood**: Focuses the element, clears `value`, fills new `text`, and emits events .
    
* **Best practice**:
    
    ```bash
    await page.getByLabel('Email').fill('alice@example.com');
    ```
    
    ## 🎯 `locator.type(text, { delay? })`
    
    * **Simulates real typing**: Sends one character at a time like an actual user.
        
    * **Triggers**: Full keyboard event sequence — `keydown`, `keypress`, `keyup` — for each character.
        
    * **Optional delay**: You can slow it down (e.g. `{ delay: 100 }` ms) to mimic human speed.
        
    * **Use case**: When the page has special keystroke-based logic (e.g. autocomplete, shortcuts, input masks)
        
    * **Example**:
        

```bash
  await page.getByPlaceholder('Search...').type('Playwright', { delay: 100 });
```

### 🔑 Comparison Summary

| Criterion | `fill()` | `type()` |
| --- | --- | --- |
| Input behavior | Set value in one go | Simulates authentic typing |
| Events triggered | Single `input` event | `keydown`/`keypress`/`keyup` per char |
| Use case | Forms, quick fill | Autocomplete, masked inputs, UX logic |
| Speed control | No delay option | Delay between keystrokes |
| Default recommendation | ✅ Preferred for most scenarios | ✅ Use when character timing matters |

## Auto-Waits

Whenever you perform an action—like `click()`, `fill()`, or `type()`—Playwright performs a set of **actionability checks**, waiting for each to pass before proceeding :

* ✅ **Attached**: Element exists in the DOM.
    
* ✅ **Visible**: Element is rendered (non-zero size & not hidden).
    
* ✅ **Stable**: Not moving or being animated.
    
* ✅ **Enabled**: Not disabled (for buttons, inputs).
    
* ✅ **Editable**: Can accept text input (for fill/type).
    
* ✅ **Receives events**: Not covered by another element and can be clicked.
    

You don’t need to `waitForSelector`, wait for a spinner, or `sleep()`—Playwright handles it all under the hood.

---

## 🔍 `page.waitForSelector(selector, options?)`

* **Purpose**: Pauses execution until an element matching the selector meets a specified state.
    
* **Default behavior**: Waits for the element to be **attached** and **visible**.
    
* **Options**:
    
    * `state: 'attached' | 'detached' | 'visible' | 'hidden'`
        
    * `timeout`: custom wait time in milliseconds.
        
* **Returns**: `ElementHandle` (or `null` if waiting for disappearance).
    

**Example**:

```bash
await page.click('button#load-more');
await page.waitForSelector('.item', { state: 'visible', timeout: 5000 });
// Now it's safe to interact with new items
```

Prefer using locators (`page.getBy...`) and assertions instead, which auto-wait for you.

## ⏱️ `page.waitForTimeout(ms)`

* **Purpose**: Simple delay—pauses the script for the specified milliseconds.
    
* **Use cases**: Rarely recommended except for debugging or simulating slow user input.
    

```bash
await page.waitForTimeout(2000); // wait 2 seconds
```

This is a “hard” wait and can lead to flakiness and wasted time.

## 🚦 `page.waitForLoadState(state?)`

* **Purpose**: Waits for the page to reach a certain loading milestone.
    
* **States**:
    
    * `'load'` (default): waits for `window.load`
        
    * `'domcontentloaded'`: waits for that event
        
    * `'networkidle'`: waits until no network connections for ~500ms (less reliable)
        
* **Example**:
    
* ```bash
      await page.goto('/dashboard');
      await page.waitForLoadState('domcontentloaded');
    ```
    
    ## ✅ Summary Table
    
    | Method / Event | Waits For | When to Use |
    | --- | --- | --- |
    | `page.goto(url, waitUntil)` | `'commit'`, `'domcontentloaded'`, `'load'`, or `'networkidle'` | On initial navigation, ensure correct load level. |
    | `page.reload()` | Same as `goto` | To refresh page state and resources. |
    | `page.goBack()` / `page.goForward()` | Navigation history, optionally wait for load state | Navigating between pages or flows. |
    | `page.waitForLoadState(state)` | DOM parsing, full load, or inactivity | Use after clicks/navigations in dynamic apps. |
    | `domcontentloaded` event | HTML parsed | Fast interactions or scripts post-DOM ready. |
    | `load` event | All page assets and scripts loaded | Full resource readiness. |
    | `networkidle` event | No network activity for ~500ms | SPA or AJAX-heavy page stability. |
    
    ## 🔹 9. Multi-page and Popup Handling in Playwright
    
    ---
    
    ### ✅ Use Case:
    
    Modern web applications may open:
    
    * A **new tab or window** (e.g., login with Google)
        
    * A **popup** on clicking a button or link
        
    
    You must handle these **new pages/contexts** properly to interact with their elements.
    
    ---
    
    ## 🔸 1. Handling Multiple Tabs or Windows
    
    In Playwright, a **new tab or window** is treated as a new `Page` object. You can listen for the `'popup'` event to detect this new page.
    
    ---
    
    ### 🔹 Example: Handling New Tab
    

```bash
import { test, expect, Page } from '@playwright/test';

test('Handle new tab or popup', async ({ browser }) => {
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://example.com');

  // Trigger the new tab
  const [newPage] = await Promise.all([
    page.waitForEvent('popup'), // Listen for new page
    page.click('a[target="_blank"]'), // Action that opens the new tab
  ]);

  // Interact with the new page
  await newPage.waitForLoadState();
  console.log(await newPage.title());
});
```

### 🧠 How This Works:

| Part | Explanation |
| --- | --- |
| `page.waitForEvent('popup')` | Waits until a new page is created via popup (like [`window.open`](http://window.open)`()` or `target="_blank"` link). |
| `Promise.all([...])` | Ensures we listen before the click triggers the popup, avoiding race conditions. |
| `newPage` | Represents the newly opened tab or window. |

## Frames

## 🔹 What are Frames & Iframes?

**Iframe (inline frame)** is an HTML element that allows embedding another HTML document within the current page.

Example:

```bash
<iframe src="https://example.com"></iframe>
```

In UI testing, interacting with content **inside iframes** needs special handling because iframe content is like a **separate page within a page**.

## 🔸 1. Locating and Interacting with Frames

There are **two primary ways** to work with frames in Playwright:

### ✅ A. `frameLocator()`: Locator API Style (Preferred for modern usage)

* Used to **interact with elements inside the iframe without switching context.**
    
* Similar to `locator()` but scoped to the iframe.
    
* ```bash
    await page
      .frameLocator('iframe[name="login-frame"]')
      .locator('text=Sign In')
      .click();
    ```
    
    ### ✅ B. `frame()`: Traditional way (Used when you need access to the whole frame as a Page)
    
    * First **get the frame** using `page.frame()` or `page.frames()`
        
    * Then use its own API like [`frame.click`](http://frame.click)`()`, `frame.locator()`, etc.
        
    

```bash
const frame = page.frame({ name: 'login-frame' }); // or use url/title

await frame?.click('text=Sign In');
```

## 🧠 Difference: `frameLocator()` vs `frame()`

| Feature | `frameLocator()` | `frame()` |
| --- | --- | --- |
| Style | Locator-style chaining | Traditional frame object |
| Use | Directly find and act on elements | Full control of frame API |
| Syntax | More concise & preferred | Verbose, more flexible |
| Async Access | Not required | Requires extracting frame object first |
| When to use | Simple interactions in frame | Advanced needs (e.g. looping frames, nested handling) |

## 🔸 2. `frameLocator()` – In-depth

### ✅ Syntax:

```bash
const locator = page.frameLocator(selector);
```

You can then call:

```bash
locator.locator('selector').click()
locator.locator('selector').fill()
```

✅ Example:

```bash
await page
  .frameLocator('iframe[src*="login"]')
  .locator('input[name="username"]')
  .fill('rahat');

await page
  .frameLocator('iframe')
  .locator('button[type="submit"]')
  .click();
```

## 🔸 3. `frame()` – In-depth

### ✅ Ways to access a frame:

```bash
const frameByName = page.frame({ name: 'my-frame' });
const frameByUrl = page.frame({ url: /.*login.*/ });
const allFrames = page.frames();
```

✅ Example:

```bash
const frame = page.frame({ name: 'login-frame' });
await frame?.fill('input[name="email"]', 'rahat@example.com');
await frame?.click('button[type="submit"]');
```

🔁 Example: Loop Through All Frames

```bash
for (const f of page.frames()) {
  console.log('Frame URL:', f.url());
}
```

## 🔸 4. Nested Iframes

You can nest `frameLocator()` calls:

```bash
await page
  .frameLocator('#outer-frame')
  .frameLocator('#inner-frame')
  .locator('text=Submit')
  .click();
```

## 🔸 5. Wait for Frame to be Available

Sometimes the iframe loads later via JS. You can wait for it:

```bash
await page.waitForSelector('iframe[name="my-frame"]');

const frame = await page.frame({ name: 'my-frame' });
await frame?.waitForSelector('input[name="email"]');
```

## ✅ Best Practices

| Tip | Description |
| --- | --- |
| Prefer `frameLocator()` | It’s more readable, chainable, and integrates better with locators |
| Always wait for iframe | If dynamically loaded, use `waitForSelector()` |
| Use frame URL or name | When using `frame()` to identify the frame |
| Avoid hard waits | Use auto-waiting like `waitForSelector()` inside frame |

## ✅ Real Example: Both Approaches

### Using `frameLocator()`

```bash
await page
  .frameLocator('iframe[name="editor-frame"]')
  .locator('textarea')
  .fill('Hello inside iframe');
```

Using `frame()`

```bash
const frame = page.frame({ name: 'editor-frame' });
await frame?.fill('textarea', 'Hello inside iframe');
```

## 🔚 Summary

| Topic | frameLocator() | frame() |
| --- | --- | --- |
| Purpose | Locator-style frame interaction | Full frame object access |
| Best for | Simpler tasks like click/fill | Complex frame handling |
| Syntax | `frameLocator('iframe').locator()` | `const frame = page.frame(...)` |
| Nesting | Supports `.frameLocator().frameLocator()` | Requires frame chaining manually |

## 🔸 Hook Overview

| 🔸 1. `beforeAll` and `afterAll` |
| --- |

These are used for **once-per-suite setup/teardown**.

### ✅ Example:

|  | Runs | Use Case |
| --- | --- | --- |
| `beforeAll` | Once before **all tests** in the file/group | Setup shared resources (e.g., DB, login) |
| `afterAll` | Once after **all tests** in the file/group | Cleanup (e.g., close DB, clear session) |
| `beforeEach` | Before **each individual test** | Fresh page, login, mocks |
| `afterEach` | After **each individual test** | Cleanup, logout, reset data |

## 🔸 1. `beforeAll` and `afterAll`

These are used for **once-per-suite setup/teardown**.

### ✅ Example:

```bash
import { test, expect, Browser, Page } from '@playwright/test';

let page: Page;

test.describe('User Tests', () => {
  test.beforeAll(async ({ browser }) => {
    const context = await browser.newContext();
    page = await context.newPage();
    await page.goto('https://example.com/login');
    await page.fill('#username', 'admin');
    await page.fill('#password', 'admin123');
    await page.click('button[type="submit"]');
  });

  test.afterAll(async () => {
    await page.close();
  });

  test('Dashboard loads correctly', async () => {
    await expect(page.locator('h1')).toHaveText('Dashboard');
  });

  test('Profile loads', async () => {
    await page.click('text=Profile');
    await expect(page.locator('h2')).toHaveText('Your Profile');
  });
});
```

## 🔸 2. `beforeEach` and `afterEach`

These run **before and after every test case**.

```bash
test.describe('Isolated Tests', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('https://example.com');
  });

  test.afterEach(async ({ page }) => {
    // Useful if you need to clear local storage or cookies
    await page.context().clearCookies();
  });

  test('Homepage loads', async ({ page }) => {
    await expect(page.locator('h1')).toHaveText('Welcome');
  });

  test('About page loads', async ({ page }) => {
    await page.click('text=About');
    await expect(page).toHaveURL(/.*about/);
  });
});
```
