Skip to content
Vitest 3
Main Navigation 가이드 & API구성브라우저 모드고급 API
3.2.0
2.1.9
1.6.1
0.34.6

한국어

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
Italiano
Polski
Türkçe
čeština
magyar

한국어

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
Italiano
Polski
Türkçe
čeština
magyar

외관

Sidebar Navigation

소개

브라우저 모드를 사용하는 이유

브라우저 모드

구성

브라우저 설정 참조

Playwright 구성

WebdriverIO 구성

API

Context API

상호작용 API

로케이터

Assertion API

명령어

가이드

다중 설정

Vitest 구성하기

테스트 API 참조

고급 API

이 페이지에서

로케이터 ​

로케이터는 단일 요소 또는 여러 요소를 나타내는 개념입니다. 모든 로케이터는 '셀렉터'라고 불리는 문자열로 정의됩니다. Vitest는 이러한 셀렉터를 내부적으로 생성하는 편리한 메서드를 제공하여 추상화합니다.

로케이터 API는 Playwright의 로케이터를 포크(fork)한 Ivya를 사용합니다. 그러나 Vitest는 이 API를 Playwright뿐만 아니라 모든 프로바이더에서도 제공합니다.

TIP

이 페이지에서는 API 사용법을 다룹니다. 로케이터와 그 사용법을 더 잘 이해하려면 Playwright의 "로케이터" 문서를 읽어보세요.

getByRole ​

ts
function getByRole(
  role: ARIARole | string,
  options?: LocatorByRoleOptions
): Locator;

ARIA 역할, ARIA 속성 및 접근성 이름을 사용하여 요소를 찾을 수 있는 로케이터를 생성합니다.

TIP

getByText('The name')으로 단일 요소를 쿼리할 때, getByRole(expectedRole, { name: 'The name' })을 사용하는 것이 더 나은 경우가 많습니다. 접근성 이름 쿼리는 *ByAltText 또는 *ByTitle과 같은 다른 쿼리를 대체하지 않습니다. 접근성 이름이 이러한 속성과 동일할 수 있지만, 이 속성들의 기능을 대체하지는 않습니다.

다음 DOM 구조를 고려해 보세요.

html
<h3>Sign up</h3>
<label>
  Login
  <input type="text" />
</label>
<label>
  Password
  <input type="password" />
</label>
<br />
<button>Submit</button>

각 요소를 암시적 역할로 찾을 수 있습니다.

ts
await expect
  .element(page.getByRole('heading', { name: 'Sign up' }))
  .toBeVisible();

await page.getByRole('textbox', { name: 'Login' }).fill('admin');
await page.getByRole('textbox', { name: 'Password' }).fill('admin');

await page.getByRole('button', { name: /submit/i }).click();

WARNING

역할은 ARIA 역할 계층을 상속하지 않고 문자열 일치로 매칭됩니다. 결과적으로 checkbox와 같은 상위 역할(superclass role)을 쿼리해도 switch와 같은 하위 역할(subclass role)을 가진 요소는 포함되지 않습니다.

기본적으로 HTML의 많은 시맨틱 요소는 역할을 가지고 있습니다. 예를 들어, <input type="radio">는 "radio" 역할을 가집니다. HTML의 비시맨틱 요소는 역할을 가지지 않습니다. <div>와 <span>은 추가된 시맨틱이 없으면 null을 반환합니다. role 속성은 시맨틱을 제공할 수 있습니다.

ARIA 가이드라인은 이미 암시적 역할을 가진 내장 요소에 role 또는 aria-* 속성을 통해 역할을 제공하는 것을 강력히 권장하지 않습니다.

