Skip to content

Commit

Permalink
feat(browser): add tripleClick to interactive api (#5987)
Browse files Browse the repository at this point in the history
  • Loading branch information
userquin authored Jun 28, 2024
1 parent 152891b commit 200a434
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 1 deletion.
25 changes: 25 additions & 0 deletions docs/guide/browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,31 @@ References:
- [WebdriverIO `element.doubleClick` API](https://webdriver.io/docs/api/element/doubleClick/)
- [testing-library `dblClick` API](https://testing-library.com/docs/user-event/convenience/#dblClick)

### userEvent.tripleClick

- **Type:** `(element: Element, options?: UserEventTripleClickOptions) => Promise<void>`

Triggers a triple click event on an element

Please refer to your provider's documentation for detailed explanation about how this method works.

```ts
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'

test('triggers a triple click on an element', async () => {
const logo = screen.getByRole('img', { name: /logo/ })

await userEvent.tripleClick(logo)
})
```

References:

- [Playwright `locator.click` API](https://playwright.dev/docs/api/class-locator#locator-click)
- [WebdriverIO `browser.action` API](https://webdriver.io/docs/api/browser/action/)
- [testing-library `tripleClick` API](https://testing-library.com/docs/user-event/convenience/#tripleClick)

### userEvent.fill

- **Type:** `(element: Element, text: string) => Promise<void>`
Expand Down
8 changes: 8 additions & 0 deletions packages/browser/context.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ export interface UserEvent {
* @see {@link https://testing-library.com/docs/user-event/convenience/#dblClick} testing-library API
*/
dblClick: (element: Element, options?: UserEventDoubleClickOptions) => Promise<void>
/**
* Triggers a triple click event on an element. Uses provider's API under the hood.
* @see {@link https://playwright.dev/docs/api/class-locator#locator-click} Playwright API: using `click` with `clickCount: 3`
* @see {@link https://webdriver.io/docs/api/browser/actions/} WebdriverIO API: using actions with `move` and 3 `down + up + down` events in a row
* @see {@link https://testing-library.com/docs/user-event/convenience/#tripleclick} testing-library API
*/
tripleClick: (element: Element, options?: UserEventTripleClickOptions) => Promise<void>
/**
* Choose one or more values from a select element. Uses provider's API under the hood.
* If select doesn't have `multiple` attribute, only the first value will be selected.
Expand Down Expand Up @@ -165,6 +172,7 @@ export interface UserEventHoverOptions {}
export interface UserEventSelectOptions {}
export interface UserEventClickOptions {}
export interface UserEventDoubleClickOptions {}
export interface UserEventTripleClickOptions {}
export interface UserEventDragAndDropOptions {}

export interface UserEventTabOptions {
Expand Down
4 changes: 4 additions & 0 deletions packages/browser/src/client/tester/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export const userEvent: UserEvent = {
const xpath = convertElementToXPath(element)
return triggerCommand('__vitest_dblClick', xpath, options)
},
tripleClick(element: Element, options: UserEventClickOptions = {}) {
const xpath = convertElementToXPath(element)
return triggerCommand('__vitest_tripleClick', xpath, options)
},
selectOptions(element, value) {
const values = provider === 'webdriverio'
? getWebdriverioSelectOptions(element, value)
Expand Down
39 changes: 39 additions & 0 deletions packages/browser/src/node/commands/click.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,42 @@ export const dblClick: UserEventCommand<UserEvent['dblClick']> = async (
throw new TypeError(`Provider "${provider.name}" doesn't support dblClick command`)
}
}

export const tripleClick: UserEventCommand<UserEvent['tripleClick']> = async (
context,
xpath,
options = {},
) => {
const provider = context.provider
if (provider instanceof PlaywrightBrowserProvider) {
const tester = context.iframe
await tester.locator(`xpath=${xpath}`).click({
timeout: 1000,
...options,
clickCount: 3,
})
}
else if (provider instanceof WebdriverBrowserProvider) {
const browser = context.browser
const markedXpath = `//${xpath}`
await browser
.action('pointer', { parameters: { pointerType: 'mouse' } })
// move the pointer over the button
.move({ origin: await browser.$(markedXpath) })
// simulate 3 clicks
.down()
.up()
.pause(50)
.down()
.up()
.pause(50)
.down()
.up()
.pause(50)
// run the sequence
.perform()
}
else {
throw new TypeError(`Provider "${provider.name}" doesn't support tripleClick command`)
}
}
3 changes: 2 additions & 1 deletion packages/browser/src/node/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { click, dblClick } from './click'
import { click, dblClick, tripleClick } from './click'
import { type } from './type'
import { clear } from './clear'
import { fill } from './fill'
Expand All @@ -20,6 +20,7 @@ export default {
writeFile,
__vitest_click: click,
__vitest_dblClick: dblClick,
__vitest_tripleClick: tripleClick,
__vitest_screenshot: screenshot,
__vitest_type: type,
__vitest_clear: clear,
Expand Down
46 changes: 46 additions & 0 deletions test/browser/test/userEvent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,52 @@ describe('userEvent.dblClick', () => {
})
})

describe('userEvent.tripleClick', () => {
test('correctly clicks a button', async () => {
const button = document.createElement('button')
button.textContent = 'Click me'
document.body.appendChild(button)
const onClick = vi.fn()
const dblClick = vi.fn()
const tripleClick = vi.fn()
button.addEventListener('click', onClick)
button.addEventListener('dblclick', dblClick)
button.addEventListener('click', tripleClick)

await userEvent.tripleClick(button)

expect(onClick).toHaveBeenCalledTimes(3)
expect(dblClick).toHaveBeenCalledTimes(1)
expect(tripleClick).toHaveBeenCalledTimes(3)
expect(tripleClick.mock.calls.length).toBe(3)
expect(tripleClick.mock.calls
.map(c => c[0] as MouseEvent)
.filter(c => c.detail === 3)).toHaveLength(1)
})

test('correctly doesn\'t click on a disabled button', async () => {
const button = document.createElement('button')
button.textContent = 'Click me'
button.disabled = true
document.body.appendChild(button)
const onClick = vi.fn()
const dblClick = vi.fn()
const tripleClick = vi.fn()
button.addEventListener('click', onClick)
button.addEventListener('dblclick', dblClick)
button.addEventListener('click', tripleClick)

await userEvent.tripleClick(button, {
// playwright requires force: true to click on a disabled button
force: true,
})

expect(onClick).not.toHaveBeenCalled()
expect(dblClick).not.toHaveBeenCalled()
expect(tripleClick).not.toHaveBeenCalled()
})
})

describe('userEvent.hover, userEvent.unhover', () => {
test('hover works correctly', async () => {
const target = document.createElement('div')
Expand Down

0 comments on commit 200a434

Please sign in to comment.