Playwright ๊ตฌ์กฐ ๋œฏ์–ด๋ณด๊ธฐ

2025. 11. 24. 23:34ยท๐Ÿ“‚ Additional/๐Ÿ“„ Playwright

์š”์ฆ˜ ๋ฆด๋ฆฌ์ฆˆ๊ฐ€ ๋๋‚˜๋ฉด ๋‹ค์Œ ๋ฆด๋ฆฌ์ฆˆ ์ค€๋น„๊นŒ์ง€ ์ž ์‹œ ์ƒ๊ธด ํ‹ˆ์ƒˆ ์‹œ๊ฐ„์—, ํšŒ์‚ฌ ์„œ๋น„์Šค ์ž๋™ํ™” ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋‹ค. ํšŒ์‚ฌ ์Šคํ„ฐ๋””์—์„œ๋Š” JavaScript๋ฅผ ๊ณต๋ถ€ํ•˜๊ณ , ๊ฐœ์ธ์ ์œผ๋กœ๋Š” TypeScript์™€ Playwright๋ฅผ ํ•จ๊ป˜ ํŒŒ๊ณ ๋“ค๋ฉฐ ‘์ž๋™ํ™” ํ”„๋กœ์„ธ์Šค’๋ผ๋Š” ์™„์ „ ์ƒˆ๋กœ์šด ์˜์—ญ์„ ํ˜ผ์ž์„œ ๋ถ€๋”ชํžˆ๋ฉฐ ๊ตฌ์ถ•ํ•˜๊ณ  ์žˆ๋‹ค.

 

QA Manager๋กœ์„œ 'ํ…Œ์ŠคํŠธ ์ž๋™ํ™” ๊ตฌ์ถ•'์ด๋ผ๋Š” ํฐ ๊ณผ์ œ๋ฅผ ๋ฐ›์•˜์ง€๋งŒ, ์‹ค์ œ ์„œ๋น„์Šค ๊ธฐ๋ฐ˜์—์„œ์˜ ๊ฒฝํ—˜์€ ๊ฑฐ์˜ ์ „๋ฌดํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ชจ๋“  ๊ฒƒ์ด ์ƒˆ๋กœ์› ๊ณ , ๊ทธ๋ž˜์„œ ๋” ๊ถ๊ธˆํ–ˆ๋‹ค.

 

๋ณธ์ธ ์„ฑ๊ฒฉ์ƒ ํ•ญ์ƒ '์™œ?'๋ผ๋Š” ์งˆ๋ฌธ์„ ๋Š์ž„์—†์ด ๋˜์ง€๊ธฐ์—, Playwright ๊ตฌ์กฐ๋ฅผ ๋ดค์„ ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์˜€๋‹ค. '์ด๊ฒŒ ์™œ ์ด๋ ‡๊ฒŒ ๋™์ž‘ํ•˜์ง€?', '์™œ ์ด๋Ÿฐ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ง€?', '์ € ๊ฐ์ฒด๋Š” ์–ด๋””์„œ ์ƒ์„ฑ๋˜๋Š” ๊ฑฐ์ง€?' ๋ผ๋Š” ์งˆ๋ฌธ๋“ค์„ ๋Š์ž„์—†์ด ๋˜์ง€๋ฉฐ ํŒŒ๊ณ ๋“ค์—ˆ๋‹ค. ํŒŒ๊ณ ๋“ค๋‹ค ๋ณด๋‹ˆ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ๋ฌธ๋ฒ•๋„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ์˜ฌํ•ด ์ดˆ ๋ถ€ํŠธ์บ ํ”„์—์„œ ๋ฐฐ์› ๋˜ Pytest + Selenium๊ณผ์˜ ์ฐจ์ด์ ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋ถ€๋ถ„์€ ๋‹ค์Œ ํฌ์ŠคํŒ…์„ ํ†ตํ•ด ์ž์„ธํžˆ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ค.

 

๊ทธ๋ž˜์„œ ์˜ค๋Š˜ ๊ธ€์€ Playwright์˜ ๊ตฌ์กฐ๋ฅผ ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณด๋ฉฐ ‘์™œ ์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ์“ฐ๋Š”์ง€’ ์ดํ•ดํ•œ ๊ณผ์ •์„ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€๋Š” "์ด๊ฒŒ ์™œ ๊ถ๊ธˆํ•˜์ง€?"๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋‚˜์—๊ฒŒ๋Š” ์ •๋ง ๊ถ๊ธˆํ–ˆ๊ณ  ํŒŒ๊ณ ๋“œ๋Š” ๊ณผ์ • ์ž์ฒด๊ฐ€ ํฐ ๋„์›€์ด ๋˜์—ˆ๋‹ค. ํ‘œ๋ฉด์ ์ธ ์‚ฌ์šฉ๋ฒ•๋งŒ ์•„๋Š” ๊ฒƒ๊ณผ, ๋‚ด๋ถ€ ๊ตฌ์กฐ๊นŒ์ง€ ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์˜ ์ฐจ์ด๋Š” ์‹ค์ œ๋กœ ์—„์ฒญ ์ปธ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๐Ÿ” ์‹œ์ž‘: ์ž๋™ ์ƒ์„ฑ๋œ ์˜ˆ์ œ ์ฝ”๋“œ

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

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);
});

test('get started link', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Click the get started link.
  await page.getByRole('link', { name: 'Get started' }).click();

  // Expects page to have a heading with the name of Installation.
  await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});

Playwright ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ œ๊ณต๋˜๋Š” tests/example.spec.ts ํŒŒ์ผ์€ ์œ„์™€ ๊ฐ™๋‹ค.

์ฒ˜์Œ ์ด ์ฝ”๋“œ๋ฅผ ๋ดค์„ ๋•Œ ๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์งˆ๋ฌธ๋“ค์ด ๋– ์˜ฌ๋ž๋‹ค.

  • @playwright/test๋Š” ๋„๋Œ€์ฒด ๋ญ์ง€?
  • test() ํ•จ์ˆ˜๋Š” ์–ด๋–ค ๊ตฌ์กฐ๋ฅผ ๊ฐ–๋Š” ๊ฑฐ์ง€?
  • page๋Š” ๋ญ๊ณ , ์™œ ํ•จ์ˆ˜ ์ธ์ž์—์„œ { page }์ฒ˜๋Ÿผ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น์„ ์“ฐ๋Š” ๊ฑฐ์ง€?

์ด ์งˆ๋ฌธ๋“ค์„ ํ•˜๋‚˜์”ฉ ๋”ฐ๋ผ๊ฐ€ ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

๐Ÿ“Œ @playwright/test

Playwright๋Š” ํฌ๊ฒŒ 2๊ฐ€์ง€ ๋ ˆ์ด์–ด๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

  1. Core API
    -> Browser / Page / Locator ๊ฐ™์€ '์ž๋™ํ™” ์—”์ง„'
  2. Test Runner (@playwright/test)
    -> test(), expect(), fixtures, ๋ณ‘๋ ฌ ์‹คํ–‰ ๋“ฑ ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ ๊ธฐ๋Šฅ

์šฐ๋ฆฌ๊ฐ€ ๋ณดํ†ต ์‚ฌ์šฉํ•˜๋Š” '@playwright/test'๋Š” Core API๊ฐ€ ์•„๋‹Œ Playwright๊ฐ€ ์ž์ฒด ์ œ๊ณตํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ ํŒจํ‚ค์ง€๋‹ค.

 

์—ฌ๊ธฐ์—๋Š” ๋‹ค์Œ ๊ธฐ๋Šฅ๋“ค์ด ํ•จ๊ป˜ ํฌํ•จ๋œ๋‹ค:

  • ํ…Œ์ŠคํŠธ ์‹คํ–‰๊ธฐ
  • test / expect ๊ฐ™์€ ์ „์—ญ ํ•จ์ˆ˜
  • ํ…Œ์ŠคํŠธ๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ BrowserContext ๊ด€๋ฆฌ
  • ํ™•์žฅ ๊ฐ€๋Šฅํ•œ Fixture ์‹œ์Šคํ…œ
  • ๋ณ‘๋ ฌ ์‹คํ–‰, ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ, ์…ฐ๋„์ž‰ ๋“ฑ

