diff --git a/packages/browser/src/client/tester/context.ts b/packages/browser/src/client/tester/context.ts index 881dd808b9e8..368f1e61a009 100644 --- a/packages/browser/src/client/tester/context.ts +++ b/packages/browser/src/client/tester/context.ts @@ -1,6 +1,6 @@ import type { Task, WorkerGlobalState } from 'vitest' import type { BrowserRPC } from '@vitest/browser/client' -import type { BrowserPage, UserEvent, UserEventClickOptions, UserEventTabOptions, UserEventTypeOptions } from '../../../context' +import type { BrowserPage, UserEvent, UserEventClickOptions, UserEventHoverOptions, UserEventTabOptions, UserEventTypeOptions } from '../../../context' import type { BrowserRunnerState } from '../utils' // this file should not import anything directly, only types @@ -137,13 +137,13 @@ function createUserEvent(): UserEvent { ) keyboard.unreleased = unreleased }, - hover(element: Element) { + hover(element: Element, options: UserEventHoverOptions = {}) { const css = convertElementToCssSelector(element) - return triggerCommand('__vitest_hover', css) + return triggerCommand('__vitest_hover', css, options) }, - unhover(element: Element) { + unhover(element: Element, options: UserEventHoverOptions = {}) { const css = convertElementToCssSelector(element.ownerDocument.body) - return triggerCommand('__vitest_hover', css) + return triggerCommand('__vitest_hover', css, options) }, // non userEvent events, but still useful diff --git a/test/browser/test/userEvent.test.ts b/test/browser/test/userEvent.test.ts index 44351d778fab..27ad21be30f1 100644 --- a/test/browser/test/userEvent.test.ts +++ b/test/browser/test/userEvent.test.ts @@ -155,13 +155,14 @@ describe('userEvent.tripleClick', () => { }) describe('userEvent.hover, userEvent.unhover', () => { - test('hover works correctly', async () => { + test('hover, unhover works correctly', async () => { const target = document.createElement('div') target.style.width = '100px' target.style.height = '100px' let mouseEntered = false let pointerEntered = false + target.addEventListener('mouseover', () => { mouseEntered = true }) @@ -188,6 +189,46 @@ describe('userEvent.hover, userEvent.unhover', () => { expect(mouseEntered).toBe(false) }) + test.runIf(server.provider === 'playwright')('hover, unhover correctly pass options', async () => { + interface ModifiersDetected { shift: boolean; control: boolean } + type ModifierKeys = 'Shift' | 'Control' | 'Alt' | 'ControlOrMeta' | 'Meta' + + const hoverOptions = { modifiers: ['Shift'] as ModifierKeys[] } + const unhoverOptions = { modifiers: ['Control'] as ModifierKeys[] } + + const target = document.createElement('div') + target.style.width = '100px' + target.style.height = '100px' + + let modifiersDetected: ModifiersDetected = { + shift: false, + control: false, + } + + target.addEventListener('mouseover', (e) => { + modifiersDetected.shift = e.shiftKey + modifiersDetected.control = e.ctrlKey + }) + + target.addEventListener('mouseout', (e) => { + modifiersDetected.shift = e.shiftKey + modifiersDetected.control = e.ctrlKey + }) + + document.body.appendChild(target) + + await userEvent.hover(target, hoverOptions) + + expect(modifiersDetected.shift).toEqual(hoverOptions.modifiers.includes('Shift')) + expect(modifiersDetected.control).toEqual(hoverOptions.modifiers.includes('Control')) + modifiersDetected = { shift: false, control: false } + + await userEvent.unhover(target, unhoverOptions) + + expect(modifiersDetected.shift).toEqual(unhoverOptions.modifiers.includes('Shift')) + expect(modifiersDetected.control).toEqual(unhoverOptions.modifiers.includes('Control')) + }) + test('hover works with shadow root', async () => { const shadowRoot = createShadowRoot() const target = document.createElement('div') @@ -210,6 +251,7 @@ describe('userEvent.hover, userEvent.unhover', () => { }) shadowRoot.appendChild(target) + expect.poll(() => document.body.contains(target)).toBeTruthy() await userEvent.hover(target)