diff --git a/docs/guide/browser/interactivity-api.md b/docs/guide/browser/interactivity-api.md index 301ade07c19f..8d2697b687cd 100644 --- a/docs/guide/browser/interactivity-api.md +++ b/docs/guide/browser/interactivity-api.md @@ -59,9 +59,33 @@ test('clicks on an element', async () => { await userEvent.click(logo) // or you can access it directly on the locator await logo.click() + + // With WebdriverIO, this uses either ElementClick (with no arguments) or + // actions (with arguments). Use an empty object to force the use of actions. + await logo.click({}) }) ``` +### Clicking with a modifier + +With either WebdriverIO or Playwright: + +```ts +await userEvent.keyboard('{Shift>}') +// By using an empty object as the option, this opts in to using a chain of actions +// instead of an ElementClick in webdriver. +// Firefox has a bug that makes this necessary. +// Follow https://bugzilla.mozilla.org/show_bug.cgi?id=1456642 to know when this +// will be fixed. +await userEvent.click(element, {}) +await userEvent.keyboard('{/Shift}') +``` + +With Playwright: +```ts +await userEvent.click(element, { modifiers: ['Shift'] }) +``` + References: - [Playwright `locator.click` API](https://playwright.dev/docs/api/class-locator#locator-click) diff --git a/packages/browser-webdriverio/src/commands/click.ts b/packages/browser-webdriverio/src/commands/click.ts index 292103eba281..997850a8dc5b 100644 --- a/packages/browser-webdriverio/src/commands/click.ts +++ b/packages/browser-webdriverio/src/commands/click.ts @@ -4,16 +4,16 @@ import type { UserEventCommand } from './utils' export const click: UserEventCommand = async ( context, selector, - options = {}, + options, ) => { const browser = context.browser - await browser.$(selector).click(options as any) + await browser.$(selector).click(options) } export const dblClick: UserEventCommand = async ( context, selector, - _options = {}, + _options, ) => { const browser = context.browser await browser.$(selector).doubleClick() @@ -22,7 +22,7 @@ export const dblClick: UserEventCommand = async ( export const tripleClick: UserEventCommand = async ( context, selector, - _options = {}, + _options, ) => { const browser = context.browser await browser diff --git a/packages/browser/src/client/tester/locators/index.ts b/packages/browser/src/client/tester/locators/index.ts index 1e1706fab2c1..14a715c9064a 100644 --- a/packages/browser/src/client/tester/locators/index.ts +++ b/packages/browser/src/client/tester/locators/index.ts @@ -74,15 +74,15 @@ export abstract class Locator { }) } - public click(options: UserEventClickOptions = {}): Promise { + public click(options?: UserEventClickOptions): Promise { return this.triggerCommand('__vitest_click', this.selector, options) } - public dblClick(options: UserEventClickOptions = {}): Promise { + public dblClick(options?: UserEventClickOptions): Promise { return this.triggerCommand('__vitest_dblClick', this.selector, options) } - public tripleClick(options: UserEventClickOptions = {}): Promise { + public tripleClick(options?: UserEventClickOptions): Promise { return this.triggerCommand('__vitest_tripleClick', this.selector, options) } diff --git a/test/browser/fixtures/user-event/keyboard.test.ts b/test/browser/fixtures/user-event/keyboard.test.ts index aced4c255e5c..de88b2eca5c0 100644 --- a/test/browser/fixtures/user-event/keyboard.test.ts +++ b/test/browser/fixtures/user-event/keyboard.test.ts @@ -63,7 +63,8 @@ test('click with modifier', async () => { }); await userEvent.keyboard('{Shift>}') - await userEvent.click(el) + // By using an empty object as the option, this opts in to using a chain of actions instead of an elementClick in webdriver. + await userEvent.click(el, {}) await userEvent.keyboard('{/Shift}') await expect.poll(() => el.textContent).toContain("[ok]") }) diff --git a/test/browser/test/userEvent.test.ts b/test/browser/test/userEvent.test.ts index 10a7f93c4a77..3c472daf2561 100644 --- a/test/browser/test/userEvent.test.ts +++ b/test/browser/test/userEvent.test.ts @@ -23,12 +23,23 @@ describe('userEvent.click', () => { document.body.appendChild(button) const onClick = vi.fn() const dblClick = vi.fn() + // Make sure a contextmenu doesn't actually appear, as it may make some + // tests fail later. + const onContextmenu = vi.fn(e => e.preventDefault()) button.addEventListener('click', onClick) + button.addEventListener('dblclick', onClick) + button.addEventListener('contextmenu', onContextmenu) await userEvent.click(button) expect(onClick).toHaveBeenCalled() expect(dblClick).not.toHaveBeenCalled() + expect(onContextmenu).not.toHaveBeenCalled() + + onClick.mockClear() + await userEvent.click(button, { button: 'right' }) + expect(onClick).not.toHaveBeenCalled() + expect(onContextmenu).toHaveBeenCalled() }) test('correctly doesn\'t click on a disabled button', async () => {