์ฆ‰, 'Playwright๋ฅผ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ํŒจํ‚ค์ง€'๊ฐ€ ๋ฐ”๋กœ ์ด์— ํ•ด๋‹นํ•œ๋‹ค.

 

๐Ÿ“Œ test() ํ•จ์ˆ˜์™€ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น

๊ฒ‰๋ณด๊ธฐ์—๋Š” ๋‹จ์ˆœํ•œ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, test()๋Š” ์‚ฌ์‹ค ์—ฌ๋Ÿฌ ํƒ€์ž…๊ณผ ๊ธฐ๋Šฅ์ด ์กฐํ•ฉ๋œ ๋ณตํ•ฉ์ ์ธ ํ•จ์ˆ˜๋‹ค.

ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ๋Œ€๋ถ€๋ถ„์ด ์ด test ๊ฐ์ฒด๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

์ •์˜๋ฅผ ๋”ฐ๋ผ๊ฐ€ ๋ณด๋ฉด, ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

const test: TestType = (
  title: string,
  body: TestBody<
    PlaywrightTestArgs &
    PlaywrightTestOptions &
    PlaywrightWorkerArgs &
    PlaywrightWorkerOptions
  >
) => void

 

์ฆ‰, Playwright์˜ test ํ•จ์ˆ˜๋Š” ๋‹จ์ผ ํƒ€์ž…๋งŒ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  ๋‹ค์Œ ๋„ค ๊ฐ€์ง€ ํƒ€์ž…์„ ์ „๋ถ€ ํ•ฉ์นœ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ๋„˜๊ธด๋‹ค.

  • PlaywrightTestArgs: ํ…Œ์ŠคํŠธ๋งˆ๋‹ค ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง€๋Š” ์ž์› (page, context ๋“ฑ)
  • PlaywrightWorkerArgs: ๊ฐ™์€ ์›Œ์ปค์— ์†ํ•œ ํ…Œ์ŠคํŠธ๋“ค์ด ๊ณต์œ ํ•˜๋Š” ์ž์›
  • PlaywrightTestOptions: ํ…Œ์ŠคํŠธ ๋‹จ์œ„ ์„ค์ •
  • PlaywrightWorkerOptions: ์›Œ์ปค ๋‹จ์œ„ ์„ค์ •

์œ„ ๋„ค ๊ฐœ์˜ ํƒ€์ž…์ด ํ•ฉ์ณ์ ธ ์ตœ์ข…์ ์œผ๋กœ ํ•˜๋‚˜์˜ ์ธ์ž ๊ฐ์ฒด(args)๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

 

์—ฌ๊ธฐ์„œ ๋˜ PlaywrightTestArgs์˜ ์ •์˜๋ฅผ ๋”ฐ๋ผ๊ฐ€ ๋ณด๋ฉด:

export interface PlaywrightTestArgs {
  page: Page;
  context: BrowserContext;
  request: APIRequestContext;
}

์ด ์ •์˜๋ฅผ ๋ณด๋ฉด page๊ฐ€ ๋‹จ์ˆœํ•œ ๊ฐ’์ด ์•„๋‹ˆ๋ผ Playwright๊ฐ€ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด ์ „๋‹ฌํ•ด์ฃผ๋Š” Page ๊ฐ์ฒด๋ผ๋Š” ์ ์ด ๋ช…ํ™•ํ•ด์ง„๋‹ค.
๊ทธ๋ฆฌ๊ณ  page๋ฟ๋งŒ ์•„๋‹ˆ๋ผ context, request ์—ญ์‹œ ๋ชจ๋‘ Playwright๊ฐ€ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „์— ์ž๋™์œผ๋กœ ์ค€๋น„ํ•ด์ฃผ๋Š” ๊ธฐ๋ณธ fixture๋‹ค.

 

์ฆ‰, test()๋Š” ๊ฒ‰์œผ๋กœ ๋ณด๊ธฐ์—๋Š” ํ•˜๋‚˜์˜ ์ธ์ž(args)๋งŒ ๋ฐ›์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ 'ํฐ ๊ฐ์ฒด ํ•˜๋‚˜'๋ฅผ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•œ๋‹ค.

{
  page: Page,
  context: BrowserContext,
  request: APIRequestContext,
  ...๊ธฐํƒ€ Playwright ๊ธฐ๋ณธ fixture๋“ค,
  ...๋‚ด๊ฐ€ extend()๋กœ ์ถ”๊ฐ€ํ•œ custom fixture๋“ค
}

์ด์ฒ˜๋Ÿผ args ๋‚ด๋ถ€์— ์ˆ˜๋งŽ์€ ๊ฐ’์ด ๋“ค์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋Š” ํ•„์š”ํ•œ ๊ฐ’๋งŒ ๊ณจ๋ผ ์“ฐ๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ ํŒจํ„ด์ด ๋œ๋‹ค.

 

๊ตฌ์กฐ ๋ถ„ํ•ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  fixture์— ์ ‘๊ทผํ•  ๋•Œ๋งˆ๋‹ค ๋‹ค์Œ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

test('example', async (args) => {
  await args.page.goto('/');
});

์ฆ‰, Playwright๊ฐ€ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น์„ ๊ธฐ๋ณธ ์‚ฌ์šฉ ๋ฐฉ์‹์œผ๋กœ ์•ˆ๋‚ดํ•˜๋Š” ์ด์œ ๋Š” ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์— ์ „๋‹ฌ๋˜๋Š” ์ธ์ž ๊ฐ์ฒด๊ฐ€ ๋งค์šฐ ํฌ๊ณ  ๋ณตํ•ฉ์ ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•„์š”ํ•œ fixture๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊บผ๋‚ด ์“ธ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์กฐ ๋ถ„ํ•ด๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ตœ์ ์˜ ์„ ํƒ์ด ๋œ๋‹ค.

 

๐Ÿ” ๋” ๋‚˜์•„๊ฐ€: Custom Fixture ์ฝ”๋“œ

import { test as base } from '@playwright/test';
import { TodoPage } from './todo-page';

// Extend basic test by providing a "todoPage" fixture.
const test = base.extend<{ todoPage: TodoPage }>({
  todoPage: async ({ page }, use) => {
    const todoPage = new TodoPage(page);
    await todoPage.goto();
    await todoPage.addToDo('item1');
    await todoPage.addToDo('item2');
    await use(todoPage);
    await todoPage.removeAll();
  },
});

test('should add an item', async ({ todoPage }) => {
  await todoPage.addToDo('my item');
  // ...
});

test('should remove an item', async ({ todoPage }) => {
  await todoPage.remove('item1');
  // ...
});

์ด ์ฝ”๋“œ๋ฅผ ์ฒ˜์Œ ๋ดค์„ ๋•Œ, ๋˜ ๋‹ค์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์งˆ๋ฌธ๋“ค์ด ๋– ์˜ฌ๋ž๋‹ค.

  • as๋Š” ์™œ ์“ฐ๋Š” ๊ฑธ๊นŒ?
  • extend๋Š” ๋ฌด์Šจ ์—ญํ• ?
  • <{ ... }> ๊ตฌ์กฐ๋Š” ๋ญ์ง€?
  • ({ ... }) ๊ตฌ์กฐ๋Š” ๋ญ์ง€?

๋‹ค์‹œ ํ•ด๋‹น ์งˆ๋ฌธ๋“ค์„ ํ•˜๋‚˜์”ฉ ๋”ฐ๋ผ๊ฐ€ ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

๐Ÿ“Œ as: ๊ธฐ๋ณธ test ์ด๋ฆ„ ๋ณ€๊ฒฝ

import { test as base } from '@playwright/test';

as๋Š” ๋‹จ์ˆœํžˆ importํ•œ ์‹๋ณ„์ž์˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋Š” ๋ฌธ๋ฒ•์ด๋‹ค.

 

๊ธฐ๋ณธ test๋ฅผ ํ™•์žฅํ•ด์„œ ์ƒˆ๋กœ์šด test ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์›๋ณธ๊ณผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด base๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ฐ”๊ฟ”์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด๋‹ค.

  • base: Playwright๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ test
  • test: ๋‚ด๊ฐ€ ํ™•์žฅํ•œ ์ปค์Šคํ…€ test