옵션 ​
  • exact: boolean

    name이 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. name이 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

    tsx
    <button>Hello World</button>;
    
    page.getByRole('button', { name: 'hello world' }); // ✅
    page.getByRole('button', { name: 'hello world', exact: true }); // ❌
    page.getByRole('button', { name: 'Hello World', exact: true }); // ✅
  • checked: boolean

    체크된 요소(aria-checked 또는 <input type="checkbox"/>로 설정된)를 포함할지 여부. 기본적으로 필터는 적용되지 않습니다.

    자세한 내용은 aria-checked를 참조하세요.

    tsx
    <>
      <button role="checkbox" aria-checked="true" />
      <input type="checkbox" checked />
    </>;
    
    page.getByRole('checkbox', { checked: true }); // ✅
    page.getByRole('checkbox', { checked: false }); // ❌
  • disabled: boolean

    비활성 상태인 요소를 포함할지 여부. 기본적으로 필터는 적용되지 않습니다. 다른 속성과 달리 disabled 상태는 상속됩니다.

    자세한 내용은 aria-disabled를 참조하세요.

    tsx
    <input type="text" disabled />;
    
    page.getByRole('textbox', { disabled: true }); // ✅
    page.getByRole('textbox', { disabled: false }); // ❌
  • expanded: boolean

    확장된 요소를 포함할지 여부. 기본적으로 필터는 적용되지 않습니다.

    자세한 내용은 aria-expanded를 참조하세요.

    tsx
    <a aria-expanded="true" href="example.com">
      Link
    </a>;
    
    page.getByRole('link', { expanded: true }); // ✅
    page.getByRole('link', { expanded: false }); // ❌
  • includeHidden: boolean

    접근성 트리에서 일반적으로 제외되는 요소를 쿼리할지 여부. 기본적으로 숨김 처리되지 않은 요소만 역할 셀렉터에 의해 일치됩니다.

    none 및 presentation 역할은 항상 포함됩니다.

    tsx
    <button style="display: none" />;
    
    page.getByRole('button'); // ❌
    page.getByRole('button', { includeHidden: false }); // ❌
    page.getByRole('button', { includeHidden: true }); // ✅
  • level: number

    heading, listitem, row, treeitem 역할에 대해 일반적으로 존재하는 숫자 속성으로, <h1>-<h6> 요소에 대한 기본값이 있습니다. 기본적으로 필터는 적용되지 않습니다.

    자세한 내용은 aria-level을 참조하세요.

    tsx
    <>
      <h1>Heading Level One</h1>
      <div role="heading" aria-level="1">
        Second Heading Level One
      </div>
    </>;
    
    page.getByRole('heading', { level: 1 }); // ✅
    page.getByRole('heading', { level: 2 }); // ❌
  • name: string | RegExp

    접근성 이름. 기본적으로 일치는 대소문자를 구분하지 않으며 부분 문자열과 일치합니다. 이 동작을 제어하려면 exact 옵션을 사용하세요.

    tsx
    <button>Click Me!</button>;
    
    page.getByRole('button', { name: 'Click Me!' }); // ✅
    page.getByRole('button', { name: 'click me!' }); // ✅
    page.getByRole('button', { name: 'Click Me?' }); // ❌
  • pressed: boolean

    눌린 요소를 포함할지 여부. 기본적으로 필터는 적용되지 않습니다.

    자세한 내용은 aria-pressed를 참조하세요.

    tsx
    <button aria-pressed="true">👍</button>;
    
    page.getByRole('button', { pressed: true }); // ✅
    page.getByRole('button', { pressed: false }); // ❌
  • selected: boolean

    선택된 요소를 포함할지 여부. 기본적으로 필터는 적용되지 않습니다.

    자세한 내용은 aria-selected를 참조하세요.

    tsx
    <button role="tab" aria-selected="true">
      Vue
    </button>;
    
    page.getByRole('button', { selected: true }); // ✅
    page.getByRole('button', { selected: false }); // ❌
참고 ​
  • MDN의 ARIA 역할 목록
  • w3.org의 ARIA 역할 목록
  • testing-library의 ByRole

getByAltText ​

ts
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;

텍스트와 일치하는 alt 속성을 가진 요소를 찾을 수 있는 로케이터를 생성합니다. testing-library의 구현과 달리 Vitest는 일치하는 alt 속성을 가진 모든 요소를 찾습니다.

tsx
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;

page.getByAltText(/incredibles.*? poster/i); // ✅
page.getByAltText('non existing alt text'); // ❌

옵션 ​

  • exact: boolean

    text가 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. text가 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

참고 ​

  • testing-library의 ByAltText

getByLabelText ​

ts
function getByLabelText(
  text: string | RegExp,
  options?: LocatorOptions
): Locator;

연결된 레이블을 가진 요소를 찾을 수 있는 로케이터를 생성합니다.

page.getByLabelText('Username') 로케이터는 아래 예시의 모든 input 요소를 찾습니다.

html
// label과 form 요소 id 간의 for/htmlFor 관계
<label for="username-input">Username</label>
<input id="username-input" />

// form 요소와 함께 사용되는 aria-labelledby 속성
<label id="username-label">Username</label>
<input aria-labelledby="username-label" />

