Problem
In browser mode (devServerUrl set), the IPC interceptor is injected after browser.url() resolves — i.e. after readyState === 'complete'. Any invoke() calls the app makes during module initialisation, DOMContentLoaded, or onload handlers run against the real (unpatched) __TAURI_INTERNALS__ and are invisible to mocks.
// service.ts – current flow
await browser.url(this.devServerUrl); // waits for readyState=complete
await browser.execute(injectionScript); // too late for startup invoke() calls
Affected scope
| Mode |
Affected? |
Tauri browser mode (devServerUrl) |
✅ Yes – confirmed |
| Tauri native mode (real binary) |
⚠️ Potentially – mock registration happens after before() hook; any invoke() during app launch before the WebDriver session is fully established may also be missed |
| Electron |
❌ No – Electron's IPC is intercepted at the Node.js layer via ipcMain, not injected into the renderer |
Proposed solutions
1. Vite plugin (browser mode only)
Ship an optional @wdio/tauri-vite-plugin that imports the injection script as a top-level module in the dev build entry point. This guarantees the mock infrastructure is available before any app code runs.
// vite.config.ts
import { wdioTauriPlugin } from '@wdio/tauri-vite-plugin';
export default { plugins: [wdioTauriPlugin()] };
2. WebDriver BiDi script.addPreloadScript (browser mode)
WebDriver BiDi (supported in ChromeDriver 115+, Firefox 128+) provides script.addPreloadScript which runs before any page script. This would work without a Vite plugin and would not require @wdio/devtools-service.
await browser.scriptAddPreloadScript({ functionDeclaration: injectionScript });
3. Investigate Tauri native mode
Audit whether the native-mode mock lifecycle (registered in the before() hook) can miss startup invoke() calls when the app is already running before the WebDriver session attaches.
Current workaround
Structure tests so that all mocks are created before the first navigation:
before(async () => {
await browser.url('/'); // navigate first
const greetMock = await tauri.mock('greet'); // then mock
// startup invoke() calls already happened — this mock only captures future calls
});
Or defer navigation until after mock setup:
before(async () => {
const greetMock = await tauri.mock('greet'); // mock first
await browser.url('/'); // then navigate
// still too late — inject is post-load
});
Neither workaround is reliable for true startup calls. The Vite plugin approach is the recommended interim solution.
Related
Problem
In browser mode (
devServerUrlset), the IPC interceptor is injected afterbrowser.url()resolves — i.e. afterreadyState === 'complete'. Anyinvoke()calls the app makes during module initialisation,DOMContentLoaded, oronloadhandlers run against the real (unpatched)__TAURI_INTERNALS__and are invisible to mocks.Affected scope
devServerUrl)before()hook; anyinvoke()during app launch before the WebDriver session is fully established may also be missedipcMain, not injected into the rendererProposed solutions
1. Vite plugin (browser mode only)
Ship an optional
@wdio/tauri-vite-pluginthat imports the injection script as a top-level module in the dev build entry point. This guarantees the mock infrastructure is available before any app code runs.2. WebDriver BiDi
script.addPreloadScript(browser mode)WebDriver BiDi (supported in ChromeDriver 115+, Firefox 128+) provides
script.addPreloadScriptwhich runs before any page script. This would work without a Vite plugin and would not require@wdio/devtools-service.3. Investigate Tauri native mode
Audit whether the native-mode mock lifecycle (registered in the
before()hook) can miss startupinvoke()calls when the app is already running before the WebDriver session attaches.Current workaround
Structure tests so that all mocks are created before the first navigation:
Or defer navigation until after mock setup:
Neither workaround is reliable for true startup calls. The Vite plugin approach is the recommended interim solution.
Related