์ด๋ ‡๊ฒŒ ์ด๋ฆ„์„ ๋‚˜๋ˆ„์ง€ ์•Š์œผ๋ฉด ํ˜ผ๋ž€์ด ์ƒ๊ธด๋‹ค.

 

๐Ÿ“Œ Playwright์—์„œ extend()๋Š” ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”๊ฐ€?

Playwright๋Š” fixture ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค. test()๊ฐ€ ๋„˜๊ฒจ์ฃผ๋Š” page, context ์—ญ์‹œ ๊ธฐ๋ณธ fixture๋‹ค.

extend()๋Š” ์—ฌ๊ธฐ์— ์ƒˆ๋กœ์šด fixture๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด fixture๋ฅผ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

 

const test = base.extend<{ todoPage: TodoPage }>({ ... });

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด,

  • ๊ธฐ์กด test ๊ธฐ๋Šฅ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ณ 
  • todoPage๋ผ๋Š” ์ƒˆ fixture๋ฅผ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค

์ฆ‰, ํ…Œ์ŠคํŠธ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋Š” Playwright์˜ ์ •์‹ ๋ฐฉ์‹์ด๋‹ค.

 

๐Ÿ“Œ ์™œ <{ todoPage: TodoPage }>์ฒ˜๋Ÿผ ์ œ๋„ค๋ฆญ์„ ์“ฐ๋Š”๊ฐ€?

์—ฌ๊ธฐ์„œ <{ todoPage: TodoPage }>๋Š” TypeScript ์ œ๋„ค๋ฆญ์ด๋‹ค.
์ด ์ œ๋„ค๋ฆญ์€ '๋‚ด๊ฐ€ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  fixture๊ฐ€ ์–ด๋–ค ํƒ€์ž…์„ ๊ฐ€์ง€๋Š”์ง€'๋ฅผ Playwright์—๊ฒŒ ์•Œ๋ ค์ค€๋‹ค.

  • key: fixture ์ด๋ฆ„ (todoPage)
  • value: ํ•ด๋‹น fixture๊ฐ€ ์–ด๋–ค ํƒ€์ž…์ธ์ง€ (TodoPage ํด๋ž˜์Šค)

์ด ํƒ€์ž… ์ •๋ณด๋ฅผ ๋„˜๊ฒจ๋‘์–ด์•ผ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ž๋™ ์™„์„ฑ ๋ฐ ํƒ€์ž… ์ถ”๋ก ์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  fixture๋Š” ํ•œ ๊ฐœ์ผ ์ˆ˜๋„ ์žˆ๊ณ , ์—ฌ๋Ÿฌ ๊ฐœ์ผ ์ˆ˜๋„ ์žˆ๋‹ค.

Playwright๋Š” ์ด๋Ÿฐ ๋‹ค์–‘ํ•œ ๊ฒฝ์šฐ๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด, ‘fixture ์ด๋ฆ„: fixture ํƒ€์ž…’๋“ค์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด ํƒ€์ž…์œผ๋กœ ๋ฌถ์–ด์„œ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

๋งŒ์•ฝ fixture๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์•„๋ž˜์ฒ˜๋Ÿผ ํ™•์žฅ๋œ๋‹ค.

extend<{
  todoPage: TodoPage;
  userPage: UserPage;
  apiClient: ApiClient;
}>

๊ฒฐ๊ตญ ์ œ๋„ค๋ฆญ์— {}๋ฅผ ์“ฐ๋Š” ์ด์œ ๋Š” ๋‹จ์ผ fixture๋“  ์—ฌ๋Ÿฌ fixture๋“  ๋™์ผํ•œ ๊ฐ์ฒด ๊ตฌ์กฐ๋กœ ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค.

 

๐Ÿ“Œ extend() ์•ˆ์˜ {}๋Š”?

extend()์— ์ „๋‹ฌํ•˜๋Š” ๊ฐ์ฒด๋Š” '์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์žฌ์ •์˜ํ•˜๊ณ  ์‹ถ์€ fixture ๋ชฉ๋ก'์„ ์„ ์–ธํ•˜๋Š” ์˜์—ญ์ด๋‹ค.

