mirror of
https://github.com/stablyai/orca.git
synced 2026-09-26 08:02:38 +00:00
fix(mobile): never replay a tap the host answered
A fulfilled browser.mouseClick ran on the host, but a null result still
replayed it as move/down/up. The native bridge always answers { clicked },
while the external-Chromium provider returns agent-browser's `data` as is,
which can be null, so a right-click there was a double tap. Only a refusal
that is not delivery-unknown now replays.
This commit is contained in:
@@ -11,17 +11,21 @@ import type { RpcClient } from '../transport/rpc-client'
|
||||
import { useMobileBrowserCommands } from './use-mobile-browser-commands'
|
||||
import { useMobileBrowserRequest } from './use-mobile-browser-request'
|
||||
|
||||
const { sent, clickFailure } = vi.hoisted(() => {
|
||||
const { sent, clickFailure, clickReply } = vi.hoisted(() => {
|
||||
const failure: { current: Error | null } = { current: null }
|
||||
return { sent: new Array<string>(), clickFailure: failure }
|
||||
const reply: { current: unknown } = { current: {} }
|
||||
return { sent: new Array<string>(), clickFailure: failure, clickReply: reply }
|
||||
})
|
||||
|
||||
vi.mock('./mobile-browser-command-operations', () => {
|
||||
const command = (method: string) => ({
|
||||
request: vi.fn(async () => {
|
||||
sent.push(method)
|
||||
if (method === 'browser.mouseClick' && clickFailure.current) {
|
||||
throw clickFailure.current
|
||||
if (method === 'browser.mouseClick') {
|
||||
if (clickFailure.current) {
|
||||
throw clickFailure.current
|
||||
}
|
||||
return clickReply.current
|
||||
}
|
||||
return {}
|
||||
}),
|
||||
@@ -85,6 +89,7 @@ describe('tap fallback', () => {
|
||||
beforeEach(() => {
|
||||
sent.length = 0
|
||||
clickFailure.current = null
|
||||
clickReply.current = {}
|
||||
})
|
||||
|
||||
it('does not replay a click whose delivery is unknown', async () => {
|
||||
@@ -100,6 +105,18 @@ describe('tap fallback', () => {
|
||||
expect(sent).toEqual(['browser.mouseClick'])
|
||||
})
|
||||
|
||||
// The external-Chromium provider answers a delivered click with agent-browser's `data`, which can be null.
|
||||
it('does not replay a click the host answered, whatever the answer', async () => {
|
||||
clickReply.current = null
|
||||
const commands = mountCommands()
|
||||
|
||||
await act(async () => {
|
||||
await commands.sendPointerClick({ x: 10, y: 20 }, 'right')
|
||||
})
|
||||
|
||||
expect(sent).toEqual(['browser.mouseClick'])
|
||||
})
|
||||
|
||||
it('replays a click the host refused as move, down and up', async () => {
|
||||
clickFailure.current = new Error('Unknown method: browser.mouseClick')
|
||||
const commands = mountCommands()
|
||||
|
||||
@@ -119,7 +119,7 @@ export function useMobileBrowserCommands(args: MobileBrowserCommandArgs) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const reply = browserPointerClick.interpret(
|
||||
browserPointerClick.interpret(
|
||||
await browserPointerClick.request(
|
||||
client,
|
||||
{
|
||||
@@ -143,18 +143,13 @@ export function useMobileBrowserCommands(args: MobileBrowserCommandArgs) {
|
||||
)
|
||||
)
|
||||
setError(null)
|
||||
if (reply !== null) {
|
||||
return
|
||||
}
|
||||
return
|
||||
} catch (error) {
|
||||
// Why: a timed-out click may still run on the host; replaying it as move/down/up double-taps.
|
||||
if (isRpcDeliveryUnknown(error)) {
|
||||
if (isRpcDeliveryUnknown(error) || pointerModifiers.length > 0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (pointerModifiers.length > 0) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const moveReply = await browserPointerMove.request(client, {
|
||||
...base,
|
||||
|
||||
Reference in New Issue
Block a user