ulixee / hero

The web browser built for scraping
MIT License
647 stars 32 forks source link

Exception from $click on disabled checkbox #256

Open eNcacz opened 3 months ago

eNcacz commented 3 months ago

When I click ($click()) on a disabled checkbox, then CanceledPromiseError (and sometimes TimeoutError) is raised after approx. 30s.

When I use click() method instead, then it returns immediately without any exceptions, which is IMHO right behavior.

Here is the web page source code, which I use for demonstration of this bug:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Testcase</title>
</head>
<body>
    <input type="checkbox" name="checkboxdisabled" id="checkboxdisabled" disabled>
    <label for="checkboxdisabled">This is a checkbox</label><br>
</body>
</html>

This is the TypeScript application which demonstrates the bug.

import Hero from '@ulixee/hero-playground';

(async () => {
  console.log('Running Hero');
  const hero = new Hero({ showChrome: true});
  await hero.goto('http://localhost/ulixee/index.html');  // <---- REPLACE THIS URL ACCORDING TO YOUR ENVIRONMENT
  await hero.waitForPaintingStable()
  console.log('Page loaded');

  const disabledCb = await hero.querySelector('#checkboxdisabled')
  await disabledCb.click()
  console.log('Checkbox clicked');
  await disabledCb.$click()
  console.log('Checkbox clicked again');

  await hero.close();
})();

And this is the output of the application:

/usr/bin/node /home/vaclav/sandbox/ulixee/app.js
Running Hero
Connecting to Ulixee Cloud at localhost:1818
Page loaded
Checkbox clicked

node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^
CanceledPromiseError: The page context to evaluate javascript was not found
    at Frame.evaluate (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/agent/main/lib/Frame.ts:323:15)
    at async MouseListener.didTriggerMouseEvent (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/agent/main/lib/MouseListener.ts:27:12)
    at async didTrigger (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/agent/main/lib/Interactor.ts:255:23)
    at async Interactor.playInteraction (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/agent/main/lib/Interactor.ts:355:26)
    at async DefaultHumanEmulator.moveMouseAndClick (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/plugins/default-human-emulator/index.ts:209:7)
    at async DefaultHumanEmulator.playInteractions (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/plugins/default-human-emulator/index.ts:90:11)
    at async Plugins.playInteractions (/home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/agent/main/lib/Plugins.ts:149:7)
    at async /home/vaclav/cr/payment-gateway/lib/be/python/ulixee-hero-browser/agent/main/lib/Interactor.ts:149:18
------REMOTE CORE---------------------------------
  at Function.reviver (/home/vaclav/sandbox/ulixee/node_modules/commons/lib/TypeSerializer.ts:249:26)
    at JSON.parse (<anonymous>)
    at Function.parse (/home/vaclav/sandbox/ulixee/node_modules/commons/lib/TypeSerializer.ts:31:17)
    at WsTransportToCore.onMessage (/home/vaclav/sandbox/ulixee/node_modules/net/lib/WsTransportToCore.ts:105:36)
    at WebSocket.emit (node:events:517:28)
    at Receiver.receiverOnMessage (/home/vaclav/sandbox/ulixee/node_modules/ws/lib/websocket.js:1068:20)
    at Receiver.emit (node:events:517:28)
    at Receiver.dataMessage (/home/vaclav/sandbox/ulixee/node_modules/ws/lib/receiver.js:517:14)
    at /home/vaclav/sandbox/ulixee/node_modules/ws/lib/receiver.js:468:23
    at /home/vaclav/sandbox/ulixee/node_modules/ws/lib/permessage-deflate.js:308:9
------CONNECTION----------------------------------
  at new Resolvable (/home/vaclav/sandbox/ulixee/node_modules/commons/lib/Resolvable.ts:19:18)
    at createPromise (/home/vaclav/sandbox/ulixee/node_modules/commons/lib/utils.ts:140:10)
    at PendingMessages.create (/home/vaclav/sandbox/ulixee/node_modules/net/lib/PendingMessages.ts:47:44)
    at ConnectionToHeroCore.sendRequest (/home/vaclav/sandbox/ulixee/node_modules/net/lib/ConnectionToCore.ts:158:50)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async CoreCommandQueue.sendRequest (/home/vaclav/sandbox/ulixee/node_modules/client/lib/CoreCommandQueue.ts:317:12)
    at async Object.cb (/home/vaclav/sandbox/ulixee/node_modules/client/lib/CoreCommandQueue.ts:231:16)
    at async Queue.next (/home/vaclav/sandbox/ulixee/node_modules/commons/lib/Queue.ts:188:19)
------CORE COMMANDS-------------------------------
    at Queue.run (/home/vaclav/sandbox/ulixee/node_modules/commons/lib/Queue.ts:63:19)
    at CoreCommandQueue.run (/home/vaclav/sandbox/ulixee/node_modules/client/lib/CoreCommandQueue.ts:220:8)
    at CoreFrameEnvironment.interact (/home/vaclav/sandbox/ulixee/node_modules/client/lib/CoreFrameEnvironment.ts:135:29)
    at Function.run (/home/vaclav/sandbox/ulixee/node_modules/client/lib/Interactor.ts:50:21)
    at HTMLInputElement.$click (/home/vaclav/sandbox/ulixee/node_modules/client/lib/DomExtender.ts:85:22)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

--------------------------------------------------
--------------------------------------------------
------6EjkN9K3JuP1rODFjGajA-----------------------
--------------------------------------------------

Node.js v18.19.0

I use this Ulixee version:

npm list
ulixee-poc@1.0.0 /home/vaclav/sandbox/ulixee
├── @types/node@20.11.30
├── @ulixee/hero-playground@2.0.0-alpha.28
└── typescript@5.4.3

Expected behavior

The $click() method will took less then 1s and did not raise any exceptions - as the click() method does.

blakebyrnes commented 3 months ago

I think what's happening here is that click verification is waiting and trying to confirm that the click occurred, but for a disabled field, it can't happen. I guess we could check if something is disabled - but I don't know how many different ways something can be disabled. I wonder if the right option here (assuming clickVerification:none works) would be a better error message

https://ulixee.org/docs/hero/basic-client/awaited-dom-extensions#click

eNcacz commented 3 months ago

I can confirm that using $click('none') works for me. Better error message will be definitely helpful.

You can close this issue, if you do not want to use it for better error message implementation tracking. I'm happy using the 'none' argument for $click(). Many thanks for your help.