const test = base.extend<{ todoPage: TodoPage }>({
  todoPage: async ({ page }, use) => {
    // ...
  },
});

 

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€๋‹ค:

  • key: fixture ์ด๋ฆ„
  • value: ํ•ด๋‹น fixture๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์‹คํ–‰ํ•  ๋กœ์ง

 

์‹ค์ œ๋กœ๋Š” ์ด๋Ÿฐ ์ˆœ์„œ๋กœ ๋™์ž‘ํ•œ๋‹ค:

const test = base.extend<{ todoPage: TodoPage }>({
  // 1) fixture ์ด๋ฆ„: fixture ์ƒ์„ฑ/์ดˆ๊ธฐํ™”/์ •๋ฆฌ๊นŒ์ง€ ๋‹ด๋‹นํ•˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜
  todoPage: async ({ page }, use) => {

    // 2) Playwright๊ฐ€ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” ๊ธฐ๋ณธ fixture(page ๋“ฑ)๋ฅผ ๋ฐ›์•„
    //    ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” fixture๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
    const todoPage = new TodoPage(page);

    // 3) ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „์— ํ•„์š”ํ•œ ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    await todoPage.goto();

    // 4) use()๋ฅผ ํ˜ธ์ถœํ•ด fixture๋ฅผ ํ…Œ์ŠคํŠธ์— ์ „๋‹ฌํ•œ๋‹ค.
    //    → test('...', async ({ todoPage }) => { ... }) ์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ด์ง
    await use(todoPage);

    // 5) ํ…Œ์ŠคํŠธ ์™„๋ฃŒ ํ›„ cleanup ๋กœ์ง์„ ์‹คํ–‰ํ•œ๋‹ค.
    await todoPage.removeAll();
  },
});

 

 

728x90
์ €์ž‘์žํ‘œ์‹œ ๋น„์˜๋ฆฌ ๋ณ€๊ฒฝ๊ธˆ์ง€ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'๐Ÿ“‚ Additional > ๐Ÿ“„ Playwright' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Playwright ๊ธฐ์ดˆ (๊ธฐ์ดˆ์ ์ธ ํ™œ์šฉ๋ฒ•๊ณผ ํ•ต์‹ฌ ์›๋ฆฌ)  (4) 2025.06.14
'๐Ÿ“‚ Additional/๐Ÿ“„ Playwright' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ์ธํ”„๋Ÿฐ ๊ฐ•์˜ - Playwright ๊ธฐ์ดˆ (๊ธฐ์ดˆ์ ์ธ ํ™œ์šฉ๋ฒ•๊ณผ ํ•ต์‹ฌ ์›๋ฆฌ)
YeonSu02
YeonSu02
Email : rkddustn2519@naver.com
  • YeonSu02
    IsLiife2
    YeonSu02
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ
      • ๐Ÿ“‚ Computer Science
      • ๐Ÿ“‚ Unity Engine
        • ๐Ÿ“„ Unity Lecture
        • ๐Ÿ“„ Unity References
        • ๐Ÿ’ป Game Development
      • ๐Ÿ“‚ Quality Assurance
        • ๐Ÿ”ฅ ์—˜๋ฆฌ์Šค SW QAํŠธ๋ž™
        • ๐Ÿ“„ Experience & Insight
        • ๐Ÿ“„ QA References
      • ๐Ÿ“‚ Program Language
        • ๐Ÿ“„ C#
        • ๐Ÿ“„ Python
        • ๐Ÿ“„ JavaScript
        • ๐Ÿ“„ TypeScript
      • ๐Ÿ“‚ Additional
        • ๐Ÿ“„ Docker
        • ๐Ÿ“„ Jenkins
        • ๐Ÿ“„ Playwright
      • ๐Ÿ“‚ Book Review
      • ๐Ÿ“‚ License
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
  • ๋งํฌ

    • GitHub
  • ์ธ๊ธฐ ๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
YeonSu02
Playwright ๊ตฌ์กฐ ๋œฏ์–ด๋ณด๊ธฐ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”