// 래퍼 레이블
<label>Username <input /></label>

// 레이블 텍스트가 다른 자식 요소 내에 있는 래퍼 레이블
<label>
  <span>Username</span>
  <input />
</label>

// aria-label 속성
// 사용자가 페이지에서 볼 수 있는 레이블이 아니므로, 시각적 사용자에게 입력의 목적이 명확해야 합니다.
<input aria-label="Username" />

옵션 ​

  • exact: boolean

    text가 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. text가 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

참고 ​

  • testing-library의 ByLabelText

getByPlaceholder ​

ts
function getByPlaceholder(
  text: string | RegExp,
  options?: LocatorOptions
): Locator;

지정된 placeholder 속성을 가진 요소를 찾을 수 있는 로케이터를 생성합니다. Vitest는 input뿐만 아니라 일치하는 placeholder 속성을 가진 모든 요소를 찾습니다.

tsx
<input placeholder="Username" />;

page.getByPlaceholder('Username'); // ✅
page.getByPlaceholder('not found'); // ❌

WARNING

일반적으로 플레이스홀더(placeholder)보다는 getByLabelText를 사용하여 레이블에 의존하는 것이 더 좋습니다.

옵션 ​

  • exact: boolean

    text가 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. text가 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

참고 ​

  • testing-library의 ByPlaceholderText

getByText ​

ts
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;

지정된 텍스트를 포함하는 요소를 찾을 수 있는 로케이터를 생성합니다. 텍스트는 TextNode의 nodeValue 또는 타입이 button이나 reset인 경우 input의 값과 일치됩니다. 텍스트 일치는 정확히 일치하는 경우에도 항상 공백을 표준화합니다. 예를 들어, 여러 공백을 하나로 바꾸고, 개행을 공백으로 바꾸며, 선행 및 후행 공백을 무시합니다.

tsx
<a href="/about">About ℹ️</a>;

page.getByText(/about/i); // ✅
page.getByText('about', { exact: true }); // ❌

TIP

이 로케이터는 비대화형 요소를 찾는 데 유용합니다. 버튼이나 입력과 같은 인터랙티브 요소를 찾아야 하는 경우 getByRole을 선호하세요.

옵션 ​

  • exact: boolean

    text가 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. text가 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

참고 ​

  • testing-library의 ByText

getByTitle ​

ts
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;

지정된 title 속성을 가진 요소를 찾을 수 있는 로케이터를 생성합니다. testing-library의 getByTitle과 달리 Vitest는 SVG 내의 title 요소를 찾지 못합니다.

tsx
<span title="Delete" id="2"></span>;

page.getByTitle('Delete'); // ✅
page.getByTitle('Create'); // ❌

옵션 ​

  • exact: boolean

    text가 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. text가 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

참고 ​

  • testing-library의 ByTitle

getByTestId ​

ts
function getByTestId(text: string | RegExp): Locator;

지정된 테스트 ID 속성과 일치하는 요소를 찾을 수 있는 로케이터를 생성합니다. browser.locators.testIdAttribute를 사용하여 속성 이름을 구성할 수 있습니다.

tsx
<div data-testid="custom-element" />;

page.getByTestId('custom-element'); // ✅
page.getByTestId('non-existing-element'); // ❌

WARNING

다른 로케이터가 사용 사례에 적합하지 않을 때만 이 방법을 사용하는 것이 좋습니다. data-testid 속성을 사용하는 것은 소프트웨어가 실제로 사용되는 방식과 유사하지 않으므로 가능하면 피해야 합니다.

옵션 ​

  • exact: boolean

    text가 정확히 일치하는지 여부: 대소문자 구분 및 전체 문자열 일치. 기본적으로 비활성화되어 있습니다. text가 정규 표현식인 경우 이 옵션은 무시됩니다. 정확히 일치해도 공백은 제거됩니다.

참고 ​

  • testing-library의 ByTestId

nth ​

ts
function nth(index: number): Locator;

이 메서드는 다중 요소 쿼리 결과 내에서 특정 인덱스만 일치하는 새 로케이터를 반환합니다. 0부터 시작하며, nth(0)은 첫 번째 요소를 선택합니다. elements()[n]과 달리 nth 로케이터는 요소가 나타날 때까지 재시도(retry)됩니다.

html
<div aria-label="one"><input /><input /><input /></div>
<div aria-label="two"><input /></div>
tsx
page.getByRole('textbox').nth(0); // ✅
page.getByRole('textbox').nth(4); // ❌

TIP

nth를 사용하기 전에 검색 범위를 좁히기 위해 체인 로케이터를 사용하는 것이 유용할 수 있습니다. 때로는 요소 위치로 구분하는 것 외에 더 나은 방법이 없을 수도 있습니다. 이는 불안정할 수 있지만, 없는 것보다는 낫습니다.

tsx
page.getByLabel('two').getByRole('input'); // ✅ page.getByRole('textbox').nth(3)보다 더 나은 대안
page.getByLabel('one').getByRole('input'); // ❌ 너무 모호함
page.getByLabel('one').getByRole('input').nth(1); // ✅ 실용적인 타협

first ​

ts
function first(): Locator;

이 메서드는 다중 요소 쿼리 결과의 첫 번째 인덱스만 일치하는 새 로케이터를 반환합니다. nth(0)의 줄임 표현입니다.

html
<input /> <input /> <input />
tsx
page.getByRole('textbox').first(); // ✅

last ​

ts
function last(): Locator;

이 메서드는 다중 요소 쿼리 결과의 마지막 인덱스만 일치하는 새 로케이터를 반환합니다. nth(-1)의 줄임 표현입니다.

html
<input /> <input /> <input />
tsx
page.getByRole('textbox').last(); // ✅

and ​

ts
function and(locator: Locator): Locator;

이 메서드는 부모 로케이터와 제공된 로케이터 모두와 일치하는 새 로케이터를 생성합니다. 다음 예시는 특정 제목을 가진 버튼을 찾습니다.

ts
page.getByRole('button').and(page.getByTitle('Subscribe'));

or ​

ts
function or(locator: Locator): Locator;

이 메서드는 두 로케이터 중 하나 또는 둘 다와 일치하는 새 로케이터를 생성합니다.

WARNING

로케이터가 단일 요소 이상을 일치시키는 경우, 단일 요소를 예상하는 다른 메서드를 호출하면 오류가 발생할 수 있습니다.

tsx
<>
  <button>Click me</button>
  <a href="https://vitest.dev">Error happened!</a>
</>;

page.getByRole('button').or(page.getByRole('link')).click(); // ❌ 여러 요소와 일치

filter ​

ts
function filter(options: LocatorOptions): Locator;

이 메서드는 텍스트로 필터링하는 등의 옵션에 따라 로케이터를 좁힙니다. 여러 필터를 적용하기 위해 체인으로 연결할 수 있습니다.

has ​

  • 유형: Locator

이 옵션은 제공된 로케이터와 일치하는 다른 요소를 포함하는 요소만 찾도록 셀렉터를 좁힙니다. 예를 들어, 다음 HTML에서:

html
<article>
  <div>Vitest</div>
</article>
<article>
  <div>Rolldown</div>
</article>

Vitest 텍스트를 포함하는 article만 찾도록 로케이터를 좁힐 수 있습니다.

ts
page.getByRole('article').filter({ has: page.getByText('Vitest') }); // ✅

WARNING

제공된 로케이터(예시에서 page.getByText('Vitest'))는 부모 로케이터(예시에서 page.getByRole('article'))에 상대적이어야 합니다. 문서 루트가 아닌 부모 로케이터를 기준으로 쿼리됩니다.

즉, 부모 로케이터 외부의 요소를 쿼리하는 로케이터를 전달할 수 없습니다.

ts
page.getByText('Vitest').filter({ has: page.getByRole('article') }); // ❌

이 예시는 article 요소가 Vitest 텍스트를 가진 요소 외부에 있기 때문에 실패합니다.

TIP

이 메서드는 요소를 더 좁히기 위해 체인으로 연결할 수 있습니다.

ts
page
  .getByRole('article')
  .filter({ has: page.getByRole('button', { name: 'delete row' }) })
  .filter({ has: page.getByText('Vitest') });

hasNot ​

  • 유형: Locator

이 옵션은 제공된 로케이터와 일치하는 다른 요소를 포함하지 않는 요소만 찾도록 셀렉터를 좁힙니다. 예를 들어, 다음 HTML에서:

html
<article>
  <div>Vitest</div>
</article>
<article>
  <div>Rolldown</div>
</article>

Rolldown을 포함하지 않는 article만 찾도록 로케이터를 좁힐 수 있습니다.

