Skip to content

Commit c1b1aa6

Browse files
authored
docs(electron): document mocking the native main-process dialog API (#40952)
1 parent 0f9632b commit c1b1aa6

3 files changed

Lines changed: 86 additions & 0 deletions

File tree

docs/src/electron-api/class-electron.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,34 @@ If you are not able to launch Electron and it will end up in timeouts during lau
5151

5252
* Ensure that `nodeCliInspect` ([FuseV1Options.EnableNodeCliInspectArguments](https://www.electronjs.org/docs/latest/tutorial/fuses#nodecliinspect)) fuse is **not** set to `false`.
5353

54+
**Mocking native dialogs:**
55+
56+
Playwright does not intercept the native Electron [dialog](https://www.electronjs.org/docs/latest/api/dialog) API
57+
(`dialog.showOpenDialog`, `dialog.showSaveDialog`, `dialog.showMessageBox`, etc.) because those calls happen in the
58+
Electron main process and go straight to OS APIs. Use [`method: ElectronApplication.evaluate`] to replace the
59+
relevant methods in the main process so tests run deterministically without any OS-level UI:
60+
61+
```js
62+
// Stub the open dialog to always return a fixed path.
63+
await electronApp.evaluate(({ dialog }, filePaths) => {
64+
dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths });
65+
}, ['/path/to/file.txt']);
66+
67+
// Stub the save dialog.
68+
await electronApp.evaluate(({ dialog }, filePath) => {
69+
dialog.showSaveDialog = () => Promise.resolve({ canceled: false, filePath });
70+
}, '/path/to/saved.txt');
71+
72+
// Stub showMessageBox to click the first button.
73+
await electronApp.evaluate(({ dialog }) => {
74+
dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
75+
});
76+
```
77+
78+
The replacement persists until the application is closed. Synchronous variants
79+
(`showOpenDialogSync`, `showSaveDialogSync`, `showMessageBoxSync`) can be stubbed the same way — just return the
80+
value directly instead of a `Promise`.
81+
5482
## async method: Electron.launch
5583
* since: v1.9
5684
- returns: <[ElectronApplication]>

packages/playwright-client/types/types.d.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22241,6 +22241,35 @@ export interface WebStorage {
2224122241
* - Ensure that `nodeCliInspect`
2224222242
* ([FuseV1Options.EnableNodeCliInspectArguments](https://www.electronjs.org/docs/latest/tutorial/fuses#nodecliinspect))
2224322243
* fuse is **not** set to `false`.
22244+
*
22245+
* **Mocking native dialogs:**
22246+
*
22247+
* Playwright does not intercept the native Electron [dialog](https://www.electronjs.org/docs/latest/api/dialog) API
22248+
* (`dialog.showOpenDialog`, `dialog.showSaveDialog`, `dialog.showMessageBox`, etc.) because those calls happen in the
22249+
* Electron main process and go straight to OS APIs. Use
22250+
* [electronApplication.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-electronapplication#electron-application-evaluate)
22251+
* to replace the relevant methods in the main process so tests run deterministically without any OS-level UI:
22252+
*
22253+
* ```js
22254+
* // Stub the open dialog to always return a fixed path.
22255+
* await electronApp.evaluate(({ dialog }, filePaths) => {
22256+
* dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths });
22257+
* }, ['/path/to/file.txt']);
22258+
*
22259+
* // Stub the save dialog.
22260+
* await electronApp.evaluate(({ dialog }, filePath) => {
22261+
* dialog.showSaveDialog = () => Promise.resolve({ canceled: false, filePath });
22262+
* }, '/path/to/saved.txt');
22263+
*
22264+
* // Stub showMessageBox to click the first button.
22265+
* await electronApp.evaluate(({ dialog }) => {
22266+
* dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
22267+
* });
22268+
* ```
22269+
*
22270+
* The replacement persists until the application is closed. Synchronous variants (`showOpenDialogSync`,
22271+
* `showSaveDialogSync`, `showMessageBoxSync`) can be stubbed the same way — just return the value directly instead of
22272+
* a `Promise`.
2224422273
*/
2224522274
export interface Electron {
2224622275
/**

packages/playwright-core/types/types.d.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22241,6 +22241,35 @@ export interface WebStorage {
2224122241
* - Ensure that `nodeCliInspect`
2224222242
* ([FuseV1Options.EnableNodeCliInspectArguments](https://www.electronjs.org/docs/latest/tutorial/fuses#nodecliinspect))
2224322243
* fuse is **not** set to `false`.
22244+
*
22245+
* **Mocking native dialogs:**
22246+
*
22247+
* Playwright does not intercept the native Electron [dialog](https://www.electronjs.org/docs/latest/api/dialog) API
22248+
* (`dialog.showOpenDialog`, `dialog.showSaveDialog`, `dialog.showMessageBox`, etc.) because those calls happen in the
22249+
* Electron main process and go straight to OS APIs. Use
22250+
* [electronApplication.evaluate(pageFunction[, arg])](https://playwright.dev/docs/api/class-electronapplication#electron-application-evaluate)
22251+
* to replace the relevant methods in the main process so tests run deterministically without any OS-level UI:
22252+
*
22253+
* ```js
22254+
* // Stub the open dialog to always return a fixed path.
22255+
* await electronApp.evaluate(({ dialog }, filePaths) => {
22256+
* dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths });
22257+
* }, ['/path/to/file.txt']);
22258+
*
22259+
* // Stub the save dialog.
22260+
* await electronApp.evaluate(({ dialog }, filePath) => {
22261+
* dialog.showSaveDialog = () => Promise.resolve({ canceled: false, filePath });
22262+
* }, '/path/to/saved.txt');
22263+
*
22264+
* // Stub showMessageBox to click the first button.
22265+
* await electronApp.evaluate(({ dialog }) => {
22266+
* dialog.showMessageBox = () => Promise.resolve({ response: 0, checkboxChecked: false });
22267+
* });
22268+
* ```
22269+
*
22270+
* The replacement persists until the application is closed. Synchronous variants (`showOpenDialogSync`,
22271+
* `showSaveDialogSync`, `showMessageBoxSync`) can be stubbed the same way — just return the value directly instead of
22272+
* a `Promise`.
2224422273
*/
2224522274
export interface Electron {
2224622275
/**

0 commit comments

Comments
 (0)