[์ง๊ธ ๋ฌด๋ฃ]Playwright ๊ธฐ์ด - ๊ธฐ์ด์ ์ธ ํ์ฉ๋ฒ๊ณผ ํต์ฌ ์๋ฆฌ ๊ฐ์ | duckyoung lee - ์ธํ๋ฐ
duckyoung lee | , [์ฌ์ง]Playwright ๊ธฐ์ด ๊ฐ์Playwright ๊ธฐ์ด ๊ฐ์์น ์ดํ๋ฆฌ์ผ์ด์ E2E ํ ์คํธ ํ๋ ์์ํฌ์ธ Playwright์ ๊ธฐ์ด์ ์ธ ํ์ฉ๋ฒ๊ณผ ํต์ฌ ์๋ฆฌ๋ฅผ ๋ฐฐ์๋๋ค.์ด๋ฐ ๋ถ๋ค๊ป ์ถ์ฒํด์E2Eํ ์คํธ๊ฐ ์ฒ์์ด
www.inflearn.com
๐ ํ๋ก์ ํธ ์ค์
๐ npm init playwright@latest
ใด Playwright๋ ์น ์๋ํ ํ ์คํธ ๋๊ตฌ (E2E ํ ์คํธ์ ์ฌ์ฉ๋จ)
ใด ์ด ๋ช ๋ น์ด๋ Playwright๋ฅผ ์ํ ๊ธฐ๋ณธ ์ค์ ๊ณผ ์ํ ํ ์คํธ ํ์ผ์ ์์ฑ
๐ npx playwright test
ใด Playwright ํ ์คํธ ์คํ
ใด CLI ์์์ ํ ์คํธ ๊ฒฐ๊ณผ ์ถ๋ ฅ
ใด playwright-report/ ํด๋์ HTML ๋ฆฌํฌํธ๋ ์์ฑ
package.json์ scripts์ ๋ค์์ฒ๋ผ ์ถ๊ฐ
"scripts": {
"test": "npx playwright test"
}
๊ทธ ์ดํ๋ถํฐ๋ ์๋ ๋ช ๋ น์ด๋ง์ผ๋ก ํ ์คํธ ์คํ ๊ฐ๋ฅ
npm run test

๊ทธ ํ, VS Code์์ Playwright Test for VSโฏCode ํ์ฅ ์ค์น
1. ํ ์คํธ ํ์ & ์คํ
- ์ฌ์ด๋๋ฐ์์ ํ ์คํธ ํ์ผ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ํ์ธ
- ๊ฐ๋ณ ํ ์คํธ ๋๋ ์ ์ฒด ์คํ ๋ฒํผ ํด๋ฆญ
- Projects ์น์ ์์ ์ํ๋ ๋ธ๋ผ์ฐ์ ๋ง ์ ํํ์ฌ ์คํ
2. ์๊ฐ์ ๋๋ฒ๊น
- "Show browser" ์ฒดํฌ → ํ ์คํธ ์คํ ๊ณผ์ ์ ์ค์ ๋ก ๋ณผ ์ ์์
- "Show trace viewer" ์ฒดํฌ → ์คํ ํ ํ์๋ผ์ธ์ผ๋ก ๋ถ์ ๊ฐ๋ฅ
3. ์ฝ๋ ์์ฑ & Locator ์ฐพ๊ธฐ
- Pick locator: ๋ธ๋ผ์ฐ์ ์์ ์์ ํด๋ฆญ → selector ์๋ ์์ฑ
- Record new: ๋ธ๋ผ์ฐ์ ์กฐ์ → ํ ์คํธ ์ฝ๋ ์๋ ์์ฑ
- Locator ํธ์ง ํ ๋ธ๋ผ์ฐ์ ์์ ํ์ด๋ผ์ดํธ๋ก ์ฆ์ ํ์ธ
4. ์คํจ ๋ถ์
- ํ ์คํธ ์คํจ ์ ํด๋น ์ง์ ํด๋ฆญ → ๋ธ๋ ์ดํฌํฌ์ธํธ ์ค์
- ๋ผ์ด๋ธ ๋๋ฒ๊ทธ ๋ชจ๋๋ก ๋จ๊ณ๋ณ ์คํ ๋ฐ ๋ณ์ ํ์ธ
- Trace Viewer๋ก ์คํจ ์๊ฐ์ ์คํฌ๋ฆฐ์ท, ๋คํธ์ํฌ ๋ก๊ทธ ๋ฑ ๋ถ์
๐ ๊ธฐ์ด ์์
๐ก ๋ค๋น๊ฒ์ด์ ํ ์คํธ ์์ฑํ๊ธฐ
import { test, expect } from '@playwright/test';
test('if user visit home and click "Get Started", h1 "introduction" is visible and page title is contains "Introduction"', async ({page}) => {
const startUrl = 'https://nextjs.org/';
const h1 = "Next.js Docs";
const title = /Docs/;
await page.goto(startUrl);
await page.getByRole('link', { name: 'Get Started' }).click();
await expect(page.getByRole('heading', { name: h1, level: 1 })).toBeVisible();
await expect(page).toHaveTitle(title);
});
๐ก ๋ฒํผ ํด๋ฆญ ํ ์คํธ ์์ฑํ๊ธฐ
import {test, expect} from '@playwright/test';
test.describe('button click', () => {
test('open preferences menu', async ({page}) => {
const startUrl = 'http://localhost:3000/';
await page.goto(startUrl);
await test.step('if click next.js icon, show dropdown menu', async () => {
await page.getByRole('button', { name: 'Open Next.js Dev Tools'}).click();
await expect(page.getByText('Preferences')).toBeVisible();
});
await test.step('if click preferences, show preferences menu', async () => {
await page.getByText('Preferences').click();
await expect(page.getByRole('heading', {name: 'Preferences'})).toBeVisible();
});
})
})
๐ก ์ ์ถ ์์ ํ ์คํธ ์์ฑํ๊ธฐ
import { test, expect } from '@playwright/test';
test.describe('sign-up', () => {
test.describe('validation', () => {
test('if select plan type and fill name, submit enabled', async ({page}) => {
const startUrl = 'https://vercel.com/signup';
await page.goto(startUrl);
await page.getByText("I'm working on personal projects").click();
await page.getByLabel('Your Name').fill('input content');
await expect(page.getByRole('button', {name: 'Continue'})).toBeEnabled();
});
});
});
๐ ํต์ฌ ๊ฐ๋
package.json์ scripts์ ๋ค์์ฒ๋ผ ์์ ์, ui ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅ
"scripts": {
"test": "npx playwright test --ui"
}