ts
page.getByRole('article').filter({ hasNot: page.getByText('Rolldown') }); // ✅
page.getByRole('article').filter({ hasNot: page.getByText('Vitest') }); // ❌

WARNING

제공된 로케이터는 has 옵션과 마찬가지로 문서 루트가 아닌 부모에 대해 쿼리됩니다.

hasText ​

  • 유형: string | RegExp

이 옵션은 셀렉터를 제공된 텍스트를 어딘가에 포함하는 요소만 찾도록 좁힙니다. string이 전달되면 일치는 대소문자를 구분하지 않으며 부분 문자열을 검색합니다.

html
<article>
  <div>Vitest</div>
</article>
<article>
  <div>Rolldown</div>
</article>

검색이 대소문자를 구분하지 않으므로 두 로케이터 모두 동일한 요소를 찾습니다.

ts
page.getByRole('article').filter({ hasText: 'Vitest' }); // ✅
page.getByRole('article').filter({ hasText: 'Vite' }); // ✅

hasNotText ​

  • 유형: string | RegExp

이 옵션은 셀렉터를 제공된 텍스트를 어딘가에 포함하지 않는 요소만 일치하도록 좁힙니다. string이 전달되면 일치는 대소문자를 구분하지 않으며 부분 문자열을 검색합니다.

메서드 ​

모든 메서드는 비동기이며 await해야 합니다. Vitest 3부터는 메서드가 await되지 않으면 테스트가 실패합니다.

click ​

ts
function click(options?: UserEventClickOptions): Promise<void>;

요소를 클릭합니다. 옵션을 사용하여 마우스 커서 위치를 설정할 수 있습니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).click();
  • 자세한 내용은 userEvent.click 참조

dblClick ​

ts
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;

요소에 더블 클릭 이벤트를 트리거합니다. 옵션을 사용하여 마우스 커서 위치를 설정할 수 있습니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).dblClick();
  • 자세한 내용은 userEvent.dblClick 참조

tripleClick ​

ts
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;

요소에 트리플 클릭 이벤트를 트리거합니다. 브라우저 API에는 tripleclick이 없으므로 이 메서드는 세 번의 클릭 이벤트를 연속으로 발생시킵니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).tripleClick();
  • 자세한 내용은 userEvent.tripleClick 참조

clear ​

ts
function clear(options?: UserEventClearOptions): Promise<void>;

입력 요소의 내용을 지웁니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('textbox', { name: 'Full Name' }).clear();
  • 자세한 내용은 userEvent.clear 참조

hover ​

ts
function hover(options?: UserEventHoverOptions): Promise<void>;

마우스 커서 위치를 선택된 요소로 이동합니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).hover();
  • 자세한 내용은 userEvent.hover 참조

unhover ​

ts
function unhover(options?: UserEventHoverOptions): Promise<void>;

이것은 locator.hover와 동일하게 작동하지만, 커서를 document.body 요소로 이동합니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).unhover();
  • 자세한 내용은 userEvent.unhover 참조

fill ​

ts
function fill(text: string, options?: UserEventFillOptions): Promise<void>;

현재 input, textarea 또는 contenteditable 요소의 값을 설정합니다.

ts
import { page } from '@vitest/browser/context';

await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean');
  • 자세한 내용은 userEvent.fill 참조

dropTo ​

ts
function dropTo(
  target: Locator,
  options?: UserEventDragAndDropOptions
): Promise<void>;

현재 요소를 대상 위치로 드래그 앤 드롭합니다.

ts
import { page } from '@vitest/browser/context';

const paris = page.getByText('Paris');
const france = page.getByText('France');

await paris.dropTo(france);
  • 자세한 내용은 userEvent.dragAndDrop 참조

selectOptions ​

ts
function selectOptions(
  values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
  options?: UserEventSelectOptions
): Promise<void>;

<select> 요소에서 하나 이상의 값을 선택합니다.

ts
import { page } from '@vitest/browser/context';

const languages = page.getByRole('select', { name: 'Languages' });

await languages.selectOptions('EN');
await languages.selectOptions(['ES', 'FR']);
await languages.selectOptions([
  languages.getByRole('option', { name: 'Spanish' }),
  languages.getByRole('option', { name: 'French' }),
]);
  • 자세한 내용은 userEvent.selectOptions 참조

screenshot ​

ts
function screenshot(
  options: LocatorScreenshotOptions & { save: false }
): Promise<string>;
function screenshot(
  options: LocatorScreenshotOptions & { base64: true }
): Promise<{
  path: string;
  base64: string;
}>;
function screenshot(
  options?: LocatorScreenshotOptions & { base64?: false }
): Promise<string>;

