[240106] TIL

playwright ๊ธฐ๋ณธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

์ฝ”๋“œ ์‹คํ–‰

 yarn playwright test stock.spec.ts
[Installation Playwright](https://playwright.dev/docs/intro)

Action

await page.goto("http://playwright.dev/");
[Page Playwright](https://playwright.dev/docs/api/class-page#page-goto)
  • ๊ธฐ๋ณธ ๋ฆฌ์†Œ์Šค ์‘๋‹ต์„ ๋ฐ˜ํ™˜

Interactions

// Create a locator
const getStarted = page.getByRole("link", { name: "Get started" });

// Click it
await getStarted.click();
Action Description
locator.check() Check the input checkbox
locator.click() Click the element
locator.uncheck() Uncheck the input checkbox
locator.hover() Hover mouse over the element
locator.fill() Fill the form field, input text
locator.focus() Focus the element
locator.press() Press single key
locator.setInputFiles() Pick files to upload
locator.selectOption() Select option in the drop down

locator

// 1. ๊ธฐ๋ณธ์ ์ธ locator ์‚ฌ์šฉ๋ฒ•
test("locator ์˜ˆ์ œ", async ({ page }) => {
  // text๋กœ ์ฐพ๊ธฐ
  page.locator("text=๋กœ๊ทธ์ธ");

  // CSS ์„ ํƒ์ž๋กœ ์ฐพ๊ธฐ
  page.locator(".login-button");
  page.locator("#username");

  // role๋กœ ์ฐพ๊ธฐ (์ ‘๊ทผ์„ฑ ๊ด€๋ จ)
  page.locator("role=button");

  // XPath๋กœ ์ฐพ๊ธฐ
  page.locator("xpath=//button");
});
  • ์ฒด์ด๋‹ ๊ฐ€๋Šฅ
  • ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์š”์†Œ ์ฐพ๊ธฐ ๊ฐ€๋Šฅ

Assertions

// Playwright ํ…Œ์ŠคํŠธ ์˜ˆ์ œ
test("๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ…Œ์ŠคํŠธ", async ({ page }) => {
  await page.goto("https://example.com/login");

  // assertions ์˜ˆ์‹œ๋“ค:

  // 1. ์ œ๋ชฉ์ด "๋กœ๊ทธ์ธ"์ด์–ด์•ผ ํ•œ๋‹ค
  await expect(page.locator("h1")).toHaveText("๋กœ๊ทธ์ธ");

  // 2. ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์ด ํŽ˜์ด์ง€์— ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค
  await expect(page.locator('button[type="submit"]')).toBeVisible();

  // 3. ์ด๋ฉ”์ผ ์ž…๋ ฅ๋ž€์ด ๋น„์–ด์žˆ์–ด์•ผ ํ•œ๋‹ค
  await expect(page.locator('input[type="email"]')).toBeEmpty();
});
Assertion Description
expect(locator).toBeChecked() Checkbox is checked
expect(locator).toBeEnabled() Control is enabled
expect(locator).toBeVisible() Element is visible
expect(locator).toContainText() Element contains text
expect(locator).toHaveAttribute() Element has attribute
expect(locator).toHaveCount() List of elements has given length
expect(locator).toHaveText() Element matches text
expect(locator).toHaveValue() Input element has value
expect(page).toHaveTitle() Page has title
expect(page).toHaveURL() Page has URL

Test lsolation

๊ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ์„œ๋กœ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์™„์ „ํžˆ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ์˜๋ฏธ

test.describe("๋กœ๊ทธ์ธ ์ƒํƒœ ํ…Œ์ŠคํŠธ", () => {
  test("๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ", async ({ page }) => {
    await page.goto("/login");
    await page.fill('input[name="email"]', "test@example.com");
    await page.fill('input[name="password"]', "password");
    await page.click('button[type="submit"]');
  });

  test("๋น„๋กœ๊ทธ์ธ ์ƒํƒœ ํ…Œ์ŠคํŠธ", async ({ page }) => {
    await page.goto("/profile");
    // ์ด์ „ ํ…Œ์ŠคํŠธ์—์„œ ๋กœ๊ทธ์ธํ–ˆ์ง€๋งŒ
    // ์ด ํ…Œ์ŠคํŠธ๋Š” ์ƒˆ๋กœ์šด ์ปจํ…์ŠคํŠธ์—์„œ ์‹œ์ž‘๋˜๋ฏ€๋กœ
    // ๋กœ๊ทธ์ธ๋˜์ง€ ์•Š์€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค
    await expect(page.locator(".login-required")).toBeVisible();
  });
});

โ†’ ๊ฐ ๊ฒฉ๋ฆฌ๋œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ

test.describe

// ๐Ÿ™…โ€โ™‚๏ธ describe ์—†์ด ์ž‘์„ฑ
test("๋กœ๊ทธ์ธ ์„ฑ๊ณต", async ({ page }) => {
  /* ... */
});
test("๋กœ๊ทธ์ธ ์‹คํŒจ", async ({ page }) => {
  /* ... */
});
test("ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต", async ({ page }) => {
  /* ... */
});
test("ํšŒ์›๊ฐ€์ž… ์‹คํŒจ", async ({ page }) => {
  /* ... */
});

// ๐Ÿ‘ describe๋กœ ๊ตฌ์กฐํ™”
test.describe("๋กœ๊ทธ์ธ", () => {
  test("์„ฑ๊ณต", async ({ page }) => {
    /* ... */
  });
  test("์‹คํŒจ", async ({ page }) => {
    /* ... */
  });
});

test.describe("ํšŒ์›๊ฐ€์ž…", () => {
  test("์„ฑ๊ณต", async ({ page }) => {
    /* ... */
  });
  test("์‹คํŒจ", async ({ page }) => {
    /* ... */
  });
});

โ†’ ํŠน๋ณ„ํ•œ ๊ธฐ๋Šฅ๋ณด๋‹ค๋Š” ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์œ„ํ•œ ๊ตฌ์กฐํ™” ๋„๊ตฌ

Using Test Hooks

ํ…Œ์ŠคํŠธ ์ „/ํ›„์— ํŠน์ • ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ

ํ…Œ์ŠคํŠธ ์„ค์ •์ด๋‚˜ ์ •๋ฆฌ ์ž‘์—…์— ์‚ฌ์šฉ

import { test, expect } from "@playwright/test";

test.describe("์‡ผํ•‘๋ชฐ ํ…Œ์ŠคํŠธ", () => {
  // 1. beforeAll: ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰
  test.beforeAll(async () => {
    // ์˜ˆ: ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์„ธํŒ…
    await setupTestDatabase();
  });

  // 2. beforeEach: ๊ฐ ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „๋งˆ๋‹ค ์‹คํ–‰
  test.beforeEach(async ({ page }) => {
    // ์˜ˆ: ๋กœ๊ทธ์ธ ์ƒํƒœ๋กœ ์‹œ์ž‘
    await page.goto("/login");
    await page.fill("#email", "test@example.com");
    await page.fill("#password", "password");
    await page.click('button[type="submit"]');
  });

  // ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋“ค
  test("์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ถ”๊ฐ€", async ({ page }) => {
    // ์ด๋ฏธ ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ์—์„œ ์‹œ์ž‘
    await page.goto("/products");
    await page.click(".add-to-cart");
  });

  // 3. afterEach: ๊ฐ ํ…Œ์ŠคํŠธ ์ข…๋ฃŒ ํ›„๋งˆ๋‹ค ์‹คํ–‰
  test.afterEach(async ({ page }) => {
    // ์˜ˆ: ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋น„์šฐ๊ธฐ
    await page.goto("/cart");
    await page.click(".clear-cart");
  });

  // 4. afterAll: ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ข…๋ฃŒ ํ›„ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰
  test.afterAll(async () => {
    // ์˜ˆ: ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ •๋ฆฌ
    await cleanupTestDatabase();
  });
});

์†Œ๋ฐํด ํ”„๋กœ์ ํŠธ

๊ธฐํƒ€

  • ์š”๊ฐ€
  • ๋งํ•ด๋ณด์นด

Categories:

Updated:

Leave a comment