โ ui ๋ชจ๋ ์ฃผ์ ๋ชฉ์
- ํ ์คํธ ํ์, ์ ํ, ์คํ์ GUI๋ก ์ ์ด
- ํ ์คํธ์ ํ์คํ ๋ฆฌ์ ๊ฐ ๋จ๊ณ์ ์ค๋ ์ท ํ์ธ
โ ui ๋ชจ๋์์ ํ ์ ์๋ ์ผ
- ์ ์ฒด ํ ์คํธ ๋ชฉ๋ก์ ์๊ฐ์ ์ผ๋ก ํ์
- ํน์ ํ ์คํธ๋ง ์ ํํ์ฌ ์คํ
- ํ ์คํธ ์คํ ์ค ๋จ๊ณ๋ณ ์ค๋ ์ท ์๋ ๊ธฐ๋ก
- ๊ฐ ๋จ๊ณ๋ณ locator, assert, click ๋ฑ ์์ ๋ณ ์ํ ํ์ธ
- ์คํจํ ํ ์คํธ์ DOM ์ํ, ์๋ฌ ๋ก๊ทธ, ์คํฌ๋ฆฐ์ท ํ์ธ
- ์ฌ์คํ ๋ฐ ๋๋ฒ๊น ๋ชจ๋ ์ ํ ๊ฐ๋ฅ
โ ui ๋ชจ๋ ํน์ง
- ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ๋จ๋ฉฐ, GUI ๋๊ตฌ๊ฐ ํจ๊ป ์ด๋ฆผ
- ํ ์คํธ ์ ๋ฐ์ ์ธ ํ๋ฆ์ ๊ด๋ฆฌํ๊ณ ์ ํ ๋ ์ ํฉ
- ์ธํฐ๋ํฐ๋ธํ๊ฒ ๊ฐ๋ฐ์์ฉ GUI์์ ํ์ธํ๊ณ ์ถ์ ๊ฒฝ์ฐ ์ ์ฉ
package.json์ scripts์ ๋ค์์ฒ๋ผ ์์ ์, debug ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅ
"scripts": {
"test": "npx playwright test --debug"
}

โ debug ๋ชจ๋ ์ฃผ์ ๋ชฉ์
- ํน์ ํ ์คํธ๋ฅผ ์ค๊ฐ์ ๋ฉ์ถ๊ณ ํ ๋จ๊ณ์ฉ ์๋ ์กฐ์
- ๋๋ฒ๊น ๋๊ตฌ(Playwright Inspector)๋ฅผ ์ด์ด ๋ด๋ถ ์ํ ๋ถ์
โ debug ๋ชจ๋์์ ํ ์ ์๋ ์ผ
- ํ ์คํธ ์ค๋จ์ (pause) ์ํ์์ ์์
- ํ ์คํธ ํ๋ฆ์ ํ ๋จ๊ณ์ฉ ์๋์ผ๋ก ์คํ
- ๊ฐ ๋ช ๋ น์ด์ Locator ๊ฒฐ๊ณผ, ์ํ, Timeout ๋ฑ์ ํ์ธ
- ์ค์๊ฐ DOM ์ํ ๊ด์ฐฐ ๋ฐ ์กฐ์ ๊ฐ๋ฅ
- ํ์ํ ๊ฒฝ์ฐ page.pause(), debug() ๋ฑ ์ฝ๋์ ์ง์ ์ฝ์ ๊ฐ๋ฅ
โ debug ๋ชจ๋ ํน์ง
- ์๋ ์คํ๋ณด๋จ ์ค๊ฐ ๊ฐ์ ์ด ํ์ํ ๋๋ฒ๊น ์ ์ ํฉ
- ์ฝ์์์ ์ง์ ์์ ์ํ ํ์ธ, ๋ค์ ์๋, ์์ ๋ฑ์ ํ ์ ์์
- ๋ฐ๋ณต ์คํจ ๊ตฌ๊ฐ์ ์ ๋ฐํ๊ฒ ํ์ ํ๊ณ ์ ํ ๋ ์ ์ฉ

๋ํ, debug ๋ชจ๋ ์คํ ์ ์๋์ผ๋ก ๋จ๋ Playwright Inspector ์ฐฝ ์์์ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ ์ ๊ณต
โ [Pick Locator] ๋ฒํผ
- ์น ํ์ด์ง์์ ํ ์คํธํ๊ณ ์ถ์ ์์๋ฅผ ํด๋ฆญํ๋ฉด, Playwright๊ฐ ์ต์ ์ Locator ์ฝ๋๋ฅผ ์๋ ์์ฑ
- getByRole, getByText, locator() ๋ฑ ๊ฐ์ฅ ์์ ์ ์ด๊ณ ์๋ฏธ ์๋ ๋ฐฉ์์ผ๋ก ์ถ์ฒ
- QA ์์ง๋์ด๋ ๋น๊ฐ๋ฐ์๋ ์ง์ CSS/XPath ๊ณ ๋ฏผ ์ ํ๊ณ ์์ ์ ํ ๊ฐ๋ฅ
- ๋ถ์์ ํ XPath ๋์ ์์ ์ ์ธ Locator ์ถ์ถ์ ์ฌ์ฉ
โ [Record] ๋ฒํผ
- ์ง์ ํ ์คํธ๋ฅผ ์ํํ๋ ๊ฒ๋ง์ผ๋ก ์ฝ๋๊ฐ ์๋ ์์ฑ๋จ
- ๋ฒํผ ํด๋ฆญ → ์นํ์ด์ง์์ ํด๋ฆญ/์ ๋ ฅ/์ ํ ๋ฑ ์ํ → Playwright๊ฐ click(), fill(), navigate() ๋ฑ ํ ์คํธ ์ฝ๋๋ก ์๋ ๊ธฐ๋ก
- ๋น๊ฐ๋ฐ์ QA ํ์์ด ํ ์คํธ ํ๋ฆ์ ์ง์ ๋ฐ๋ผ๊ฐ๋ฉด์ ์๋๋ฆฌ์ค ๊ธฐ๋ก ๊ฐ๋ฅ
- ํ ์คํธ ์ฝ๋ ์์ฑ์ ์๋ํํ๊ฑฐ๋, ์ด์์ผ๋ก ๋น ๋ฅด๊ฒ ๋ง๋ค๊ณ ์ถ์ ๊ฒฝ์ฐ ์ฌ์ฉ ๊ฐ๋ฅ
๐ ํ์ API
๐ก Locator
Locators | Playwright
Introduction
playwright.dev
- page.getByRole()
ใด ๋ช ์์ ๋๋ ์์์ ์ธ ์ ๊ทผ์ฑ ์์ฑ(role ๋ฑ)์ ๊ธฐ๋ฐ์ผ๋ก ์์๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ - page.getByText()
ใด ํ ์คํธ ๋ด์ฉ์ ๊ธฐ์ค์ผ๋ก ์์๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ - page.getByLabel()
ใด ์ฐ๊ด๋ label ํ ์คํธ๋ฅผ ๊ธฐ์ค์ผ๋ก form control ์์(์: input, textarea ๋ฑ)๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ - page.getByPlaceholder()
ใด placeholder ์์ฑ์ ๊ธฐ์ค์ผ๋ก input ์์๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ - page.getByAltText()
ใด ๋์ฒด ํ ์คํธ(alt ์์ฑ)๋ฅผ ๊ธฐ์ค์ผ๋ก ์์(์ฃผ๋ก ์ด๋ฏธ์ง)๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ - page.getByTitle()
ใด title ์์ฑ์ ๊ธฐ์ค์ผ๋ก ์์๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ - page.getByTestId()
ใด data-testid ์์ฑ(๋๋ ์ค์ ํ ๋ค๋ฅธ ์์ฑ)์ ๊ธฐ์ค์ผ๋ก ์์๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ
๐ก Actions
Actions | Playwright
Introduction
playwright.dev
- page.click()
ใด ์ง์ ํ ์ ๋ ํฐ์ ์์๋ฅผ ํด๋ฆญํ๋ ๋ฐฉ๋ฒ - page.fill()
ใด input, textarea ๋ฑ ์ ๋ ฅ ํ๋์ ๋ฌธ์์ด์ ์ ๋ ฅํ๋ ๋ฐฉ๋ฒ (๊ธฐ์กด ๊ฐ์ ์๋ ์ญ์ ) - page.type()
ใด ํค๋ณด๋ ์ ๋ ฅ์ ํ ๊ธ์์ฉ ์๋ฎฌ๋ ์ด์ ํ๋ ๋ฐฉ๋ฒ (์ ๋ ฅ ์๋ ์กฐ์ ๊ฐ๋ฅ) - page.press()
ใด ํค๋ณด๋์ ํน์ ํค(Enter, Tab ๋ฑ)๋ฅผ ๋๋ฅด๋ ๋์์ ์ํํ๋ ๋ฐฉ๋ฒ - page.check()
ใด ์ฒดํฌ๋ฐ์ค๋ฅผ ์ฒดํฌ ์ํ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ - page.uncheck()
ใด ์ฒดํฌ๋ฐ์ค๋ฅผ ์ฒดํฌ ํด์ ์ํ๋ก ๋ง๋๋ ๋ฐฉ๋ฒ - page.selectOption()
ใด `<select>` ์์์์ ํน์ ์ต์ ์ ์ ํํ๋ ๋ฐฉ๋ฒ - page.focus()
ใด ํน์ ์์์ ํฌ์ปค์ค๋ฅผ ์ฃผ๋ ๋ฐฉ๋ฒ - page.tap()
ใด ๋ชจ๋ฐ์ผ ํ๊ฒฝ์์ ํฐ์น ์ด๋ฒคํธ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๋ ๋ฐฉ๋ฒ - page.dragAndDrop()
ใด ํ ์์๋ฅผ ๋ค๋ฅธ ์์๋ก ๋๋๊ทธ ์ค ๋๋กญํ๋ ๋ฐฉ๋ฒ
๐ก Events
Events | Playwright
Introduction
playwright.dev
- page.on('request', handler)
ใด HTTP ์์ฒญ ๋ฐ์ ์ ์คํํ ์ฝ๋ฐฑ ๋ฑ๋ก ๋ฐฉ๋ฒ. - page.on('response', handler)
ใด ์๋ฒ ์๋ต ์์ ์ ์คํํ ์ฝ๋ฐฑ ๋ฑ๋ก ๋ฐฉ๋ฒ. - page.on('requestfailed', handler)
ใด ์์ฒญ ์คํจ ์ ์คํํ ์ฝ๋ฐฑ ๋ฑ๋ก ๋ฐฉ๋ฒ. - page.on('dialog', handler)
ใด alert/prompt/confirm ์ฐฝ ๋ฐ์ ์ ์ฝ๋ฐฑ ๋ฑ๋ก ๋ฐฉ๋ฒ. - page.on('popup', handler)
ใด ์ ์ฐฝ์ด๋ ํญ์ด ์ด๋ฆด ๋ ์ฝ๋ฐฑ ๋ฑ๋ก ๋ฐฉ๋ฒ. - page.on('pageerror', handler)
ใด JS ์ค๋ฅ ๋ฐ์ ์ ์คํํ ์ฝ๋ฐฑ ๋ฑ๋ก ๋ฐฉ๋ฒ.
๐ก Assertions
Assertions | Playwright
Introduction
playwright.dev
- await expect(locator).toBeVisible()
ใด ์์์ ๊ฐ์์ฑ์ ํ์ธํ๋ ๋ฐฉ๋ฒ. - await expect(locator).toHaveText(textOrRegex)
ใด ์์๊ฐ ํน์ ํ ์คํธ๋ฅผ ํฌํจํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ. - await expect(locator).toHaveAttribute(name, valueOrRegex)
ใด ์์์ ํน์ ์์ฑ(attribute) ๊ฐ์ ๊ฒ์ฆํ๋ ๋ฐฉ๋ฒ. - await expect(page).toHaveURL(urlOrRegex)
ใด ํ์ฌ ํ์ด์ง์ URL์ด ์์ํ ๊ฐ๊ณผ ์ผ์นํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ. - await expect(page).toHaveTitle(titleOrRegex)
ใด ํ์ฌ ํ์ด์ง์ ํ์ดํ์ด ์์๊ณผ ์ผ์นํ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ. - await expect(response).toBeOK()
ใด ๋คํธ์ํฌ ์๋ต์ด 2xx ์ํ์ธ์ง ํ์ธํ๋ ๋ฐฉ๋ฒ.
๐ ํ ์คํธ ์์ฑ ๊ธฐ๋ฅ
Playwright์ ๊ณต์ VS Code ํ์ฅ์ธ Playwright Test for VS Code๋ฅผ ์ค์นํ๋ฉด, ์ฌ์ด๋๋ฐ์ [Record New] ๋ฒํผ์ด ์๊ธด๋ค. ์ด ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์๋ก์ด ํ ์คํธ ํ์ผ์ด ์๋์ผ๋ก ์์ฑ๋๊ณ , ๋ธ๋ผ์ฐ์ ์ฐฝ์ด ํจ๊ป ์ด๋ฆฐ๋ค. ์ด ์ฐฝ์์ ์ฌ์ฉ์๊ฐ ์น์ฌ์ดํธ๋ฅผ ๋ฐฉ๋ฌธํ๊ณ ๋ฒํผ์ ํด๋ฆญํ๊ฑฐ๋ ํ ์คํธ๋ฅผ ์ ๋ ฅํ๋ ๋ฑ, ์ํํ๋ ๋ชจ๋ ๋์์ด ์๋์ผ๋ก ๊ธฐ๋ก๋๋ค. ์๋ฅผ ๋ค์ด, ํํ์ด์ง์ ์ ์ํด ๋ก๊ทธ์ธ ๋ฒํผ์ ํด๋ฆญํ๊ณ ์ ๋ ฅ์ฐฝ์ ํ ์คํธ๋ฅผ ์ ๋ ฅํ๋ฉด, ํด๋น ํ๋์ด ๊ทธ๋๋ก Playwright ํ ์คํธ ์ฝ๋๋ก ๋ณํ๋์ด ํ ์คํธ ํ์ผ์ ์๋ ์ ๋ ฅ๋๋ค.
์ด ์ธ์๋ [Record at cursor] ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด, ์ด๋ฏธ ์์ฑ ์ค์ธ ํ ์คํธ ์ฝ๋์์ ์ปค์ ์์น ์ดํ๋ถํฐ ๋ นํ๋ฅผ ์์ํ ์ ์์ด ์ค๊ฐ์ ํ ์คํธ ์๋๋ฆฌ์ค๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ด์ด์ ์์ฑํ ๋ ์ ์ฉํ๋ค. ๋ํ [Pick Locator] ๊ธฐ๋ฅ์ ์์ ์ดํด๋ณธ ๋๋ฒ๊ทธ ๋ชจ๋์ ๋ง์ฐฌ๊ฐ์ง๋ก, ํ๋ฉด์์ ํน์ ์์๋ฅผ ํด๋ฆญํ๋ฉด ๊ฐ์ฅ ์ ์ ํ locator๋ฅผ ์๋์ผ๋ก ์ถ์ถํด์ฃผ๋ ๊ธฐ๋ฅ์ผ๋ก, ์ ํํ๊ณ ์์ ์ ์ธ ์์ ์ ํ์ ๋งค์ฐ ๋์์ด ๋๋ค.
'๐ Additional > ๐ Playwright' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Playwright ๊ตฌ์กฐ ๋ฏ์ด๋ณด๊ธฐ (11) | 2025.11.24 |
|---|