로케이터의 셀렉터와 일치하는 요소의 스크린샷을 생성합니다.

path 옵션을 사용하여 스크린샷 저장 위치를 지정할 수 있으며, 이는 현재 테스트 파일에 상대적입니다. path 옵션이 설정되지 않은 경우, Vitest는 기본적으로 browser.screenshotDirectory (__screenshot__이 기본값)와 파일 및 테스트 이름을 사용하여 스크린샷의 파일 경로를 결정합니다.

스크린샷의 내용도 필요한 경우, base64: true를 지정하여 스크린샷이 저장된 파일 경로와 함께 반환받을 수 있습니다.

ts
import { page } from '@vitest/browser/context';

const button = page.getByRole('button', { name: 'Click Me!' });

const path = await button.screenshot();

const { path, base64 } = await button.screenshot({
  path: './button-click-me.png',
  base64: true, // base64 문자열도 반환
});
// path - 스크린샷의 전체 경로
// bas64 - 스크린샷의 base64 인코딩 문자열

경고 3.2.0+

save가 false로 설정된 경우 screenshot은 항상 base64 문자열을 반환합니다. 이때 path는 무시됩니다.

query ​

ts
function query(): Element | null;

이 메서드는 로케이터의 셀렉터와 일치하는 단일 요소를 반환하며, 요소가 없으면 null을 반환합니다.

여러 요소가 셀렉터와 일치하는 경우, 이 메서드는 오류를 발생시킵니다. 일치하는 모든 DOM 요소를 필요로 한다면 .elements()를 사용하고, 셀렉터와 일치하는 로케이터 배열이 필요하다면 .all()을 사용하세요.

다음 DOM 구조를 고려해 보세요.

html
<div>Hello <span>World</span></div>
<div>Hello</div>

이 로케이터는 오류를 발생시키지 않습니다.

ts
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElement

이 로케이터는 오류를 발생시킵니다.

ts
// 여러 요소를 반환
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌

element ​

ts
function element(): Element;

이 메서드는 로케이터의 셀렉터와 일치하는 단일 요소를 반환합니다.

셀렉터와 일치하는 요소가 없는 경우 오류가 발생합니다. 요소가 존재하는지 확인하기만 하면 되는 경우 .query()를 사용하는 것을 고려하세요.

셀렉터와 일치하는 _여러 요소_가 있는 경우 오류가 발생합니다. 일치하는 모든 DOM 요소를 필요로 한다면 .elements()를 사용하고, 셀렉터와 일치하는 로케이터 배열이 필요하다면 .all()을 사용하세요.

TIP

이 메서드는 외부 라이브러리에 전달해야 할 때 유용할 수 있습니다. 로케이터가 expect.element와 함께 사용될 때마다 어설션이 재시도(retry)될 때 자동으로 호출됩니다.

ts
await expect.element(page.getByRole('button')).toBeDisabled();

다음 DOM 구조를 고려해 보세요.

html
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>

이 로케이터는 오류를 발생시키지 않습니다.

ts
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅

이 로케이터는 오류를 발생시킵니다.

ts
// 여러 요소를 반환
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌

// 요소를 반환하지 않음
page.getByText('Hello USA').element(); // ❌

elements ​

ts
function elements(): Element[];

이 메서드는 로케이터의 셀렉터와 일치하는 요소 배열을 반환합니다.

이 함수는 절대 오류를 발생시키지 않습니다. 셀렉터와 일치하는 요소가 없으면 이 메서드는 빈 배열을 반환합니다.

다음 DOM 구조를 고려해 보세요.

html
<div>Hello <span>World</span></div>
<div>Hello</div>

이 로케이터는 항상 성공합니다.

ts
page.getByText('Hello World').elements(); // ✅ [HTMLElement]
page.getByText('World').elements(); // ✅ [HTMLElement]
page.getByText('Hello', { exact: true }).elements(); // ✅ [HTMLElement]
page.getByText('Hello').element(); // ✅ [HTMLElement, HTMLElement]
page.getByText('Hello USA').elements(); // ✅ []

all ​

ts
function all(): Locator[];

이 메서드는 셀렉터와 일치하는 새 로케이터 배열을 반환합니다.

내부적으로 이 메서드는 .elements를 호출하고 page.elementLocator를 사용하여 모든 요소를 래핑합니다.

  • locator.elements() 참조

