Skip to content

Commit b1b2c67

Browse files
FIX: click (#161)
* test: click effectiveness * fix click after CDP change, add tests * disable rule
1 parent 2cb431c commit b1b2c67

File tree

3 files changed

+51
-27
lines changed

3 files changed

+51
-27
lines changed

src/__test__/custom-page.html

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
setTimeout(() => {
3939
box.style.top = Math.random() * 500
4040
}, 1000)
41+
window.boxWasClicked = false
42+
box.addEventListener('click', () => {
43+
window.boxWasClicked = true
44+
})
4145
</script>
4246

4347
</html>

src/__test__/spoof.spec.ts

+38-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import type { Page } from 'puppeteer'
1+
import type { ElementHandle, Page } from 'puppeteer'
22
import { type ClickOptions, createCursor, GhostCursor } from '../spoof'
33
import { join } from 'path'
4-
import { promises as fs } from 'fs'
4+
import { readFileSync } from 'fs'
55
import installMouseHelper from '../mouse-helper'
66

77
declare const page: Page
@@ -18,63 +18,76 @@ const cursorDefaultOptions = {
1818
inViewportMargin: 50
1919
} as const satisfies ClickOptions
2020

21+
declare global {
22+
// eslint-disable-next-line no-var
23+
var boxWasClicked: boolean
24+
}
25+
2126
describe('Mouse movements', () => {
27+
const html = readFileSync(join(__dirname, 'custom-page.html'), 'utf8')
28+
2229
beforeAll(async () => {
2330
await installMouseHelper(page)
24-
const html = await fs.readFile(join(__dirname, 'custom-page.html'), 'utf8')
31+
})
32+
33+
beforeEach(async () => {
2534
await page.goto('data:text/html,' + encodeURIComponent(html), {
2635
waitUntil: 'networkidle2'
2736
})
28-
})
2937

30-
beforeEach(() => {
3138
cursor = createCursor(page, undefined, undefined, {
3239
move: cursorDefaultOptions,
3340
click: cursorDefaultOptions,
3441
moveTo: cursorDefaultOptions
3542
})
3643
})
3744

45+
const testClick = async (clickSelector: string): Promise<void> => {
46+
expect(await page.evaluate(() => window.boxWasClicked)).toEqual(false)
47+
await cursor.click(clickSelector)
48+
expect(await page.evaluate(() => window.boxWasClicked)).toEqual(true)
49+
}
50+
3851
it('Should click on the element without throwing an error (CSS selector)', async () => {
39-
await cursor.click('#box1')
52+
await testClick('#box1')
4053
})
4154

4255
it('Should click on the element without throwing an error (XPath selector)', async () => {
43-
await cursor.click('//*[@id="box1"]')
56+
await testClick('//*[@id="box1"]')
4457
})
4558

4659
it('Should scroll to elements correctly', async () => {
4760
const getScrollPosition = async (): Promise<{ top: number, left: number }> => await page.evaluate(() => (
4861
{ top: window.scrollY, left: window.scrollX }
4962
))
5063

51-
const box1 = await page.waitForSelector('#box1')
52-
if (box1 == null) throw new Error('box not found')
53-
const box2 = await page.waitForSelector('#box2')
54-
if (box2 == null) throw new Error('box not found')
55-
const box3 = await page.waitForSelector('#box3')
56-
if (box3 == null) throw new Error('box not found')
64+
const boxes = await Promise.all([1, 2, 3].map(async (number: number): Promise<ElementHandle<HTMLElement>> => {
65+
const selector = `#box${number}`
66+
const box = await page.waitForSelector(selector) as ElementHandle<HTMLElement> | null
67+
if (box == null) throw new Error(`${selector} not found`)
68+
return box
69+
}))
5770

5871
expect(await getScrollPosition()).toEqual({ top: 0, left: 0 })
5972

60-
expect(await box1.isIntersectingViewport()).toBeTruthy()
61-
await cursor.click(box1)
73+
expect(await boxes[0].isIntersectingViewport()).toBeTruthy()
74+
await cursor.click(boxes[0])
6275
expect(await getScrollPosition()).toEqual({ top: 0, left: 0 })
63-
expect(await box1.isIntersectingViewport()).toBeTruthy()
76+
expect(await boxes[0].isIntersectingViewport()).toBeTruthy()
6477

65-
expect(await box2.isIntersectingViewport()).toBeFalsy()
66-
await cursor.move(box2)
78+
expect(await boxes[1].isIntersectingViewport()).toBeFalsy()
79+
await cursor.move(boxes[1])
6780
expect(await getScrollPosition()).toEqual({ top: 2500, left: 0 })
68-
expect(await box2.isIntersectingViewport()).toBeTruthy()
81+
expect(await boxes[1].isIntersectingViewport()).toBeTruthy()
6982

70-
expect(await box3.isIntersectingViewport()).toBeFalsy()
71-
await cursor.move(box3)
83+
expect(await boxes[2].isIntersectingViewport()).toBeFalsy()
84+
await cursor.move(boxes[2])
7285
expect(await getScrollPosition()).toEqual({ top: 4450, left: 2250 })
73-
expect(await box3.isIntersectingViewport()).toBeTruthy()
86+
expect(await boxes[2].isIntersectingViewport()).toBeTruthy()
7487

75-
expect(await box1.isIntersectingViewport()).toBeFalsy()
76-
await cursor.click(box1)
77-
expect(await box1.isIntersectingViewport()).toBeTruthy()
88+
expect(await boxes[0].isIntersectingViewport()).toBeFalsy()
89+
await cursor.click(boxes[0])
90+
expect(await boxes[0].isIntersectingViewport()).toBeTruthy()
7891
})
7992
})
8093

src/spoof.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -481,9 +481,16 @@ export const createCursor = (
481481

482482
try {
483483
await delay(optionsResolved.hesitate)
484-
await page.mouse.down()
484+
485+
const cdpClient = getCDPClient(page)
486+
const dispatchParams: Omit<Protocol.Input.DispatchMouseEventRequest, 'type'> = {
487+
...previous,
488+
button: 'left',
489+
clickCount: 1
490+
}
491+
await cdpClient.send('Input.dispatchMouseEvent', { ...dispatchParams, type: 'mousePressed' })
485492
await delay(optionsResolved.waitForClick)
486-
await page.mouse.up()
493+
await cdpClient.send('Input.dispatchMouseEvent', { ...dispatchParams, type: 'mouseReleased' })
487494
} catch (error) {
488495
log('Warning: could not click mouse, error message:', error)
489496
}

0 commit comments

Comments
 (0)