Text input — fill vs type
fill is what you want 95% of the time — it focuses the field, clears it, sets the value, and fires the input event. Fast and reliable. Use it for login forms, order creation, search fields.
pressSequentially types character by character — useful for testing autocomplete or fields that react to each keystroke. It's slower than fill on purpose.
test('fill login form', async ({ page }) => {
await page.goto('/login')
// fill — найшвидший і найнадійніший спосіб
await page.getByLabel('Email').fill('admin@example.com')
await page.getByLabel('Password').fill(process.env.TEST_PASSWORD!)
// Дата, час — теж через fill
await page.getByLabel('Order date').fill('2026-05-14')
await page.getByLabel('Delivery time').fill('14:30')
await page.getByRole('button', { name: 'Sign in' }).click()
})
test('autocomplete reacts to typing', async ({ page }) => {
await page.goto('/orders/new')
// pressSequentially — символ за символом, для autocomplete
await page.getByLabel('Customer name').pressSequentially('Iva', { delay: 50 })
// Autocomplete список з'явився
await expect(page.getByRole('listbox')).toBeVisible()
await page.getByRole('option', { name: 'Ivan Kozenko' }).click()
})
Checkboxes and radio buttons
check() and uncheck() are semantic — they verify the current state first. check() on an already-checked box does nothing. setChecked(true/false) explicitly sets the state regardless. I use check() for clarity and setChecked when I need to be explicit about the end state.
test('accept terms and subscribe', async ({ page }) => {
await page.goto('/register')
await page.getByLabel('I agree to the terms').check()
await expect(page.getByLabel('I agree to the terms')).toBeChecked()
// Відмінити
await page.getByLabel('Subscribe to newsletter').uncheck()
await expect(page.getByLabel('Subscribe to newsletter')).not.toBeChecked()
// setChecked — явна установка
await page.getByLabel('Send notifications').setChecked(true)
})
test('select delivery method', async ({ page }) => {
await page.goto('/checkout')
// Радіокнопка — те саме API
await page.getByLabel('Express delivery').check()
await expect(page.getByLabel('Express delivery')).toBeChecked()
await expect(page.getByLabel('Standard delivery')).not.toBeChecked()
})
Select dropdowns
selectOption works on native <select> elements. You can select by value (what's in the value attribute), by label (what the user sees), or by index. For multiple-select, pass an array.
test('filter orders by status', async ({ page }) => {
await page.goto('/orders')
// За value — те що в HTML <option value="pending">
await page.getByRole('combobox', { name: 'Status' }).selectOption('pending')
// За label — те що бачить користувач
await page.getByRole('combobox', { name: 'Status' }).selectOption({ label: 'Pending' })
// За індексом (з 0)
await page.getByRole('combobox', { name: 'Items per page' }).selectOption({ index: 2 })
// Multi-select
await page.getByLabel('Tags').selectOption(['urgent', 'vip', 'export'])
})
Clicks and mouse actions
click() is the most-used action — it waits for the element to be visible, stable (animations done), and not obscured. It also scrolls the element into view first. Variants: dblclick(), right-click with { button: 'right' }, shift+click with { modifiers: ['Shift'] }.
test('order table interactions', async ({ page }) => {
await page.goto('/orders')
// Звичайний клік
await page.getByRole('button', { name: 'Create order' }).click()
// Подвійний клік (відкрити для редагування)
await page.getByRole('row').filter({ hasText: 'ORDER-042' }).dblclick()
// Правий клік (контекстне меню)
await page.getByRole('row').filter({ hasText: 'ORDER-007' })
.click({ button: 'right' })
await page.getByRole('menuitem', { name: 'Archive' }).click()
// Ctrl+клік (мульти-вибір)
await page.getByRole('row').nth(1).click()
await page.getByRole('row').nth(3).click({ modifiers: ['ControlOrMeta'] })
await page.getByRole('row').nth(5).click({ modifiers: ['ControlOrMeta'] })
// Hover (показати тултіп)
await page.getByTestId('info-icon').hover()
await expect(page.getByRole('tooltip')).toBeVisible()
})
Keyboard shortcuts and key presses
press() sends a keyboard event to the focused element. Common use cases: submitting forms with Enter, clearing fields with Control+A then Backspace, navigating with ArrowDown/Tab. For combinations, use + separator.
test('keyboard navigation in order form', async ({ page }) => {
await page.goto('/orders/new')
const nameField = page.getByLabel('Customer name')
await nameField.fill('Test')
// Очистити і ввести нове значення
await nameField.press('Control+a')
await nameField.press('Backspace')
await nameField.fill('Ivan Kozenko')
// Enter для відправки форми
await page.getByLabel('Search').press('Enter')
// Tab між полями
await page.getByLabel('First name').press('Tab') // переходить на Last name
// Escape для закриття модального
await page.keyboard.press('Escape')
await expect(page.getByRole('dialog')).not.toBeVisible()
// Arrow down в dropdown
await page.getByRole('combobox', { name: 'Status' }).press('ArrowDown')
})
File upload
setInputFiles sets files on an <input type="file"> element without opening the OS file picker. Pass a file path or multiple paths for multi-file inputs. For drag-and-drop upload zones, use page.dragAndDrop() or dispatchEvent.
test('upload order document', async ({ page }) => {
await page.goto('/orders/42/documents')
// Один файл
await page.getByLabel('Upload document').setInputFiles('tests/fixtures/invoice.pdf')
// Кілька файлів
await page.getByLabel('Upload documents').setInputFiles([
'tests/fixtures/invoice.pdf',
'tests/fixtures/contract.pdf',
])
// Очистити вибір файлів
await page.getByLabel('Upload document').setInputFiles([])
await page.getByRole('button', { name: 'Submit' }).click()
await expect(page.getByText('2 documents uploaded')).toBeVisible()
})
Drag and drop
For HTML5 drag-and-drop (elements with draggable attribute), page.dragAndDrop() handles the whole sequence. For custom drag implementations that listen to mouse events directly, use the lower-level mouse.down(), mouse.move(), mouse.up() sequence.
test('reorder items in kanban', async ({ page }) => {
await page.goto('/orders/kanban')
// HTML5 dragAndDrop: з "Pending" колонки до "In Progress"
await page.dragAndDrop(
'[data-testid="card-ORDER-042"]',
'[data-testid="column-in-progress"]'
)
await expect(
page.getByTestId('column-in-progress').getByText('ORDER-042')
).toBeVisible()
})