Playwright๋ Microsoft์์ ๋ง๋ ์คํ์์ค E2E(End-to-End) ํ ์คํธ ํ๋ ์์ํฌ๋ก, ์ค์ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์ ์ฌ์ฉ์์ ํ๋์ ๊ทธ๋๋ก ์๋ฎฌ๋ ์ด์ ํ๋ ๋ฐ ์ด์ ์ ๋ง์ถ๊ณ ์๋ค. Chromium, Firefox, WebKit ๋ฑ ์ฃผ์ ๋ ๋๋ง ์์ง์ ๋ชจ๋ ์ง์ํ๋ฉฐ, ๋ฉํฐ ๋ธ๋ผ์ฐ์ ํ ์คํธ๋ฅผ ๋จ์ผ ์ฝ๋๋ฒ ์ด์ค๋ก ์ํํ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค.
๋น๊ต ํญ๋ชฉ | Playwright | Cypress | Selenium |
---|---|---|---|
๋ฉํฐ ๋ธ๋ผ์ฐ์ ์ง์ | โ Chromium, Firefox, WebKit | ๐ซ Chrome ์ค์ฌ | โ ๋ชจ๋ ๋ธ๋ผ์ฐ์ |
๋ฉํฐ ํญ/์ฐฝ ์ ์ด | โ ๊ฐ๋ฅ | ๐ซ ๋ถ๊ฐ๋ฅ | โ ๊ฐ๋ฅ |
๋คํธ์ํฌ ์์ฒญ ๊ฐ๋ก์ฑ๊ธฐ | โ ์ฌ์ | ๐ธ ์ ํ์ | ๐ธ ๋ฒ๊ฑฐ๋ก์ |
์๋ ๋๊ธฐ(Auto-Wait) | โ ๊ธฐ๋ณธ ๋ด์ฅ | ๐ซ ์ง์ ์ฒ๋ฆฌ | ๐ซ ์ง์ ์ฒ๋ฆฌ |
์๋ | โก ๋น ๋ฆ | โก ๋น ๋ฆ | ๐ข ์๋์ ์ผ๋ก ๋๋ฆผ |
์ค์น/์ ์ | โก ๊ฐํธ | โก ๊ฐํธ | ๐ต ๋ณต์กํ ์ ์์ |
๋ฉํฐ ๋ธ๋ผ์ฐ์ ์ง์์๋ ๊ฐ๋ ฅํ ๊ฐ์ ์ ๊ฐ์ง๊ณ ์์ง๋ง, ์์์ ์ฒ๋ผ Playwright๋ง์ด ๊ฐ์ง๊ณ ์๋ Auto-wait ๊ธฐ๋ฅ์ ๋ํด์ ์์๋ณด๊ณ ์ ํ๋ค. ํ ์คํธ ๋์ค ํํ ๊ฒช๋ ํ์ด๋ฐ ๋ฌธ์ ๋ฅผ ์ค์ฌ์ฃผ๋ฉฐ, ์์ ์ ์ด๊ณ ์ ๋ขฐ๋ ๋์ ํ ์คํธ ์์ฑ์ด ๊ฐ๋ฅํ๋ค.
Playwright์ ํต์ฌ ๊ธฐ๋ฅ ์ค ํ๋์ธ Auto-Waiting์ ์ฌ์ฉ์์ ๋ช
๋ น (click, fill, goto ๋ฑ)์ ์คํํ ๋, DOM ์ํ๊ฐ ์์ ํ๊ณ ์คํ ๊ฐ๋ฅํ ์ํ๊ฐ ๋ ๋๊น์ง ์๋์ผ๋ก ๊ธฐ๋ค๋ ค์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค. ์ฆ, ์ฌ์ฉ์๊ฐ ๋ณ๋๋ก waitFor
ํจ์๋ฅผ ์์ฑํ์ง ์์๋, Playwright๋ ์ ์ ํ ํ์ด๋ฐ์ ์ค์ค๋ก ํ๋จํด์ค๋ค.
Playwright๊ฐ ์ด๋ค element๋ฅผ ํด๋ฆญํ๊ฑฐ๋ ์ ๋ ฅํ๊ธฐ ์ ์ ํ์ธํ๋ ์กฐ๊ฑด๋ค์ด ์๋ค. ๋ฐ๋ก Actionability checks๋ผ๊ณ ๋ถ๋ฆฌ๋ ๊ฒ๋ค์ด๋ค. ์ด๊ฒ ๋ฐ๋ก Auto-Waiting์ ํต์ฌ์ด๋ค.
๐ฏ ์๋ฅผ ๋ค์ด page.click(selector)
ํธ์ถ ์, Playwright๋ ๋ค์์ ํ์ธํ๋ค.
- Element๊ฐ DOM์ ์กด์ฌํ๋๊ฐ? (attached)
- ๋ณด์ด๋๊ฐ? (visible)
- ์ธ ์ ์๋ (ํ์ฑํ) ์ํ์ธ๊ฐ? (enabled)
- ์คํฌ๋กค์ด ํ์ํ๊ฐ? (in viewport)
- ๋ค๋ฅธ ์์์ ์ ๊ฐ๋ ค์ก๋๊ฐ? (not obscured)
์ด ๋ชจ๋ ์กฐ๊ฑด์ ๋ง์กฑํ ๋๊น์ง, Playwright๋ ๊ธฐ๋ค๋ฆฐ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ง์กฑ๋๋ ์๊ฐ, click
์ด๋ฒคํธ๋ฅผ ๋ณด๋ธ๋ค.
์ด๊ฑธ Actionability model์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
Playwright๋ ๋ด๋ถ์ ์ผ๋ก WebSocket์ ํตํด ๋ธ๋ผ์ฐ์ ์ ์ค์๊ฐ์ผ๋ก ์ฐ๊ฒฐ๋ ์ํ์์ ๋ช ๋ น์ ์ฃผ๊ณ ๋ฐ๋๋ค. ์ด ์ฐ๊ฒฐ์ ํตํด DOM ์ํ๋ฅผ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ , ๋ณํ๊ฐ ๊ฐ์ง๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.
page.click()
๊ฐ์ ๋ช
๋ น์ ๋ด๋ถ์ ์ผ๋ก JavaScript Promise๋ก ๊ตฌํ๋์ด ์์ผ๋ฉฐ, actionability ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๊ธฐ ์ ๊น์ง resolve๋์ง ์๋๋ค.
์กฐ๊ฑด์ ์ฒดํฌํ๊ธฐ ์ํด ๋ธ๋ผ์ฐ์ ๋ด์์ ์๋์ ๊ฐ์ด DOM ๋ณํ ๊ฐ์ง๋ฅผ ํ์ฌ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋์ง ํ๋จํ๋ค๊ณ ํ๋ค.
- MutationObserver: DOM ๊ตฌ์กฐ ๋ณํ ๊ฐ์ง
- IntersectionObserver: ์์์ ํ๋ฉด ๋ด ๋ ธ์ถ ์ฌ๋ถ ํ์ธ
- ์ฃผ๊ธฐ์ polling: ์กฐ๊ฑด ์ถฉ์กฑ ์ฌ๋ถ ์ ๊ฒ
์๋ฅผ ๋ค์ด, page.click('#submit')
๋ ๋ค์๊ณผ ๊ฐ์ ํ๋ฆ์ ๋ฐ๋ฅธ๋ค.
await page.waitForSelector('#submit'); // ์กด์ฌ ํ์ธ
await ensureActionable('#submit'); // visibility, enabled ๋ฑ ์ฒดํฌ
await scrollIntoView('#submit'); // ์คํฌ๋กค ์กฐ์
await page.click('#submit'); // ์ค์ ํด๋ฆญ ์คํ
}
Playwright๋ ์ด๋ฐ ์์ผ๋ก, wait โ check โ ์คํ ํจํด์ ์๋ํํด๋์๋ค.
๋จ์ํ click()
์ ํธ์ถํฌ์ ๋ฟ์ธ๋ฐ, ์ด ๋ชจ๋ ๊ณผ์ ์ ๋ช
์์ ์ผ๋ก ์์ฑํ์ง ์์๋ Playwright๊ฐ ์๋์ผ๋ก ๊ธฐ๋ค๋ฆฌ๊ณ ํ๋จํ๋ค.
E2E ํ
์คํธ์ ๊ฐ์ฅ ํฐ ์ ์ Flaky Test, ์ฆ ๊ฐํ์ ์คํจ๋ผ๊ณ ํ๋ค. ์ด๋ ๋๋ถ๋ถ DOM์ด ์์ง ์ค๋น๋์ง ์์๋๋ฐ ๋์์ ์๋ํ๋ฉด์ ๋ฐ์ํ๋ค.
Playwright๋ ์ด๋ฐ ํ์ด๋ฐ ์ด์๋ฅผ ๋ฐฉ์งํด ํ
์คํธ์ ์ ๋ขฐ๋์ ์์ ์ฑ์ ๋์ฌ์ค๋ค.
๊ธฐ์กด์๋ waitForSelector
, waitForTimeout
๋ฑ์ ์๋์ผ๋ก ์์ฑํด์ผ ํ์ง๋ง, Playwright๋ ์ด ๊ณผ์ ์ ๋ด๋ถ์ ์ผ๋ก ์ฒ๋ฆฌํด์ค๋ค.
โ ๋ ์ ์ ์ฝ๋๋ก ๋ ๋ง์ ์์ ์ฑ์ ํ๋ณดํ ์ ์๋ค.
Playwright์ Auto-Waiting์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ณธ์ ์ธ ์ํธ์์ฉ ๋์์ ๋ํด์๋ง ๋์ํ๋ค๊ณ ํ๋ค.
- click, dblclick
- fill, type, press
- check, uncheck
- hover
- selectOption
- setInputFiles
- goto, waitForNavigation, reload
โ ํ์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์๋ ์๋ ๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค.
์ํฉ | ๋๊ธฐ ํจ์ ์์ |
---|---|
๋ฐ์ดํฐ ๋ก๋ฉ ์๋ฃ ํ์ธ | page.waitForResponse() |
ํน์ ํ ์คํธ ๋ ๋๋ง ๋๊ธฐ | page.waitForSelector('text=์๋ฃ') |
์ ๋๋ฉ์ด์ ์ข ๋ฃ ํ์ธ | page.waitForFunction(() => !isAnimating) |
API ์๋ต ์๋ฃ | page.waitForResponse(res => res.url().includes('/api') && res.status() === 200) |
์ด๋ด ๋ ์ฌ์ ํ page.waitForFunction()
, page.waitForResponse()
, page.waitForSelector()
๊ฐ์ ์๋ ๋๊ธฐ๊ฐ ํ์ํ๋ค. ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด Auto-waiting์ด ์ง์๋์ง ์๋ ๊ฒฝ์ฐ์ผ ์ ์์ผ๋, ๊ณต์ ๋ฌธ์๋ฅผ ๊ผผ๊ผผํ ํ์ธํ์.
Playwright์ Auto-Waiting์ ๋จ์ํ โ๊ธฐ๋ค๋ฆฌ๋ ๊ธฐ๋ฅโ์ ๋์ด์, ์ฌ์ฉ์์ ์ค์ ํ๋ ํ๋ฆ์ ์ ํํ ์ดํดํ๊ณ ์คํ ๊ฐ๋ฅํ ์์ ์ ํ๋จํ์ฌ ์๋์ผ๋ก ๋์ํ๋ ๋๋ํ ๊ธฐ๋ฅ์ธ ๊ฒ ๊ฐ๋ค.
๋๋ ํ์์ ๋จ์ ๋ฐ ํตํฉ ํ ์คํธ๋ฅผ ์ํ Jest๋ง ์๊ณ ์์๋๋ฐ, (์ฌ์ฉํด๋ณธ ์ ์ ์๊ณ ..) Playwright๋ฅผ ํตํด ๋ธ๋ผ์ฐ์ ์์์ ์ ์ฒด ์ฌ์ฉ์ ํ๋ก์ฐ๋ฅผ ์๋์ผ๋ก ํ ์คํธํ ์ ์๋ค๋ ์ ์ด ์ ๊ธฐํ๊ณ ๋งค๋ ฅ์ ์ด์๋ค.
๊ธฐ์กด์๋ ๋งค๋ฒ ์ ๋ ฅ ๊ฐ์ ์ง์ ๋ฃ์ด ์ ํจ์ฑ ๊ฒ์ฌ ๋๋ ๋ฑ๋ก์ด ์ ๋๋ก ๋์ํ๋์ง ํ์ธํด์ผ ํ์๋๋ฐ, Playwright๋ฅผ ํตํด ์๋ํํด ๋์ผ๋ ์ ๋ง ํธ๋ฆฌํ ๊ฒ ๊ฐ๋ค.
์๋์ผ๋ก ํ ์คํธ ํ๋ ์๊ฐ์ด ์๊ทผ ๋ง์ด ์์๋๊ณ ๊ท์ฐฎ์ ์ผ์ด์๋๋ฐ, ๊ธฐ์กด ํ๋ก์ ํธ์๋ ๋์ ํ๋ฉด ๊ฐ๋ฐ์ ๊ฒฝํ์ด ๋งค์ฐ ํฅ์๋ ๊ฒ ๊ฐ๋ค :)