tauri-apps / tauri

Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
https://tauri.app
Apache License 2.0
82.69k stars 2.48k forks source link

[bug] tauri-driver errors when trying .click(), .setValue() #6541

Open Sheap opened 1 year ago

Sheap commented 1 year ago

Describe the bug

When trying to use webdriver.io for e2e testing, many basic functions do not work, and simply return Request failed with status 500 due to unsupported operation: unknown error

There are workarounds (using browser.execute, but having to manually replace these basic functions is tedious, and they are not exactly the same behaviourally.

Reproduction

  1. extend hello_tauri with a button which changes it's contents on click:
    <script type="text/javascript">
        function handleClick() {
            document.getElementById("click-test").innerHTML = "Thank you"
        }
    </script>
    ...
    <button id="click-test" onClick="handleClick()">Click me</button>
  2. Add a test for this button:
    it("should click button", async () => {
    const button = await $("#click-test");
    await button.waitForClickable();
    await button.click();
    expect(button.getText()).toMatch("Thank you");
    });

Expected behavior

The test should pass

Platform and versions

Environment
  › OS: Fedora 37 X64
  › Node.js: 18.14.2
  › npm: 9.5.0
  › pnpm: 7.27.0
  › yarn: 1.22.19
  › rustup: 1.25.2
  › rustc: 1.67.1
  › cargo: 1.67.1
  › Rust toolchain: stable-x86_64-unknown-linux-gnu

Packages
  › @tauri-apps/cli [NPM]: 2.0.0-alpha.2
  › @tauri-apps/api [NPM]: Not installed!
  › tauri [RUST]: 1.0.0-rc.3,
  › tauri-build [RUST]: 1.0.0-rc.3,
  › tao [RUST]: 0.6.2,
  › wry [RUST]: 0.13.2,

App
  › build-type: build
  › CSP: unset
  › distDir: dist
  › devPath: dist

App directory structure
  ├─ selenium
  ├─ webdriverio
  └─ node_modules

Stack trace

[0-0] 2023-03-24T08:12:25.996Z INFO webdriver: RESULT true
[0-0] 2023-03-24T08:12:25.996Z INFO webdriver: COMMAND elementClick("node-2E82D59D-A27A-4CAD-AE82-37C8E442F334")
[0-0] 2023-03-24T08:12:25.997Z INFO webdriver: [POST] http://127.0.0.1:4444/session/5194703d-38d0-477a-ae51-a9495d5fa0cd/element/node-2E82D59D-A27A-4CAD-AE82-37C8E442F334/click
[0-0] 2023-03-24T08:12:26.001Z WARN webdriver: Request failed with status 500 due to unknown error
[0-0] 2023-03-24T08:12:26.001Z INFO webdriver: Retrying 1/3
[0-0] 2023-03-24T08:12:26.001Z INFO webdriver: [POST] http://127.0.0.1:4444/session/5194703d-38d0-477a-ae51-a9495d5fa0cd/element/node-2E82D59D-A27A-4CAD-AE82-37C8E442F334/click
[0-0] 2023-03-24T08:12:26.044Z WARN webdriver: Request failed with status 500 due to unknown error
[0-0] 2023-03-24T08:12:26.044Z INFO webdriver: Retrying 2/3
[0-0] 2023-03-24T08:12:26.044Z INFO webdriver: [POST] http://127.0.0.1:4444/session/5194703d-38d0-477a-ae51-a9495d5fa0cd/element/node-2E82D59D-A27A-4CAD-AE82-37C8E442F334/click
[0-0] 2023-03-24T08:12:26.048Z WARN webdriver: Request failed with status 500 due to unknown error
[0-0] 2023-03-24T08:12:26.048Z INFO webdriver: Retrying 3/3
[0-0] 2023-03-24T08:12:26.048Z INFO webdriver: [POST] http://127.0.0.1:4444/session/5194703d-38d0-477a-ae51-a9495d5fa0cd/element/node-2E82D59D-A27A-4CAD-AE82-37C8E442F334/click
[0-0] 2023-03-24T08:12:26.093Z ERROR webdriver: Request failed with status 500 due to unsupported operation: unknown error
[0-0] unsupported operation in "Hello Tauri should click button"
unsupported operation: unknown error
    at Object.getErrorFromResponseBody (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/webdriver/build/utils.js:189:12)
    at NodeJSRequest._request (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/webdriver/build/request/index.js:157:31)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
    at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
    at async Element.elementErrorHandlerCallbackFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/runner/node_modules/webdriverio/build/middlewares.js:23:32)
    at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
    at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
    at async Element.elementErrorHandlerCallbackFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/runner/node_modules/webdriverio/build/middlewares.js:23:32)
    at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
[0-0] 2023-03-24T08:12:26.095Z INFO webdriver: COMMAND deleteSession()
[0-0] 2023-03-24T08:12:26.095Z INFO webdriver: [DELETE] http://127.0.0.1:4444/session/5194703d-38d0-477a-ae51-a9495d5fa0cd
[0-0] FAILED in undefined - /test/specs/example.e2e.js
2023-03-24T08:12:26.214Z INFO @wdio/cli:launcher: Run onComplete hook

 "spec" Reporter:
------------------------------------------------------------------
[wry 0.13.2 linux #0-0] Running: wry (v0.13.2) on linux
[wry 0.13.2 linux #0-0] Session ID: 5194703d-38d0-477a-ae51-a9495d5fa0cd
[wry 0.13.2 linux #0-0]
[wry 0.13.2 linux #0-0] » /test/specs/example.e2e.js
[wry 0.13.2 linux #0-0] Hello Tauri
[wry 0.13.2 linux #0-0]    ✓ should be cordial
[wry 0.13.2 linux #0-0]    ✓ should be excited
[wry 0.13.2 linux #0-0]    ✓ should be easy on the eyes
[wry 0.13.2 linux #0-0]    ✖ should click button
[wry 0.13.2 linux #0-0]
[wry 0.13.2 linux #0-0] 3 passing (460ms)
[wry 0.13.2 linux #0-0] 1 failing
[wry 0.13.2 linux #0-0]
[wry 0.13.2 linux #0-0] 1) Hello Tauri should click button
[wry 0.13.2 linux #0-0] unknown error
[wry 0.13.2 linux #0-0] unsupported operation: unknown error
[wry 0.13.2 linux #0-0]     at Object.getErrorFromResponseBody (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/webdriver/build/utils.js:189:12)
[wry 0.13.2 linux #0-0]     at NodeJSRequest._request (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/webdriver/build/request/index.js:157:31)
[wry 0.13.2 linux #0-0]     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
[wry 0.13.2 linux #0-0]     at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
[wry 0.13.2 linux #0-0]     at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
[wry 0.13.2 linux #0-0]     at async Element.elementErrorHandlerCallbackFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/runner/node_modules/webdriverio/build
/middlewares.js:23:32)
[wry 0.13.2 linux #0-0]     at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
[wry 0.13.2 linux #0-0]     at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)
[wry 0.13.2 linux #0-0]     at async Element.elementErrorHandlerCallbackFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/runner/node_modules/webdriverio/build
/middlewares.js:23:32)
[wry 0.13.2 linux #0-0]     at async Element.wrapCommandFn (/home/stuart/motius-projects/aumovis/hello_tauri/webdriver/node_modules/@wdio/utils/build/shim.js:103:29)

Additional context

.setValue() had similar issues for me, and the workaround (at least in a svelte app) were more complicated, as you also need to get events to fire properly. I used click as the example here as it is simpler.

For others having trouble with this issue, here are my current workarounds:

click

async function findAndClick (selector: string, timeout?: number) {
  const button = await $(selector);
  await button.waitForClickable({
    timeout,
  });
  await browser.execute('arguments[0].click();', button);
}

setValue

async function setValue (selector: string, value: number | string) {
  const field = await $(selector);
  await browser.execute(`arguments[0].value="${value}"`, field);
  await browser.execute('arguments[0].dispatchEvent(new Event("input", { bubbles: true }))', field);
}
Sheap commented 1 year ago

Note: I'm not 100% sure I understand the boundary here between webdriver and tauri-driver. I suspect this issue is on the tauri driver end, as the error is coming back from the http request to the tauri-driver port. I can recreate it by making the same request directly using postman, but perhaps the request itself is incorrect.

AlexTMjugador commented 1 year ago

I can reproduce this issue too.

After some investigation, I came up with the conclusions that, in WebDriver spec parlance, tauri-driver is just an intermediary node (i.e., proxy) that launches the corresponding OS webview driver binary listening on a non-default port, and then forwards messages as-is to such driver, only mangling capabilities to be driver-neutral. On Linux, it launches the WebKit GTK driver (WebKitWebDriver), while on Windows it launches the MS Edge driver (msedgedriver.exe).

The issue at hand is not caused due to tauri-driver's interference: I've confirmed using Wireshark that the affected requests are responses are passed verbatim to the underlying driver. In other words, the issue would happen even if Webdriver IO used the underlying driver directly.

My best guess about the root cause of the issue is that some Wry security feature or incompatibility is preventing the WebKit driver from doing its work. Given that E2E testing is a pretty advanced topic that doesn't tend to get much developer attention, it's likely that the driver stopped working at some point but almost nobody noticed. I'll update this comment if I get to dig further into this.

chippers commented 1 year ago

Adding e2e tests is something we as a team have discussed before, but have not implemented. I think it would be really valuable, but we are also cautious of requiring non-rust things to build the repo. This is why many examples are ignored. I think having a separate process for e2e would be perfectly fine, but requires maintenance.

Thank you @AlexTMjugador for the writeup, it's quite accurate. If you are interested in joining the working group, reach out on discord and I can help with that

amosjyng commented 1 year ago

I've just encountered this myself as well. Thank you for the workaround @Sheap , you just saved me a lot of time with the bubbles: true trick :P