속성 ​

selector ​

selector는 브라우저 프로바이더가 요소를 찾는 데 사용하는 문자열입니다. Playwright는 playwright 로케이터 구문을 사용하며, preview 및 webdriverio는 CSS를 사용합니다.

DANGER

이 문자열은 테스트 코드에서 직접 사용해서는 안 됩니다. selector 문자열은 Commands API와 함께 사용할 때만 사용해야 합니다.

ts
import type { BrowserCommand } from 'vitest/node';

const test: BrowserCommand<string> = function test(context, selector) {
  // playwright
  await context.iframe.locator(selector).click();
  // webdriverio
  await context.browser.$(selector).click();
};
ts
import { test } from 'vitest';
import { commands, page } from '@vitest/browser/context';

test('works correctly', async () => {
  await commands.test(page.getByText('Hello').selector); // ✅
  // Vitest는 자동으로 문자열로 언래핑(unwrap)합니다.
  await commands.test(page.getByText('Hello')); // ✅
});

사용자 정의 로케이터 3.2.0+ 고급 ​

로케이터 팩토리(factory) 객체를 정의하여 기본 제공 로케이터 API를 확장할 수 있습니다. 이 메서드들은 page 객체와 생성된 모든 로케이터의 메서드로 존재합니다.

이러한 로케이터는 기본 제공 로케이터만으로는 충분하지 않을 때 유용할 수 있습니다. 예를 들어, UI에 사용자 정의 프레임워크를 사용하는 경우에 그렇습니다.

로케이터 팩토리는 셀렉터 문자열 또는 로케이터 자체를 반환해야 합니다.

TIP

셀렉터 구문은 Playwright 로케이터와 동일합니다. 자세한 내용은 해당 가이드를 읽어보세요.

ts
import { locators } from '@vitest/browser/context';

locators.extend({
  getByArticleTitle(title) {
    return `[data-title="${title}"]`;
  },
  getByArticleCommentsCount(count) {
    return `.comments :text("${count} comments")`;
  },
  async previewComments() {
    // "this"를 통해 현재 로케이터에 접근할 수 있습니다.
    // 메서드가 `page`에서 호출된 경우, `this`는 로케이터가 아닌 `page`가 됩니다!
    if (this !== page) {
      await this.click();
    }
    // ...
  },
});

// TypeScript를 사용하는 경우, LocatorSelectors 인터페이스를 확장하여
// locators.extend, page.* 및 locator.* 메서드에서 자동 완성을 사용할 수 있습니다.
declare module '@vitest/browser/context' {
  interface LocatorSelectors {
    // 사용자 정의 메서드가 문자열을 반환하면 로케이터로 변환됩니다.
    // 다른 것을 반환하면 평소와 같이 반환됩니다.
    getByArticleTitle(title: string): Locator;
    getByArticleCommentsCount(count: number): Locator;

    // Vitest는 프로미스(Promise)를 반환하며 로케이터로 변환을 시도하지 않습니다.
    previewComments(this: Locator): Promise<void>;
  }
}

메서드가 전역 page 객체에서 호출되면 셀렉터는 전체 페이지에 적용됩니다. 아래 예시에서 getByArticleTitle은 data-title 속성 값이 title인 모든 요소를 찾습니다. 하지만 메서드가 로케이터에서 호출되면 해당 로케이터로 범위가 지정됩니다.

html
<article data-title="Hello, World!">
  Hello, World!
  <button id="comments">2 comments</button>
</article>

<article data-title="Hello, Vitest!">
  Hello, Vitest!
  <button id="comments">0 comments</button>
</article>
ts
const articles = page.getByRole('article');
const worldArticle = page.getByArticleTitle('Hello, World!'); // ✅
const commentsElement = worldArticle.getByArticleCommentsCount(2); // ✅
const wrongCommentsElement = worldArticle.getByArticleCommentsCount(0); // ❌
const wrongElement = page.getByArticleTitle('No Article!'); // ❌

await commentsElement.previewComments(); // ✅
await wrongCommentsElement.previewComments(); // ❌
Pager
이전상호작용 API
다음Assertion API

MIT 라이선스 하에 배포되었습니다.

Copyright (c) 2021-Present Vitest Team

https://vitest.dev/guide/browser/locators

MIT 라이선스 하에 배포되었습니다.

Copyright (c) 2021-Present Vitest Team