상호작용 API
Vitest는 이벤트를 가짜로 만드는 대신 Chrome DevTools Protocol 또는 webdriver를 사용하여 @testing-library/user-event
API의 하위 집합을 구현합니다. 이는 브라우저 동작을 사용자가 페이지와 상호작용하는 방식과 더 신뢰할 수 있고 일관되게 만듭니다.
import { userEvent } from '@vitest/browser/context';
await userEvent.click(document.querySelector('.button'));
거의 모든 userEvent
메서드는 공급자의 옵션을 상속합니다. IDE에서 사용 가능한 모든 옵션을 보려면 설정 파일 또는 구성 파일 (tsconfig.json
의 included
에 있는 내용에 따라 다름)에 webdriver
또는 playwright
유형(공급자에 따라 다름)을 추가하십시오.
/// <reference types="@vitest/browser/providers/playwright" />
/// <reference types="@vitest/browser/providers/webdriverio" />
userEvent.setup
function setup(): UserEvent;
새로운 사용자 이벤트 인스턴스를 생성합니다. 이는 키보드 상태를 유지하여 버튼을 올바르게 누르고 놓아야 할 때 유용합니다.
WARNING
@testing-library/user-event
와 달리, @vitest/browser/context
의 기본 userEvent
인스턴스는 메서드가 호출될 때마다 생성되는 것이 아니라 한 번 생성됩니다! 다음 스니펫에서 작동 방식의 차이를 확인할 수 있습니다.
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';
await vitestUserEvent.keyboard('{Shift}'); // Shift 키를 누른 상태로 유지
await vitestUserEvent.keyboard('{/Shift}'); // Shift 키를 놓음
await originalUserEvent.keyboard('{Shift}'); // Shift 키를 누른 상태로 유지
await originalUserEvent.keyboard('{/Shift}'); // 상태가 다르기 때문에 Shift 키를 놓지 않음
이 동작은 키보드를 시뮬레이션하지 않고 실제로 Shift 키를 누르기 때문에 더 유용합니다. 따라서 원래 동작을 유지하면 필드에 입력할 때 예기치 않은 문제가 발생할 수 있습니다.
userEvent.click
function click(
element: Element | Locator,
options?: UserEventClickOptions
): Promise<void>;
요소를 클릭합니다. 공급자의 옵션을 상속합니다. 이 메서드가 작동하는 방식에 대한 자세한 설명은 공급자의 문서를 참조하십시오.
import { page, userEvent } from '@vitest/browser/context';
test('clicks on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.click(logo);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await logo.click();
});
참조:
userEvent.dblClick
function dblClick(
element: Element | Locator,
options?: UserEventDoubleClickOptions
): Promise<void>;
요소에 더블 클릭 이벤트를 트리거합니다.
이 메서드가 작동하는 방식에 대한 자세한 설명은 공급자의 문서를 참조하십시오.
import { page, userEvent } from '@vitest/browser/context';
test('triggers a double click on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.dblClick(logo);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await logo.dblClick();
});
참조:
userEvent.tripleClick
function tripleClick(
element: Element | Locator,
options?: UserEventTripleClickOptions
): Promise<void>;
요소에 트리플 클릭 이벤트를 트리거합니다. 브라우저 API에는 tripleclick
이 없으므로 이 메서드는 연속으로 세 번의 클릭 이벤트를 발생시키므로 이벤트를 필터링하려면 클릭 이벤트 세부 정보를 확인해야 합니다: evt.detail === 3
.
이 메서드가 작동하는 방식에 대한 자세한 설명은 공급자의 문서를 참조하십시오.
import { page, userEvent } from '@vitest/browser/context';
test('triggers a triple click on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
let tripleClickFired = false;
logo.addEventListener('click', evt => {
if (evt.detail === 3) {
tripleClickFired = true;
}
});
await userEvent.tripleClick(logo);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await logo.tripleClick();
expect(tripleClickFired).toBe(true);
});
참조:
- Playwright
locator.click
API:clickCount: 3
을 사용하여click
을 통해 구현됩니다. - WebdriverIO
browser.action
API:move
와 세 번의down + up + pause
이벤트를 연속으로 사용하여 액션 API를 통해 구현됩니다. - testing-library
tripleClick
API
userEvent.fill
function fill(element: Element | Locator, text: string): Promise<void>;
input
/textarea
/contenteditable
필드에 값을 설정합니다. 이 메서드는 새 값을 설정하기 전에 입력 필드의 기존 텍스트를 지웁니다.
import { page, userEvent } from '@vitest/browser/context';
test('update input', async () => {
const input = page.getByRole('input');
await userEvent.fill(input, 'foo'); // input.value == foo
await userEvent.fill(input, '{{a[['); // input.value == {{a[[
await userEvent.fill(input, '{Shift}'); // input.value == {Shift}
// 또는 로케이터에서 직접 접근할 수 있습니다.
await input.fill('foo'); // input.value == foo
});
이 메서드는 요소에 포커스를 주고, 내용을 채운 후 input
이벤트를 발생시킵니다. 빈 문자열을 사용하여 필드를 지울 수 있습니다.
TIP
이 API는 userEvent.type
또는 userEvent.keyboard
를 사용하는 것보다 빠르지만, user-event keyboard
구문 (예: {Shift}{selectall}
)을 지원하지 않습니다.
특수 문자를 입력하거나 키 누름 이벤트를 세밀하게 제어할 필요가 없는 상황에서는 userEvent.type
대신 이 API를 사용하는 것이 좋습니다.
참조:
userEvent.keyboard
function keyboard(text: string): Promise<void>;
userEvent.keyboard
를 사용하면 키보드 스트로크를 트리거할 수 있습니다. 어떤 입력 필드에 포커스가 있으면 해당 입력 필드에 문자를 입력합니다. 그렇지 않으면 현재 포커스된 요소(포커스된 요소가 없으면 document.body
)에 키보드 이벤트를 트리거합니다.
이 API는 user-event keyboard
구문을 지원합니다.
import { userEvent } from '@vitest/browser/context';
test('trigger keystrokes', async () => {
await userEvent.keyboard('foo'); // 다음으로 변환: f, o, o
await userEvent.keyboard('{{a[['); // 다음으로 변환: {, a, [
await userEvent.keyboard('{Shift}{f}{o}{o}'); // 다음으로 변환: Shift, f, o, o
await userEvent.keyboard('{a>5}'); // a를 놓지 않고 누르고 5번의 keydown 트리거
await userEvent.keyboard('{a>5/}'); // a를 5번 keydown하고 놓음
});
참조:
userEvent.tab
function tab(options?: UserEventTabOptions): Promise<void>;
Tab
키 이벤트를 보냅니다. 이는 userEvent.keyboard('{tab}')
의 약어입니다.
import { page, userEvent } from '@vitest/browser/context';
test('tab works', async () => {
const [input1, input2] = page.getByRole('input').elements();
expect(input1).toHaveFocus();
await userEvent.tab();
expect(input2).toHaveFocus();
await userEvent.tab({ shift: true });
expect(input1).toHaveFocus();
});
참조:
userEvent.type
function type(
element: Element | Locator,
text: string,
options?: UserEventTypeOptions
): Promise<void>;
WARNING
특수 문자 (예: {shift}
또는 {selectall}
)에 의존하지 않는 경우, 더 나은 성능을 위해 userEvent.fill
을 대신 사용하는 것이 좋습니다.
type
메서드는 keyboard
API를 기반으로 구축된 @testing-library/user-event
의 type
유틸리티를 구현합니다.
이 함수를 사용하면 input
/textarea
/contenteditable
요소에 문자를 입력할 수 있습니다. user-event keyboard
구문을 지원합니다.
입력 필드 없이 문자를 누르기만 하면 되는 경우 userEvent.keyboard
API를 사용하십시오.
import { page, userEvent } from '@vitest/browser/context';
test('update input', async () => {
const input = page.getByRole('input');
await userEvent.type(input, 'foo'); // input.value == foo
await userEvent.type(input, '{{a[['); // input.value == foo{a[
await userEvent.type(input, '{Shift}'); // input.value == foo{a[
});
INFO
Vitest는 input.type
과 같이 로케이터에 .type
메서드를 노출하지 않습니다. 이는 userEvent
라이브러리와의 호환성을 위해서만 존재하기 때문입니다. 더 빠르므로 .fill
을 대신 사용하는 것을 고려하십시오.
참조:
userEvent.clear
function clear(
element: Element | Locator,
options?: UserEventClearOptions
): Promise<void>;
이 메서드는 입력 요소의 내용을 삭제합니다.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const input = page.getByRole('input');
await userEvent.fill(input, 'foo');
expect(input).toHaveValue('foo');
await userEvent.clear(input);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await input.clear();
expect(input).toHaveValue('');
});
참조:
userEvent.selectOptions
function selectOptions(
element: Element | Locator,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
userEvent.selectOptions
를 사용하면 <select>
요소에서 값을 선택할 수 있습니다.
WARNING
선택 요소에 multiple
속성이 없으면 Vitest는 배열의 첫 번째 요소만 선택합니다.
@testing-library
와 달리 Vitest는 현재 listbox를 지원하지 않지만, 향후 지원을 추가할 계획입니다.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const select = page.getByRole('select');
await userEvent.selectOptions(select, 'Option 1');
// 또는 로케이터에서 직접 접근할 수 있습니다.
await select.selectOptions('Option 1');
expect(select).toHaveValue('option-1');
await userEvent.selectOptions(select, 'option-1');
expect(select).toHaveValue('option-1');
await userEvent.selectOptions(select, [
page.getByRole('option', { name: 'Option 1' }),
page.getByRole('option', { name: 'Option 2' }),
]);
expect(select).toHaveValue(['option-1', 'option-2']);
});
WARNING
webdriverio
공급자는 여러 요소를 선택하는 API를 제공하지 않으므로 이 명령을 지원하지 않습니다.
참조:
- Playwright
locator.selectOption
API - WebdriverIO
element.selectByIndex
API - testing-library
selectOptions
API
userEvent.hover
function hover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
이 메서드는 커서 위치를 지정한 요소로 이동시킵니다. 이 메서드가 작동하는 방식에 대한 자세한 설명은 공급자의 문서를 참조하십시오.
WARNING
webdriverio
공급자를 사용하는 경우 커서는 기본적으로 요소의 중앙으로 이동합니다.
playwright
공급자를 사용하는 경우 커서는 요소의 "일부" 보이는 지점으로 이동합니다.
import { page, userEvent } from '@vitest/browser/context';
test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.hover(logo);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await logo.hover();
});
참조:
userEvent.unhover
function unhover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
이 기능은 userEvent.hover
와 동일하게 작동하지만, 커서를 document.body
요소로 이동시킵니다.
WARNING
기본적으로 커서 위치는 (playwright
공급자에서는) "일부" 보이는 위치에 있거나 (webdriverio
공급자에서는) 본문 요소의 중앙에 있으므로, 현재 호버된 요소가 이미 같은 위치에 있으면 이 메서드는 아무런 효과가 없습니다.
import { page, userEvent } from '@vitest/browser/context';
test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.unhover(logo);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await logo.unhover();
});
참조:
userEvent.upload
function upload(
element: Element | Locator,
files: string[] | string | File[] | File,
options?: UserEventUploadOptions
): Promise<void>;
파일 입력 요소에 지정된 파일을 설정합니다.
import { page, userEvent } from '@vitest/browser/context';
test('can upload a file', async () => {
const input = page.getByRole('button', { name: /Upload files/ });
const file = new File(['file'], 'file.png', { type: 'image/png' });
await userEvent.upload(input, file);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await input.upload(file);
// 프로젝트 루트를 기준으로 파일 경로를 사용할 수도 있습니다.
await userEvent.upload(input, './fixtures/file.png');
});
WARNING
webdriverio
공급자는 chrome
및 edge
브라우저에서만 이 명령을 지원합니다. 또한 현재 문자열 유형만 지원합니다.
참조:
userEvent.dragAndDrop
function dragAndDrop(
source: Element | Locator,
target: Element | Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
소스 요소를 대상 요소 위로 드래그합니다. source
요소에 draggable
속성이 true
로 설정되어 있어야 함을 잊지 마십시오.
import { page, userEvent } from '@vitest/browser/context';
test('drag and drop works', async () => {
const source = page.getByRole('img', { name: /logo/ });
const target = page.getByTestId('logo-target');
await userEvent.dragAndDrop(source, target);
// 또는 로케이터에서 직접 접근할 수 있습니다.
await source.dropTo(target);
await expect.element(target).toHaveTextContent('Logo is processed');
});
WARNING
이 API는 기본 preview
공급자에서는 지원되지 않습니다.
참조:
userEvent.copy
function copy(): Promise<void>;
선택한 텍스트를 클립보드로 복사합니다.
import { page, userEvent } from '@vitest/browser/context';
test('copy and paste', async () => {
// 'source'에 쓰기
await userEvent.click(page.getByPlaceholder('source'));
await userEvent.keyboard('hello');
// 'source' 선택 및 복사
await userEvent.dblClick(page.getByPlaceholder('source'));
await userEvent.copy();
// 'target'에 붙여넣기
await userEvent.click(page.getByPlaceholder('target'));
await userEvent.paste();
await expect
.element(page.getByPlaceholder('source'))
.toHaveTextContent('hello');
await expect
.element(page.getByPlaceholder('target'))
.toHaveTextContent('hello');
});
참조:
userEvent.cut
function cut(): Promise<void>;
선택한 텍스트를 클립보드로 잘라냅니다.
import { page, userEvent } from '@vitest/browser/context';
test('copy and paste', async () => {
// 'source'에 쓰기
await userEvent.click(page.getByPlaceholder('source'));
await userEvent.keyboard('hello');
// 'source' 선택 및 잘라내기
await userEvent.dblClick(page.getByPlaceholder('source'));
await userEvent.cut();
// 'target'에 붙여넣기
await userEvent.click(page.getByPlaceholder('target'));
await userEvent.paste();
await expect.element(page.getByPlaceholder('source')).toHaveTextContent('');
await expect
.element(page.getByPlaceholder('target'))
.toHaveTextContent('hello');
});
참조:
userEvent.paste
function paste(): Promise<void>;
클립보드의 텍스트를 붙여넣습니다. 사용 예시는 userEvent.copy
및 userEvent.cut
를 참조하십시오.
참조: