{"id":20035816,"url":"https://github.com/spaceagetv/electron-playwright-helpers","last_synced_at":"2025-12-29T01:17:19.388Z","repository":{"id":37777020,"uuid":"462080780","full_name":"spaceagetv/electron-playwright-helpers","owner":"spaceagetv","description":"Helper functions for running Electron end-to-end tests using Playwright.","archived":false,"fork":false,"pushed_at":"2025-02-14T20:16:18.000Z","size":1998,"stargazers_count":61,"open_issues_count":10,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-28T14:09:27.713Z","etag":null,"topics":["electron","end-to-end","end-to-end-testing","playwright","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spaceagetv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-22T00:38:19.000Z","updated_at":"2025-03-20T16:11:58.000Z","dependencies_parsed_at":"2023-02-14T11:31:18.051Z","dependency_job_id":"f803e69c-4f6c-4017-b7dd-c43c16a72459","html_url":"https://github.com/spaceagetv/electron-playwright-helpers","commit_stats":{"total_commits":66,"total_committers":5,"mean_commits":13.2,"dds":"0.18181818181818177","last_synced_commit":"eaf4c2a3d1c1ce7cd8ec9f57062c2ab37050c8ac"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaceagetv%2Felectron-playwright-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaceagetv%2Felectron-playwright-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaceagetv%2Felectron-playwright-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spaceagetv%2Felectron-playwright-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spaceagetv","download_url":"https://codeload.github.com/spaceagetv/electron-playwright-helpers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247014519,"owners_count":20869376,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["electron","end-to-end","end-to-end-testing","playwright","typescript"],"created_at":"2024-11-13T10:09:22.226Z","updated_at":"2025-12-29T01:17:19.381Z","avatar_url":"https://github.com/spaceagetv.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Electron Playwright Helpers\n\n[![npm version](https://img.shields.io/npm/v/electron-playwright-helpers.svg)](https://www.npmjs.com/package/electron-playwright-helpers)\n[![npm downloads](https://img.shields.io/npm/dm/electron-playwright-helpers.svg)](https://www.npmjs.com/package/electron-playwright-helpers)\n\nHelper functions to make it easier to use [Playwright](https://playwright.dev/) for end-to-end testing with\n[Electron](https://www.electronjs.org/). Parse packaged Electron projects so you can run tests on them. Click Electron menu items, send IPC messages, get menu structures, stub `dialog.showOpenDialog()` results, etc.\n\n## Installation\n\n```shell\nnpm i -D electron-playwright-helpers\n```\n\n## Usage\n\nFor a full example of how to use this library, see the \n[electron-playwright-example](https://github.com/spaceagetv/electron-playwright-example) project.\nBut here's a quick example:\n\nJavascript:\n\n```JS\nconst eph = require('electron-playwright-helpers')\n// - or cherry pick -\nconst { findLatestBuild, parseElectronApp, clickMenuItemById } = require('electron-playwright-helpers')\n\nlet electronApp: ElectronApplication\n\ntest.beforeAll(async () =\u003e {\n  // find the latest build in the out directory\n  const latestBuild = findLatestBuild()\n  // parse the packaged Electron app and find paths and other info\n  const appInfo = parseElectronApp(latestBuild)\n  electronApp = await electron.launch({\n    args: [appInfo.main], // main file from package.json\n    executablePath: appInfo.executable // path to the Electron executable\n  })\n})\n\ntest.afterAll(async () =\u003e {\n  await electronApp.close()\n})\n\ntest('open a file', async () =\u003e {\n  // stub electron dialog so dialog.showOpenDialog() \n  // will return a file path without opening a dialog\n  await eph.stubDialog(electronApp, 'showOpenDialog', { filePaths: ['/path/to/file'] })\n\n  // call the click method of menu item in the Electron app's application menu\n  await eph.clickMenuItemById(electronApp, 'open-file')\n\n  // get the result of an ipcMain.handle() function\n  const result = await eph.ipcMainInvokeHandler(electronApp, 'get-open-file-path')\n  \n  // result should be the file path\n  expect(result).toBe('/path/to/file')\n})\n```\n\nTypescript:\n\n```TS\nimport * as eph from 'electron-playwright-helpers'\n// - or cherry pick -\nimport { electronWaitForFunction, ipcMainCallFirstListener, clickMenuItemById } from 'electron-playwright-helpers'\n\n// then same as Javascript above\n```\n\n## Contributing\n\nYes, please! Pull requests are always welcome. Feel free to add or suggest new features, fix bugs, etc.\n\nPlease use [Conventional Commit](https://www.conventionalcommits.org/) messages for your commits. This project uses [semantic-release](https://github.com/semantic-release/semantic-release) to automatically publish new versions to NPM. The commit messages are used to determine the version number and changelog. We're also using Prettier as our code format and ESlint to enforce formatting, so please make sure your code is formatted before submitting a PR.\n\n## Migrating from v1.x to v2.0\n\nVersion 2.0 introduces significant improvements to handle flakiness issues that appeared with Electron 27+ and Playwright. Starting with Electron 27, Playwright's `evaluate()` calls became unreliable, often throwing errors like \"context or browser has been closed\", \"Promise was collected\", or \"Execution context was destroyed\" seemingly at random.\n\n### What's New in v2.0\n\n#### Built-in Retry Logic\n\nAll helper functions now automatically retry operations that fail due to Playwright context issues. This happens transparently - your existing code will work without changes, but will be more reliable.\n\n#### New Utility Functions\n\n- **`retry(fn, options)`** - Wrap any Playwright call to automatically retry on context errors\n- **`retryUntilTruthy(fn, options)`** - Like Playwright's `page.waitForFunction()` but with automatic retry on errors\n- **`setRetryOptions(options)`** - Configure default retry behavior globally\n- **`getRetryOptions()`** - Get current retry configuration\n- **`resetRetryOptions()`** - Reset retry options to defaults\n\n#### Conditional Dialog Stubbing (New!)\n\n- **`stubDialogMatchers(app, stubs, options)`** - Stub dialogs with conditional matching based on dialog options\n- **`clearDialogMatchers(app)`** - Clear dialog matcher stubs\n\n### Breaking Changes\n\n#### 1. Node.js 18+ Required\n\nVersion 2.0 requires Node.js 18 or later due to modern JavaScript features like `structuredClone()`.\n\n#### 2. IPC Helper Function Signatures\n\nIPC helpers now accept an optional `RetryOptions` object as the last argument:\n\n```typescript\n// v1.x\nawait ipcRendererSend(page, 'my-channel', arg1, arg2)\n\n// v2.0 - still works exactly the same\nawait ipcRendererSend(page, 'my-channel', arg1, arg2)\n\n// v2.0 - with retry options\nawait ipcRendererSend(page, 'my-channel', arg1, arg2, { timeout: 10000 })\n```\n\nThis applies to: `ipcRendererSend`, `ipcRendererInvoke`, `ipcRendererEmit`, `ipcRendererCallFirstListener`, `ipcMainEmit`, `ipcMainCallFirstListener`, `ipcMainInvokeHandler`\n\n#### 3. Menu Helper Function Signatures\n\nMenu helpers now accept an optional `RetryOptions` object:\n\n```typescript\n// v1.x\nawait clickMenuItemById(electronApp, 'my-menu-item')\n\n// v2.0 - still works exactly the same\nawait clickMenuItemById(electronApp, 'my-menu-item')\n\n// v2.0 - with retry options\nawait clickMenuItemById(electronApp, 'my-menu-item', { timeout: 10000 })\n```\n\n### Migration Steps\n\nFor most projects, upgrading is straightforward:\n\n1. **Update Node.js** to version 18 or later\n2. **Update the package**: `npm install electron-playwright-helpers@latest`\n3. **Test your suite** - existing code should work without changes\n\n### Customizing Retry Behavior\n\nIf you need to adjust retry behavior globally:\n\n```typescript\nimport { setRetryOptions, resetRetryOptions } from 'electron-playwright-helpers'\n\n// Increase timeout for slow CI environments\nsetRetryOptions({\n  timeout: 10000,  // 10 seconds (default: 5000)\n  poll: 500,       // poll every 500ms (default: 200)\n})\n\n// Reset to defaults\nresetRetryOptions()\n```\n\nOr disable retries for specific calls:\n\n```typescript\nawait ipcRendererSend(page, 'channel', arg, { disable: true })\n```\n\n### Using the New Retry Functions\n\nIf you have custom Playwright `evaluate()` calls that aren't using our helpers, wrap them with `retry()`:\n\n```typescript\nimport { retry, retryUntilTruthy } from 'electron-playwright-helpers'\n\n// Wrap evaluate calls to handle context errors\nconst result = await retry(() =\u003e\n  electronApp.evaluate(({ app }) =\u003e app.getName())\n)\n\n// Wait for a condition with automatic error recovery\nawait retryUntilTruthy(() =\u003e\n  page.evaluate(() =\u003e document.body.classList.contains('ready'))\n)\n```\n\n## Additional Resources\n\n* [Electron Playwright Example](https://github.com/spaceagetv/electron-playwright-example) - an example of how to use this library\n* [Playwright Electron Class](https://playwright.dev/docs/api/class-electron) - Playwright API docs for Electron\n* [Electron API](https://electronjs.org/docs/api/app) - Electron API documentation\n\n## API\n\n## Constants\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ca href=\"#dialogMatcherDefaults\"\u003edialogMatcherDefaults\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eUnion type of all dialog matcher stubs.\u003c/p\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\n## Functions\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ca href=\"#toSerializableMatcher\"\u003etoSerializableMatcher()\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eConvert a string or RegExp to a serializable StringMatcher.\nRegExp objects cannot be transferred via Playwright's evaluate(),\nso we serialize them as {source, flags}.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#matchesPattern\"\u003ematchesPattern()\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eCheck if a value matches a StringMatcher.\nUsed inside app.evaluate() where the matcher is already serialized.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#findLatestBuild\"\u003efindLatestBuild(buildDirectory)\u003c/a\u003e ⇒ \u003ccode\u003estring\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eParses the \u003ccode\u003eout\u003c/code\u003e directory to find the latest build of your Electron project.\nUse \u003ccode\u003enpm run package\u003c/code\u003e (or similar) to build your app prior to testing.\u003c/p\u003e\n\u003cp\u003eAssumptions: We assume that your build will be in the \u003ccode\u003eout\u003c/code\u003e directory, and that\nthe build directory will be named with a hyphen-delimited platform name, e.g.\n\u003ccode\u003eout/my-app-win-x64\u003c/code\u003e. If your build directory is not \u003ccode\u003eout\u003c/code\u003e, you can\npass the name of the directory as the \u003ccode\u003ebuildDirectory\u003c/code\u003e parameter. If your\nbuild directory is not named with a hyphen-delimited platform name, this\nfunction will not work. However, you can pass the build path into\n\u003ccode\u003eparseElectronApp()\u003c/code\u003e directly.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#parseElectronApp\"\u003eparseElectronApp(buildDir)\u003c/a\u003e ⇒ \u003ccode\u003e\u003ca href=\"#ElectronAppInfo\"\u003eElectronAppInfo\u003c/a\u003e\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGiven a directory containing an Electron app build,\nor the path to the app itself (directory on Mac, executable on Windows),\nreturn a bunch of metadata, including the path to the app's executable\nand the path to the app's main file.\u003c/p\u003e\n\u003cp\u003eFormat of the data returned is an object with the following properties:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eexecutable: path to the app's executable file\u003c/li\u003e\n\u003cli\u003emain: path to the app's main (JS) file\u003c/li\u003e\n\u003cli\u003ename: name of the app\u003c/li\u003e\n\u003cli\u003eresourcesDir: path to the app's resources directory\u003c/li\u003e\n\u003cli\u003easar: true if the app is using asar\u003c/li\u003e\n\u003cli\u003eplatform: OS platform\u003c/li\u003e\n\u003cli\u003earch: architecture\u003c/li\u003e\n\u003cli\u003epackageJson: the JSON.parse()'d contents of the package.json file.\u003c/li\u003e\n\u003c/ul\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#electronWaitForFunction\"\u003eelectronWaitForFunction(electronApp, fn, arg)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eWait for a function to evaluate to true in the main Electron process. This really\nshould be part of the Playwright API, but it's not.\u003c/p\u003e\n\u003cp\u003eThis function is to \u003ccode\u003eelectronApp.evaluate()\u003c/code\u003e\nas \u003ccode\u003epage.waitForFunction()\u003c/code\u003e is \u003ccode\u003epage.evaluate()\u003c/code\u003e.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#evaluateWithRetry\"\u003eevaluateWithRetry(electronApp, fn, arg, retries, retryIntervalMs)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;R\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eElectron's \u003ccode\u003eevaluate\u003c/code\u003e function can be flakey,\nthrowing an error saying the execution context has been destroyed.\nThis function retries the evaluation several times to see if it can\nrun the evaluation without an error. If it fails after the retries,\nit throws the error.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#isSerializedNativeImageSuccess\"\u003eisSerializedNativeImageSuccess()\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eType guard to check if a SerializedNativeImage is a success case\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#isSerializedNativeImageError\"\u003eisSerializedNativeImageError()\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eType guard to check if a SerializedNativeImage is an error case\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#retryUntilTruthy\"\u003eretryUntilTruthy(fn, [timeoutMs], [intervalMs])\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eRetries a given function until it returns a truthy value or the timeout is reached.\u003c/p\u003e\n\u003cp\u003eThis offers similar functionality to Playwright's \u003ca href=\"https://playwright.dev/docs/api/class-page#page-wait-for-function\"\u003e\u003ccode\u003epage.waitForFunction()\u003c/code\u003e\u003c/a\u003e\nmethod – but with more flexibility and control over the retry attempts. It also defaults to ignoring common errors due to\nthe way that Playwright handles browser contexts.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#matchesPattern\"\u003ematchesPattern()\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eHelper to match a string against a pattern (string or RegExp).\nFor strings, performs a substring match (includes).\nFor RegExp, tests the pattern against the value.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#stubDialog\"\u003estubDialog(app, method, value)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eStub a single dialog method. This is a convenience function that calls \u003ccode\u003estubMultipleDialogs\u003c/code\u003e\nfor a single method.\u003c/p\u003e\n\u003cp\u003ePlaywright does not have a way to interact with Electron dialog windows,\nso this function allows you to substitute the dialog module's methods during your tests.\nBy stubbing the dialog module, your Electron application will not display any dialog windows,\nand you can control the return value of the dialog methods. You're basically saying\n\u0026quot;when my application calls dialog.showOpenDialog, return this value instead\u0026quot;. This allows you\nto test your application's behavior when the user selects a file, or cancels the dialog, etc.\u003c/p\u003e\n\u003cp\u003eNote: Each dialog method can only be stubbed with one value at a time, so you will want to call\n\u003ccode\u003estubDialog\u003c/code\u003e before each time that you expect your application to call the dialog method.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#stubMultipleDialogs\"\u003estubMultipleDialogs(app, mocks)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eStub methods of the Electron dialog module.\u003c/p\u003e\n\u003cp\u003ePlaywright does not have a way to interact with Electron dialog windows,\nso this function allows you to mock the dialog module's methods during your tests.\nBy mocking the dialog module, your Electron application will not display any dialog windows,\nand you can control the return value of the dialog methods. You're basically saying\n\u0026quot;when my application calls dialog.showOpenDialog, return this value instead\u0026quot;. This allows you\nto test your application's behavior when the user selects a file, or cancels the dialog, etc.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#stubAllDialogs\"\u003estubAllDialogs(app)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eStub all dialog methods. This is a convenience function that calls \u003ccode\u003estubMultipleDialogs\u003c/code\u003e\nfor all dialog methods. This is useful if you want to ensure that dialogs are not displayed\nduring your tests. However, you may want to use \u003ccode\u003estubDialog\u003c/code\u003e or \u003ccode\u003estubMultipleDialogs\u003c/code\u003e to\ncontrol the return value of specific dialog methods (e.g. \u003ccode\u003eshowOpenDialog\u003c/code\u003e) during your tests.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#stubDialogMatchers\"\u003estubDialogMatchers(app, stubs, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eStub dialog methods with matchers that check dialog options before returning values.\nThis allows you to set up multiple different return values based on the dialog's\ntitle, message, buttons, or other options.\u003c/p\u003e\n\u003cp\u003eMatchers are checked in order - the first matching stub wins.\nIf no stub matches, either an error is thrown (if throwOnUnmatched is true)\nor the default value is returned.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#clearDialogMatchers\"\u003eclearDialogMatchers(app)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eClear all dialog matcher stubs and restore original dialog methods.\nNote: This requires the app to have stored the original methods,\nwhich is not done by default. You may need to restart the app\nto fully restore dialog functionality.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcMainEmit\"\u003eipcMainEmit(electronApp, message, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;boolean\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eEmit an ipcMain message from the main process.\nThis will trigger all ipcMain listeners for the message.\u003c/p\u003e\n\u003cp\u003eThis does not transfer data between main and renderer processes.\nIt simply emits an event in the main process.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcMainCallFirstListener\"\u003eipcMainCallFirstListener(electronApp, message, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eCall the first listener for a given ipcMain message in the main process\nand return its result.\u003c/p\u003e\n\u003cp\u003eNOTE: ipcMain listeners usually don't return a value, but we're using\nthis to retrieve test data from the main process.\u003c/p\u003e\n\u003cp\u003eGenerally, it's probably better to use \u003ccode\u003eipcMainInvokeHandler()\u003c/code\u003e instead.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcMainInvokeHandler\"\u003eipcMainInvokeHandler(electronApp, message, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet the return value of an \u003ccode\u003eipcMain.handle()\u003c/code\u003e function\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcRendererSend\"\u003eipcRendererSend(page, channel, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eSend an \u003ccode\u003eipcRenderer.send()\u003c/code\u003e (to main process) from a given window.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true and contextIsolation must be false\nin the webPreferences for this BrowserWindow.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcRendererInvoke\"\u003eipcRendererInvoke(page, message, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eSend an ipcRenderer.invoke() from a given window.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true and contextIsolation must be false\nin the webPreferences for this window\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcRendererCallFirstListener\"\u003eipcRendererCallFirstListener(page, message, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eCall just the first listener for a given ipcRenderer channel in a given window.\n\u003cem\u003eUNLIKE MOST Electron ipcRenderer listeners\u003c/em\u003e, this function SHOULD return a value.\u003c/p\u003e\n\u003cp\u003eThis function does not send data between main and renderer processes.\nIt simply retrieves data from the renderer process.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true for this BrowserWindow.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#ipcRendererEmit\"\u003eipcRendererEmit(page, message, ...args, retryOptions)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;boolean\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eEmit an IPC message to a given window.\nThis will trigger all ipcRenderer listeners for the message.\u003c/p\u003e\n\u003cp\u003eThis does not transfer data between main and renderer processes.\nIt simply emits an event in the renderer process.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true for this window\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#clickMenuItemById\"\u003eclickMenuItemById(electronApp, id)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eExecute the \u003ccode\u003e.click()\u003c/code\u003e method on the element with the given id.\n\u003cstrong\u003eNOTE:\u003c/strong\u003e All menu testing functions will only work with items in the\n\u003ca href=\"https://www.electronjs.org/docs/latest/api/menu#menusetapplicationmenumenu\"\u003eapplication menu\u003c/a\u003e.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#clickMenuItem\"\u003eclickMenuItem(electronApp, property, value)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eClick the first matching menu item by any of its properties. This is\nuseful for menu items that don't have an id. HOWEVER, this is not as fast\nor reliable as using \u003ccode\u003eclickMenuItemById()\u003c/code\u003e if the menu item has an id.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNOTE:\u003c/strong\u003e All menu testing functions will only work with items in the\n\u003ca href=\"https://www.electronjs.org/docs/latest/api/menu#menusetapplicationmenumenu\"\u003eapplication menu\u003c/a\u003e.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getMenuItemAttribute\"\u003egetMenuItemAttribute(electronApp, menuId, attribute)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;string\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet a given attribute the MenuItem with the given id.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getMenuItemById\"\u003egetMenuItemById(electronApp, menuId)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;MenuItemPartial\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet information about the MenuItem with the given id. Returns serializable values including\nprimitives, objects, arrays, and other non-recursive data structures.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getApplicationMenu\"\u003egetApplicationMenu(electronApp)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;Array.\u0026lt;MenuItemPartial\u0026gt;\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet the current state of the application menu. Contains serializable values including\nprimitives, objects, arrays, and other non-recursive data structures.\nVery similar to menu\n\u003ca href=\"https://www.electronjs.org/docs/latest/api/menu#examples\"\u003econstruction template structure\u003c/a\u003e\nin Electron.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#findMenuItem\"\u003efindMenuItem(electronApp, property, value, menuItems)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;MenuItemPartial\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eFind a MenuItem by any of its properties\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#waitForMenuItem\"\u003ewaitForMenuItem(electronApp, id)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eWait for a MenuItem to exist\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#waitForMenuItemStatus\"\u003ewaitForMenuItemStatus(electronApp, id, property, value)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eWait for a MenuItem to have a specific attribute value.\nFor example, wait for a MenuItem to be enabled... or be visible.. etc\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#addTimeoutToPromise\"\u003eaddTimeoutToPromise(promise, timeoutMs, timeoutMessage)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eAdd a timeout to any Promise\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#addTimeout\"\u003eaddTimeout(functionName, timeoutMs, timeoutMessage, ...args)\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eAdd a timeout to any helper function from this library which returns a Promise.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#retry\"\u003eretry(fn, [options])\u003c/a\u003e ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eRetries a function until it returns without throwing an error.\u003c/p\u003e\n\u003cp\u003eStarting with Electron 27, Playwright can get very flakey when running code in Electron's main or renderer processes.\nIt will often throw errors like \u0026quot;context or browser has been closed\u0026quot; or \u0026quot;Promise was collected\u0026quot; for no apparent reason.\nThis function retries a given function until it returns without throwing one of these errors, or until the timeout is reached.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#setRetryOptions\"\u003esetRetryOptions(options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eSets the default retry() options. These options will be used for all subsequent calls to retry() unless overridden.\nYou can reset the defaults at any time by calling resetRetryOptions().\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getRetryOptions\"\u003egetRetryOptions()\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGets the current default retry options.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#resetRetryOptions\"\u003eresetRetryOptions()\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eResets the retry options to their default values.\u003c/p\u003e\n\u003cp\u003eThe default values are:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eretries: 20\u003c/li\u003e\n\u003cli\u003eintervalMs: 200\u003c/li\u003e\n\u003cli\u003etimeoutMs: 5000\u003c/li\u003e\n\u003cli\u003eerrorMatch: 'context or browser has been closed'\u003c/li\u003e\n\u003c/ul\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#errToString\"\u003eerrToString(err)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eConverts an unknown error to a string representation.\u003c/p\u003e\n\u003cp\u003eThis function handles different types of errors and attempts to convert them\nto a string in a meaningful way. It checks if the error is an object with a\n\u003ccode\u003etoString\u003c/code\u003e method and uses that method if available. If the error is a string,\nit returns the string directly. For other types, it converts the error to a\nJSON string.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getWindowByUrl\"\u003egetWindowByUrl(electronApp, pattern, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet all windows whose URL matches the given pattern.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getWindowByTitle\"\u003egetWindowByTitle(electronApp, pattern, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet all windows whose title matches the given pattern.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#getWindowByMatcher\"\u003egetWindowByMatcher(electronApp, matcher, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eGet all windows that match the provided matcher function.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#waitForWindowByUrl\"\u003ewaitForWindowByUrl(electronApp, pattern, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eWait for a window whose URL matches the given pattern.\u003c/p\u003e\n\u003cp\u003eThis function checks existing windows first, then listens for new windows.\nIt uses polling to handle windows that may have their URL change after opening.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#waitForWindowByTitle\"\u003ewaitForWindowByTitle(electronApp, pattern, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eWait for a window whose title matches the given pattern.\u003c/p\u003e\n\u003cp\u003eThis function checks existing windows first, then listens for new windows.\nIt uses polling to handle windows that may have their title change after opening.\u003c/p\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ca href=\"#waitForWindowByMatcher\"\u003ewaitForWindowByMatcher(electronApp, matcher, options)\u003c/a\u003e ⇒\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eWait for a window that matches the provided matcher function.\u003c/p\u003e\n\u003cp\u003eThis function:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eChecks existing windows first\u003c/li\u003e\n\u003cli\u003eListens for new window events\u003c/li\u003e\n\u003cli\u003ePolls existing windows periodically (to catch URL/title changes)\u003c/li\u003e\n\u003c/ol\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\n## Typedefs\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ca href=\"#ElectronAppInfo\"\u003eElectronAppInfo\u003c/a\u003e\u003c/dt\u003e\n\u003cdd\u003e\u003cp\u003eFormat of the data returned from \u003ccode\u003eparseElectronApp()\u003c/code\u003e\u003c/p\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ca name=\"dialogMatcherDefaults\"\u003e\u003c/a\u003e\n\n## dialogMatcherDefaults\n\u003cp\u003eUnion type of all dialog matcher stubs.\u003c/p\u003e\n\n**Kind**: global constant  \n\u003ca name=\"toSerializableMatcher\"\u003e\u003c/a\u003e\n\n## toSerializableMatcher()\n\u003cp\u003eConvert a string or RegExp to a serializable StringMatcher.\nRegExp objects cannot be transferred via Playwright's evaluate(),\nso we serialize them as {source, flags}.\u003c/p\u003e\n\n**Kind**: global function  \n\u003ca name=\"matchesPattern\"\u003e\u003c/a\u003e\n\n## matchesPattern()\n\u003cp\u003eCheck if a value matches a StringMatcher.\nUsed inside app.evaluate() where the matcher is already serialized.\u003c/p\u003e\n\n**Kind**: global function  \n\u003ca name=\"findLatestBuild\"\u003e\u003c/a\u003e\n\n## findLatestBuild(buildDirectory) ⇒ \u003ccode\u003estring\u003c/code\u003e\n\u003cp\u003eParses the \u003ccode\u003eout\u003c/code\u003e directory to find the latest build of your Electron project.\nUse \u003ccode\u003enpm run package\u003c/code\u003e (or similar) to build your app prior to testing.\u003c/p\u003e\n\u003cp\u003eAssumptions: We assume that your build will be in the \u003ccode\u003eout\u003c/code\u003e directory, and that\nthe build directory will be named with a hyphen-delimited platform name, e.g.\n\u003ccode\u003eout/my-app-win-x64\u003c/code\u003e. If your build directory is not \u003ccode\u003eout\u003c/code\u003e, you can\npass the name of the directory as the \u003ccode\u003ebuildDirectory\u003c/code\u003e parameter. If your\nbuild directory is not named with a hyphen-delimited platform name, this\nfunction will not work. However, you can pass the build path into\n\u003ccode\u003eparseElectronApp()\u003c/code\u003e directly.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003estring\u003c/code\u003e - \u003cul\u003e\n\u003cli\u003epath to the most recently modified build directory\u003c/li\u003e\n\u003c/ul\u003e  \n**See**: parseElectronApp  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| buildDirectory | \u003ccode\u003estring\u003c/code\u003e | \u003ccode\u003e\u0026quot;out\u0026quot;\u003c/code\u003e | \u003cp\u003eoptional - the directory to search for the latest build (path/name relative to package root or full path starting with /). Defaults to \u003ccode\u003eout\u003c/code\u003e.\u003c/p\u003e |\n\n\u003ca name=\"parseElectronApp\"\u003e\u003c/a\u003e\n\n## parseElectronApp(buildDir) ⇒ [\u003ccode\u003eElectronAppInfo\u003c/code\u003e](#ElectronAppInfo)\n\u003cp\u003eGiven a directory containing an Electron app build,\nor the path to the app itself (directory on Mac, executable on Windows),\nreturn a bunch of metadata, including the path to the app's executable\nand the path to the app's main file.\u003c/p\u003e\n\u003cp\u003eFormat of the data returned is an object with the following properties:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eexecutable: path to the app's executable file\u003c/li\u003e\n\u003cli\u003emain: path to the app's main (JS) file\u003c/li\u003e\n\u003cli\u003ename: name of the app\u003c/li\u003e\n\u003cli\u003eresourcesDir: path to the app's resources directory\u003c/li\u003e\n\u003cli\u003easar: true if the app is using asar\u003c/li\u003e\n\u003cli\u003eplatform: OS platform\u003c/li\u003e\n\u003cli\u003earch: architecture\u003c/li\u003e\n\u003cli\u003epackageJson: the JSON.parse()'d contents of the package.json file.\u003c/li\u003e\n\u003c/ul\u003e\n\n**Kind**: global function  \n**Returns**: [\u003ccode\u003eElectronAppInfo\u003c/code\u003e](#ElectronAppInfo) - \u003cp\u003emetadata about the app\u003c/p\u003e  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| buildDir | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003eabsolute path to the build directory or the app itself\u003c/p\u003e |\n\n\u003ca name=\"electronWaitForFunction\"\u003e\u003c/a\u003e\n\n## electronWaitForFunction(electronApp, fn, arg) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eWait for a function to evaluate to true in the main Electron process. This really\nshould be part of the Playwright API, but it's not.\u003c/p\u003e\n\u003cp\u003eThis function is to \u003ccode\u003eelectronApp.evaluate()\u003c/code\u003e\nas \u003ccode\u003epage.waitForFunction()\u003c/code\u003e is \u003ccode\u003epage.evaluate()\u003c/code\u003e.\u003c/p\u003e\n\n**Kind**: global function  \n**Fulfil**: \u003ccode\u003evoid\u003c/code\u003e Resolves when the function returns true  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Playwright ElectronApplication\u003c/p\u003e |\n| fn | \u003ccode\u003efunction\u003c/code\u003e | \u003cp\u003ethe function to evaluate in the main process - must return a boolean\u003c/p\u003e |\n| arg | \u003ccode\u003eAny\u003c/code\u003e | \u003cp\u003eoptional - an argument to pass to the function\u003c/p\u003e |\n\n\u003ca name=\"evaluateWithRetry\"\u003e\u003c/a\u003e\n\n## evaluateWithRetry(electronApp, fn, arg, retries, retryIntervalMs) ⇒ \u003ccode\u003ePromise.\u0026lt;R\u0026gt;\u003c/code\u003e\n\u003cp\u003eElectron's \u003ccode\u003eevaluate\u003c/code\u003e function can be flakey,\nthrowing an error saying the execution context has been destroyed.\nThis function retries the evaluation several times to see if it can\nrun the evaluation without an error. If it fails after the retries,\nit throws the error.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;R\u0026gt;\u003c/code\u003e - \u003cul\u003e\n\u003cli\u003ethe result of the evaluation\u003c/li\u003e\n\u003c/ul\u003e  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Playwright ElectronApplication\u003c/p\u003e |\n| fn | \u003ccode\u003efunction\u003c/code\u003e | \u003cp\u003ethe function to evaluate in the main process\u003c/p\u003e |\n| arg | \u003ccode\u003eAny\u003c/code\u003e | \u003cp\u003ean argument to pass to the function\u003c/p\u003e |\n| retries |  | \u003cp\u003ethe number of times to retry the evaluation\u003c/p\u003e |\n| retryIntervalMs |  | \u003cp\u003ethe interval between retries\u003c/p\u003e |\n\n\u003ca name=\"isSerializedNativeImageSuccess\"\u003e\u003c/a\u003e\n\n## isSerializedNativeImageSuccess()\n\u003cp\u003eType guard to check if a SerializedNativeImage is a success case\u003c/p\u003e\n\n**Kind**: global function  \n\u003ca name=\"isSerializedNativeImageError\"\u003e\u003c/a\u003e\n\n## isSerializedNativeImageError()\n\u003cp\u003eType guard to check if a SerializedNativeImage is an error case\u003c/p\u003e\n\n**Kind**: global function  \n\u003ca name=\"retryUntilTruthy\"\u003e\u003c/a\u003e\n\n## retryUntilTruthy(fn, [timeoutMs], [intervalMs]) ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\n\u003cp\u003eRetries a given function until it returns a truthy value or the timeout is reached.\u003c/p\u003e\n\u003cp\u003eThis offers similar functionality to Playwright's \u003ca href=\"https://playwright.dev/docs/api/class-page#page-wait-for-function\"\u003e\u003ccode\u003epage.waitForFunction()\u003c/code\u003e\u003c/a\u003e\nmethod – but with more flexibility and control over the retry attempts. It also defaults to ignoring common errors due to\nthe way that Playwright handles browser contexts.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e - \u003cul\u003e\n\u003cli\u003eA promise that resolves to the truthy value returned by the function.\u003c/li\u003e\n\u003c/ul\u003e  \n**Throws**:\n\n- \u003ccode\u003eError\u003c/code\u003e \u003cul\u003e\n\u003cli\u003eThrows an error if the timeout is reached before a truthy value is returned.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| fn | \u003ccode\u003efunction\u003c/code\u003e |  | \u003cp\u003eThe function to retry. It can return a promise or a value. It should NOT return void/undefined.\u003c/p\u003e |\n| [timeoutMs] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e5000\u003c/code\u003e | \u003cp\u003eThe maximum time in milliseconds to keep retrying the function. Defaults to 5000ms.\u003c/p\u003e |\n| [intervalMs] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e100\u003c/code\u003e | \u003cp\u003eThe delay between each retry attempt in milliseconds. Defaults to 100ms.\u003c/p\u003e |\n| [options.retryTimeout] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e5000\u003c/code\u003e | \u003cp\u003eThe maximum time in milliseconds to wait for an individual try to return a result. Defaults to 5000ms.\u003c/p\u003e |\n| [options.retryPoll] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e200\u003c/code\u003e | \u003cp\u003eThe delay between each retry attempt in milliseconds. Defaults to 200ms.\u003c/p\u003e |\n| [options.retryErrorMatch] | \u003ccode\u003estring\u003c/code\u003e \\| \u003ccode\u003eArray.\u0026lt;string\u0026gt;\u003c/code\u003e \\| \u003ccode\u003eRegExp\u003c/code\u003e |  | \u003cp\u003eThe error message or pattern to match against. Errors that don't match will throw immediately.\u003c/p\u003e |\n\n**Example**  \n```javascript\ntest('my test', async () =\u003e {\n  // this will fail immediately if Playwright's context gets weird:\n  const oldWay = await page.waitForFunction(() =\u003e document.body.classList.contains('ready'))\n\n // this will not fail if Playwright's context gets weird:\n  const newWay = await retryUntilTruthy(() =\u003e\n    page.evaluate(() =\u003e document.body.classList.contains('ready'))\n  )\n})\n```\n\u003ca name=\"matchesPattern\"\u003e\u003c/a\u003e\n\n## matchesPattern()\n\u003cp\u003eHelper to match a string against a pattern (string or RegExp).\nFor strings, performs a substring match (includes).\nFor RegExp, tests the pattern against the value.\u003c/p\u003e\n\n**Kind**: global function  \n\u003ca name=\"ElectronAppInfo\"\u003e\u003c/a\u003e\n\n## ElectronAppInfo\n\u003cp\u003eFormat of the data returned from \u003ccode\u003eparseElectronApp()\u003c/code\u003e\u003c/p\u003e\n\n**Kind**: global typedef  \n**Properties**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| executable | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003epath to the Electron executable\u003c/p\u003e |\n| main | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003epath to the main (JS) file\u003c/p\u003e |\n| name | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ename of the your application\u003c/p\u003e |\n| resourcesDir | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003epath to the resources directory\u003c/p\u003e |\n| asar | \u003ccode\u003eboolean\u003c/code\u003e | \u003cp\u003ewhether the app is packaged as an asar archive\u003c/p\u003e |\n| platform | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003e'darwin', 'linux', or 'win32'\u003c/p\u003e |\n| arch | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003e'x64', 'x32', or 'arm64'\u003c/p\u003e |\n| packageJson | \u003ccode\u003ePackageJson\u003c/code\u003e | \u003cp\u003ethe \u003ccode\u003eJSON.parse()\u003c/code\u003e'd contents of the package.json file.\u003c/p\u003e |\n\n\u003ca name=\"stubDialog\"\u003e\u003c/a\u003e\n\n## stubDialog(app, method, value) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eStub a single dialog method. This is a convenience function that calls \u003ccode\u003estubMultipleDialogs\u003c/code\u003e\nfor a single method.\u003c/p\u003e\n\u003cp\u003ePlaywright does not have a way to interact with Electron dialog windows,\nso this function allows you to substitute the dialog module's methods during your tests.\nBy stubbing the dialog module, your Electron application will not display any dialog windows,\nand you can control the return value of the dialog methods. You're basically saying\n\u0026quot;when my application calls dialog.showOpenDialog, return this value instead\u0026quot;. This allows you\nto test your application's behavior when the user selects a file, or cancels the dialog, etc.\u003c/p\u003e\n\u003cp\u003eNote: Each dialog method can only be stubbed with one value at a time, so you will want to call\n\u003ccode\u003estubDialog\u003c/code\u003e before each time that you expect your application to call the dialog method.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e - \u003cp\u003eA promise that resolves when the mock is applied.\u003c/p\u003e  \n**Category**: Dialog  \n**Fullfil**: \u003ccode\u003evoid\u003c/code\u003e - A promise that resolves when the mock is applied.  \n**See**: stubMultipleDialogs  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| app | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003eThe Playwright ElectronApplication instance.\u003c/p\u003e |\n| method | \u003ccode\u003eString\u003c/code\u003e | \u003cp\u003eThe \u003ca href=\"https://www.electronjs.org/docs/latest/api/dialog#methods\"\u003edialog method\u003c/a\u003e to mock.\u003c/p\u003e |\n| value | \u003ccode\u003eReturnType.\u0026lt;Electron.Dialog\u0026gt;\u003c/code\u003e | \u003cp\u003eThe value that your application will receive when calling this dialog method. See the \u003ca href=\"https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options\"\u003eElectron docs\u003c/a\u003e for the return value of each method.\u003c/p\u003e |\n\n**Example**  \n```ts\nawait stubDialog(app, 'showOpenDialog', {\n filePaths: ['/path/to/file'],\n canceled: false,\n})\nawait clickMenuItemById(app, 'open-file')\n// when time your application calls dialog.showOpenDialog,\n// it will return the value you specified\n```\n\u003ca name=\"stubMultipleDialogs\"\u003e\u003c/a\u003e\n\n## stubMultipleDialogs(app, mocks) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eStub methods of the Electron dialog module.\u003c/p\u003e\n\u003cp\u003ePlaywright does not have a way to interact with Electron dialog windows,\nso this function allows you to mock the dialog module's methods during your tests.\nBy mocking the dialog module, your Electron application will not display any dialog windows,\nand you can control the return value of the dialog methods. You're basically saying\n\u0026quot;when my application calls dialog.showOpenDialog, return this value instead\u0026quot;. This allows you\nto test your application's behavior when the user selects a file, or cancels the dialog, etc.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e - \u003cp\u003eA promise that resolves when the mocks are applied.\u003c/p\u003e  \n**Category**: Dialog  \n**Fullfil**: \u003ccode\u003evoid\u003c/code\u003e - A promise that resolves when the mocks are applied.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| app | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003eThe Playwright ElectronApplication instance.\u003c/p\u003e |\n| mocks | \u003ccode\u003eArray.\u0026lt;DialogMethodStubPartial\u0026gt;\u003c/code\u003e | \u003cp\u003eAn array of dialog method mocks to apply.\u003c/p\u003e |\n\n**Example**  \n```ts\nawait stubMultipleDialogs(app, [\n {\n   method: 'showOpenDialog',\n   value: {\n     filePaths: ['/path/to/file1', '/path/to/file2'],\n     canceled: false,\n   },\n },\n {\n    method: 'showSaveDialog',\n    value: {\n      filePath: '/path/to/file',\n      canceled: false,\n    },\n  },\n])\nawait clickMenuItemById(app, 'save-file')\n// when your application calls dialog.showSaveDialog,\n// it will return the value you specified\n```\n\u003ca name=\"stubAllDialogs\"\u003e\u003c/a\u003e\n\n## stubAllDialogs(app) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eStub all dialog methods. This is a convenience function that calls \u003ccode\u003estubMultipleDialogs\u003c/code\u003e\nfor all dialog methods. This is useful if you want to ensure that dialogs are not displayed\nduring your tests. However, you may want to use \u003ccode\u003estubDialog\u003c/code\u003e or \u003ccode\u003estubMultipleDialogs\u003c/code\u003e to\ncontrol the return value of specific dialog methods (e.g. \u003ccode\u003eshowOpenDialog\u003c/code\u003e) during your tests.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e - \u003cp\u003eA promise that resolves when the mocks are applied.\u003c/p\u003e  \n**Category**: Dialog  \n**Fullfil**: \u003ccode\u003evoid\u003c/code\u003e - A promise that resolves when the mocks are applied.  \n**See**: stubDialog  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| app | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003eThe Playwright ElectronApplication instance.\u003c/p\u003e |\n\n\u003ca name=\"stubDialogMatchers\"\u003e\u003c/a\u003e\n\n## stubDialogMatchers(app, stubs, options) ⇒\n\u003cp\u003eStub dialog methods with matchers that check dialog options before returning values.\nThis allows you to set up multiple different return values based on the dialog's\ntitle, message, buttons, or other options.\u003c/p\u003e\n\u003cp\u003eMatchers are checked in order - the first matching stub wins.\nIf no stub matches, either an error is thrown (if throwOnUnmatched is true)\nor the default value is returned.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eA promise that resolves when the stubs are applied.\u003c/p\u003e  \n**Category**: Dialog  \n\n| Param | Description |\n| --- | --- |\n| app | \u003cp\u003eThe Playwright ElectronApplication instance.\u003c/p\u003e |\n| stubs | \u003cp\u003eArray of dialog matcher stubs to apply.\u003c/p\u003e |\n| options | \u003cp\u003eOptional configuration.\u003c/p\u003e |\n\n**Example**  \n```ts\n// Set up multiple dialog stubs at the start of your test\nawait stubDialogMatchers(app, [\n  {\n    method: 'showMessageBox',\n    matcher: { title: /delete/i, buttons: /yes/i },\n    value: { response: 1 }, // Click \"Yes\" for delete dialogs\n  },\n  {\n    method: 'showMessageBox',\n    matcher: { title: /save/i },\n    value: { response: 0 }, // Click \"Save\" for save dialogs\n  },\n  {\n    method: 'showOpenDialog',\n    matcher: { title: 'Select Image' },\n    value: { filePaths: ['/path/to/image.png'], canceled: false },\n  },\n  {\n    method: 'showOpenDialog',\n    matcher: {}, // Match all other open dialogs\n    value: { canceled: true },\n  },\n])\n```\n\u003ca name=\"clearDialogMatchers\"\u003e\u003c/a\u003e\n\n## clearDialogMatchers(app) ⇒\n\u003cp\u003eClear all dialog matcher stubs and restore original dialog methods.\nNote: This requires the app to have stored the original methods,\nwhich is not done by default. You may need to restart the app\nto fully restore dialog functionality.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eA promise that resolves when the stubs are cleared.\u003c/p\u003e  \n**Category**: Dialog  \n\n| Param | Description |\n| --- | --- |\n| app | \u003cp\u003eThe Playwright ElectronApplication instance.\u003c/p\u003e |\n\n\u003ca name=\"ipcMainEmit\"\u003e\u003c/a\u003e\n\n## ipcMainEmit(electronApp, message, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;boolean\u0026gt;\u003c/code\u003e\n\u003cp\u003eEmit an ipcMain message from the main process.\nThis will trigger all ipcMain listeners for the message.\u003c/p\u003e\n\u003cp\u003eThis does not transfer data between main and renderer processes.\nIt simply emits an event in the main process.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCMain  \n**Fulfil**: \u003ccode\u003eboolean\u003c/code\u003e true if there were listeners for this message  \n**Reject**: \u003ccode\u003eError\u003c/code\u003e if there are no ipcMain listeners for the event  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe ElectronApplication object from Playwright\u003c/p\u003e |\n| message | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe channel to call all ipcMain listeners for\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eone or more arguments to send\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"ipcMainCallFirstListener\"\u003e\u003c/a\u003e\n\n## ipcMainCallFirstListener(electronApp, message, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\n\u003cp\u003eCall the first listener for a given ipcMain message in the main process\nand return its result.\u003c/p\u003e\n\u003cp\u003eNOTE: ipcMain listeners usually don't return a value, but we're using\nthis to retrieve test data from the main process.\u003c/p\u003e\n\u003cp\u003eGenerally, it's probably better to use \u003ccode\u003eipcMainInvokeHandler()\u003c/code\u003e instead.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCMain  \n**Fulfil**: \u003ccode\u003eunknown\u003c/code\u003e resolves with the result of the function  \n**Reject**: \u003ccode\u003eError\u003c/code\u003e if there are no ipcMain listeners for the event  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe ElectronApplication object from Playwright\u003c/p\u003e |\n| message | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe channel to call the first listener for\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eone or more arguments to send\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"ipcMainInvokeHandler\"\u003e\u003c/a\u003e\n\n## ipcMainInvokeHandler(electronApp, message, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\n\u003cp\u003eGet the return value of an \u003ccode\u003eipcMain.handle()\u003c/code\u003e function\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCMain  \n**Fulfil**: \u003ccode\u003eunknown\u003c/code\u003e resolves with the result of the function called in main process  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe ElectronApplication object from Playwright\u003c/p\u003e |\n| message | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe channel to call the first listener for\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eone or more arguments to send\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"ipcRendererSend\"\u003e\u003c/a\u003e\n\n## ipcRendererSend(page, channel, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\n\u003cp\u003eSend an \u003ccode\u003eipcRenderer.send()\u003c/code\u003e (to main process) from a given window.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true and contextIsolation must be false\nin the webPreferences for this BrowserWindow.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCRenderer  \n**Fulfil**: \u003ccode\u003eunknown\u003c/code\u003e resolves with the result of `ipcRenderer.send()`  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | \u003cp\u003ethe Playwright Page to send the ipcRenderer.send() from\u003c/p\u003e |\n| channel | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe channel to send the ipcRenderer.send() to\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eone or more arguments to send to the \u003ccode\u003eipcRenderer.send()\u003c/code\u003e\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional last argument - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"ipcRendererInvoke\"\u003e\u003c/a\u003e\n\n## ipcRendererInvoke(page, message, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\n\u003cp\u003eSend an ipcRenderer.invoke() from a given window.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true and contextIsolation must be false\nin the webPreferences for this window\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCRenderer  \n**Fulfil**: \u003ccode\u003eunknown\u003c/code\u003e resolves with the result of ipcRenderer.invoke()  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | \u003cp\u003ethe Playwright Page to send the ipcRenderer.invoke() from\u003c/p\u003e |\n| message | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe channel to send the ipcRenderer.invoke() to\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eone or more arguments to send to the ipcRenderer.invoke()\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional last argument - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"ipcRendererCallFirstListener\"\u003e\u003c/a\u003e\n\n## ipcRendererCallFirstListener(page, message, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;unknown\u0026gt;\u003c/code\u003e\n\u003cp\u003eCall just the first listener for a given ipcRenderer channel in a given window.\n\u003cem\u003eUNLIKE MOST Electron ipcRenderer listeners\u003c/em\u003e, this function SHOULD return a value.\u003c/p\u003e\n\u003cp\u003eThis function does not send data between main and renderer processes.\nIt simply retrieves data from the renderer process.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true for this BrowserWindow.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCRenderer  \n**Fulfil**: \u003ccode\u003eunknown\u003c/code\u003e the result of the first `ipcRenderer.on()` listener  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | \u003cp\u003eThe Playwright Page to with the \u003ccode\u003eipcRenderer.on()\u003c/code\u003e listener\u003c/p\u003e |\n| message | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003eThe channel to call the first listener for\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eoptional - One or more arguments to send to the ipcRenderer.on() listener\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"ipcRendererEmit\"\u003e\u003c/a\u003e\n\n## ipcRendererEmit(page, message, ...args, retryOptions) ⇒ \u003ccode\u003ePromise.\u0026lt;boolean\u0026gt;\u003c/code\u003e\n\u003cp\u003eEmit an IPC message to a given window.\nThis will trigger all ipcRenderer listeners for the message.\u003c/p\u003e\n\u003cp\u003eThis does not transfer data between main and renderer processes.\nIt simply emits an event in the renderer process.\u003c/p\u003e\n\u003cp\u003eNote: nodeIntegration must be true for this window\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: IPCRenderer  \n**Fulfil**: \u003ccode\u003eboolean\u003c/code\u003e true if the event was emitted  \n**Reject**: \u003ccode\u003eError\u003c/code\u003e if there are no ipcRenderer listeners for the event  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | \u003cp\u003ethe Playwright Page to with the ipcRenderer.on() listener\u003c/p\u003e |\n| message | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe channel to call all ipcRenderer listeners for\u003c/p\u003e |\n| ...args | \u003ccode\u003eunknown\u003c/code\u003e | \u003cp\u003eoptional - one or more arguments to send\u003c/p\u003e |\n| retryOptions | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003cp\u003eoptional - options for retrying upon error\u003c/p\u003e |\n\n\u003ca name=\"clickMenuItemById\"\u003e\u003c/a\u003e\n\n## clickMenuItemById(electronApp, id) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eExecute the \u003ccode\u003e.click()\u003c/code\u003e method on the element with the given id.\n\u003cstrong\u003eNOTE:\u003c/strong\u003e All menu testing functions will only work with items in the\n\u003ca href=\"https://www.electronjs.org/docs/latest/api/menu#menusetapplicationmenumenu\"\u003eapplication menu\u003c/a\u003e.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003evoid\u003c/code\u003e resolves with the result of the `click()` method - probably `undefined`  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| id | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe id of the MenuItem to click\u003c/p\u003e |\n\n\u003ca name=\"clickMenuItem\"\u003e\u003c/a\u003e\n\n## clickMenuItem(electronApp, property, value) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eClick the first matching menu item by any of its properties. This is\nuseful for menu items that don't have an id. HOWEVER, this is not as fast\nor reliable as using \u003ccode\u003eclickMenuItemById()\u003c/code\u003e if the menu item has an id.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNOTE:\u003c/strong\u003e All menu testing functions will only work with items in the\n\u003ca href=\"https://www.electronjs.org/docs/latest/api/menu#menusetapplicationmenumenu\"\u003eapplication menu\u003c/a\u003e.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003evoid\u003c/code\u003e resolves with the result of the `click()` method - probably `undefined`  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| property | \u003ccode\u003eString\u003c/code\u003e | \u003cp\u003ea property of the MenuItem to search for\u003c/p\u003e |\n| value | \u003ccode\u003eString\u003c/code\u003e \\| \u003ccode\u003eNumber\u003c/code\u003e \\| \u003ccode\u003eBoolean\u003c/code\u003e | \u003cp\u003ethe value of the property to search for\u003c/p\u003e |\n\n\u003ca name=\"getMenuItemAttribute\"\u003e\u003c/a\u003e\n\n## getMenuItemAttribute(electronApp, menuId, attribute) ⇒ \u003ccode\u003ePromise.\u0026lt;string\u0026gt;\u003c/code\u003e\n\u003cp\u003eGet a given attribute the MenuItem with the given id.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003estring\u003c/code\u003e resolves with the attribute value  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| menuId | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe id of the MenuItem to retrieve the attribute from\u003c/p\u003e |\n| attribute | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe attribute to retrieve\u003c/p\u003e |\n\n\u003ca name=\"getMenuItemById\"\u003e\u003c/a\u003e\n\n## getMenuItemById(electronApp, menuId) ⇒ \u003ccode\u003ePromise.\u0026lt;MenuItemPartial\u0026gt;\u003c/code\u003e\n\u003cp\u003eGet information about the MenuItem with the given id. Returns serializable values including\nprimitives, objects, arrays, and other non-recursive data structures.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003eMenuItemPartial\u003c/code\u003e the MenuItem with the given id  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| menuId | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe id of the MenuItem to retrieve\u003c/p\u003e |\n\n\u003ca name=\"getApplicationMenu\"\u003e\u003c/a\u003e\n\n## getApplicationMenu(electronApp) ⇒ \u003ccode\u003ePromise.\u0026lt;Array.\u0026lt;MenuItemPartial\u0026gt;\u0026gt;\u003c/code\u003e\n\u003cp\u003eGet the current state of the application menu. Contains serializable values including\nprimitives, objects, arrays, and other non-recursive data structures.\nVery similar to menu\n\u003ca href=\"https://www.electronjs.org/docs/latest/api/menu#examples\"\u003econstruction template structure\u003c/a\u003e\nin Electron.\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003eMenuItemPartial[]\u003c/code\u003e an array of MenuItem-like objects  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n\n\u003ca name=\"findMenuItem\"\u003e\u003c/a\u003e\n\n## findMenuItem(electronApp, property, value, menuItems) ⇒ \u003ccode\u003ePromise.\u0026lt;MenuItemPartial\u0026gt;\u003c/code\u003e\n\u003cp\u003eFind a MenuItem by any of its properties\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003eMenuItemPartial\u003c/code\u003e the first MenuItem with the given property and value  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| property | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe property to search for\u003c/p\u003e |\n| value | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe value to search for\u003c/p\u003e |\n| menuItems | \u003ccode\u003eMenuItemPartial\u003c/code\u003e \\| \u003ccode\u003eArray.\u0026lt;MenuItemPartial\u0026gt;\u003c/code\u003e | \u003cp\u003eoptional - single MenuItem or array - if not provided, will be retrieved from the application menu\u003c/p\u003e |\n\n\u003ca name=\"waitForMenuItem\"\u003e\u003c/a\u003e\n\n## waitForMenuItem(electronApp, id) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eWait for a MenuItem to exist\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003evoid\u003c/code\u003e resolves when the MenuItem is found  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| id | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe id of the MenuItem to wait for\u003c/p\u003e |\n\n\u003ca name=\"waitForMenuItemStatus\"\u003e\u003c/a\u003e\n\n## waitForMenuItemStatus(electronApp, id, property, value) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\u003cp\u003eWait for a MenuItem to have a specific attribute value.\nFor example, wait for a MenuItem to be enabled... or be visible.. etc\u003c/p\u003e\n\n**Kind**: global function  \n**Category**: Menu  \n**Fulfil**: \u003ccode\u003evoid\u003c/code\u003e resolves when the MenuItem with correct status is found  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| electronApp | \u003ccode\u003eElectronApplication\u003c/code\u003e | \u003cp\u003ethe Electron application object (from Playwright)\u003c/p\u003e |\n| id | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe id of the MenuItem to wait for\u003c/p\u003e |\n| property | \u003ccode\u003estring\u003c/code\u003e | \u003cp\u003ethe property to search for\u003c/p\u003e |\n| value | \u003ccode\u003estring\u003c/code\u003e \\| \u003ccode\u003enumber\u003c/code\u003e \\| \u003ccode\u003eboolean\u003c/code\u003e | \u003cp\u003ethe value to search for\u003c/p\u003e |\n\n\u003ca name=\"addTimeoutToPromise\"\u003e\u003c/a\u003e\n\n## addTimeoutToPromise(promise, timeoutMs, timeoutMessage) ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\n\u003cp\u003eAdd a timeout to any Promise\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e - \u003cp\u003ethe result of the original promise if it resolves before the timeout\u003c/p\u003e  \n**Category**: Utilities  \n**See**: addTimeout  \n\n| Param | Default | Description |\n| --- | --- | --- |\n| promise |  | \u003cp\u003ethe promise to add a timeout to - must be a Promise\u003c/p\u003e |\n| timeoutMs | \u003ccode\u003e5000\u003c/code\u003e | \u003cp\u003ethe timeout in milliseconds - defaults to 5000\u003c/p\u003e |\n| timeoutMessage |  | \u003cp\u003eoptional - the message to return if the timeout is reached\u003c/p\u003e |\n\n\u003ca name=\"addTimeout\"\u003e\u003c/a\u003e\n\n## addTimeout(functionName, timeoutMs, timeoutMessage, ...args) ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\n\u003cp\u003eAdd a timeout to any helper function from this library which returns a Promise.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e - \u003cp\u003ethe result of the helper function if it resolves before the timeout\u003c/p\u003e  \n**Category**: Utilities  \n\n| Param | Default | Description |\n| --- | --- | --- |\n| functionName |  | \u003cp\u003ethe name of the helper function to call\u003c/p\u003e |\n| timeoutMs | \u003ccode\u003e5000\u003c/code\u003e | \u003cp\u003ethe timeout in milliseconds - defaults to 5000\u003c/p\u003e |\n| timeoutMessage |  | \u003cp\u003eoptional - the message to return if the timeout is reached\u003c/p\u003e |\n| ...args |  | \u003cp\u003eany arguments to pass to the helper function\u003c/p\u003e |\n\n\u003ca name=\"retry\"\u003e\u003c/a\u003e\n\n## retry(fn, [options]) ⇒ \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e\n\u003cp\u003eRetries a function until it returns without throwing an error.\u003c/p\u003e\n\u003cp\u003eStarting with Electron 27, Playwright can get very flakey when running code in Electron's main or renderer processes.\nIt will often throw errors like \u0026quot;context or browser has been closed\u0026quot; or \u0026quot;Promise was collected\u0026quot; for no apparent reason.\nThis function retries a given function until it returns without throwing one of these errors, or until the timeout is reached.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003ccode\u003ePromise.\u0026lt;T\u0026gt;\u003c/code\u003e - \u003cp\u003eA promise that resolves with the result of the function or rejects with an error or timeout message.\u003c/p\u003e  \n**Category**: Utilities  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| fn | \u003ccode\u003efunction\u003c/code\u003e |  | \u003cp\u003eThe function to retry.\u003c/p\u003e |\n| [options] | \u003ccode\u003eRetryOptions\u003c/code\u003e | \u003ccode\u003e{}\u003c/code\u003e | \u003cp\u003eThe options for retrying the function.\u003c/p\u003e |\n| [options.timeout] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e5000\u003c/code\u003e | \u003cp\u003eThe maximum time to wait before giving up in milliseconds.\u003c/p\u003e |\n| [options.poll] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e200\u003c/code\u003e | \u003cp\u003eThe delay between each retry attempt in milliseconds.\u003c/p\u003e |\n| [options.errorMatch] | \u003ccode\u003estring\u003c/code\u003e \\| \u003ccode\u003eArray.\u0026lt;string\u0026gt;\u003c/code\u003e \\| \u003ccode\u003eRegExp\u003c/code\u003e | \u003ccode\u003e\u0026quot;[\u0026#x27;context or browser has been closed\u0026#x27;, \u0026#x27;Promise was collected\u0026#x27;, \u0026#x27;Execution context was destroyed\u0026#x27;]\u0026quot;\u003c/code\u003e | \u003cp\u003eString(s) or regex to match against error message. If the error does not match, it will throw immediately. If it does match, it will retry.\u003c/p\u003e |\n\n**Example**  \nYou can simply wrap your Playwright calls in this function to make them more reliable:\n\n```javascript\ntest('my test', async () =\u003e {\n  // instead of this:\n  const oldWayRenderer = await page.evaluate(() =\u003e document.body.classList.contains('active'))\n  const oldWayMain = await electronApp.evaluate(({}) =\u003e document.body.classList.contains('active'))\n  // use this:\n  const newWay = await retry(() =\u003e\n    page.evaluate(() =\u003e document.body.classList.contains('active'))\n  )\n  // note the `() =\u003e` in front of the original function call\n  // and the `await` keyword in front of `retry`,\n  // but NOT in front of `page.evaluate`\n})\n```\n\u003ca name=\"setRetryOptions\"\u003e\u003c/a\u003e\n\n## setRetryOptions(options) ⇒\n\u003cp\u003eSets the default retry() options. These options will be used for all subsequent calls to retry() unless overridden.\nYou can reset the defaults at any time by calling resetRetryOptions().\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eThe updated retry options.\u003c/p\u003e  \n**Category**: Utilities  \n\n| Param | Description |\n| --- | --- |\n| options | \u003cp\u003eA partial object containing the retry options to be set.\u003c/p\u003e |\n\n\u003ca name=\"getRetryOptions\"\u003e\u003c/a\u003e\n\n## getRetryOptions() ⇒\n\u003cp\u003eGets the current default retry options.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eThe current retry options.\u003c/p\u003e  \n**Category**: Utilities  \n\u003ca name=\"resetRetryOptions\"\u003e\u003c/a\u003e\n\n## resetRetryOptions()\n\u003cp\u003eResets the retry options to their default values.\u003c/p\u003e\n\u003cp\u003eThe default values are:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eretries: 20\u003c/li\u003e\n\u003cli\u003eintervalMs: 200\u003c/li\u003e\n\u003cli\u003etimeoutMs: 5000\u003c/li\u003e\n\u003cli\u003eerrorMatch: 'context or browser has been closed'\u003c/li\u003e\n\u003c/ul\u003e\n\n**Kind**: global function  \n**Category**: Utilities  \n\u003ca name=\"errToString\"\u003e\u003c/a\u003e\n\n## errToString(err) ⇒\n\u003cp\u003eConverts an unknown error to a string representation.\u003c/p\u003e\n\u003cp\u003eThis function handles different types of errors and attempts to convert them\nto a string in a meaningful way. It checks if the error is an object with a\n\u003ccode\u003etoString\u003c/code\u003e method and uses that method if available. If the error is a string,\nit returns the string directly. For other types, it converts the error to a\nJSON string.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eA string representation of the error.\u003c/p\u003e  \n**Category**: Utilities  \n\n| Param | Description |\n| --- | --- |\n| err | \u003cp\u003eThe unknown error to be converted to a string.\u003c/p\u003e |\n\n\u003ca name=\"getWindowByUrl\"\u003e\u003c/a\u003e\n\n## getWindowByUrl(electronApp, pattern, options) ⇒\n\u003cp\u003eGet all windows whose URL matches the given pattern.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eAn array of matching Pages\u003c/p\u003e  \n**Category**: Window Helpers  \n\n| Param | Description |\n| --- | --- |\n| electronApp | \u003cp\u003eThe Playwright ElectronApplication\u003c/p\u003e |\n| pattern | \u003cp\u003eA string (substring match) or RegExp to match against the URL\u003c/p\u003e |\n| options | \u003cp\u003eOptions with \u003ccode\u003eall: true\u003c/code\u003e to return all matches\u003c/p\u003e |\n\n**Example**  \n```ts\nconst allSettingsWindows = await getWindowByUrl(app, '/settings', { all: true })\n```\n\u003ca name=\"getWindowByTitle\"\u003e\u003c/a\u003e\n\n## getWindowByTitle(electronApp, pattern, options) ⇒\n\u003cp\u003eGet all windows whose title matches the given pattern.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eAn array of matching Pages\u003c/p\u003e  \n**Category**: Window Helpers  \n\n| Param | Description |\n| --- | --- |\n| electronApp | \u003cp\u003eThe Playwright ElectronApplication\u003c/p\u003e |\n| pattern | \u003cp\u003eA string (substring match) or RegExp to match against the title\u003c/p\u003e |\n| options | \u003cp\u003eOptions with \u003ccode\u003eall: true\u003c/code\u003e to return all matches\u003c/p\u003e |\n\n**Example**  \n```ts\nconst allNumberedWindows = await getWindowByTitle(app, /Window \\d+/, { all: true })\n```\n\u003ca name=\"getWindowByMatcher\"\u003e\u003c/a\u003e\n\n## getWindowByMatcher(electronApp, matcher, options) ⇒\n\u003cp\u003eGet all windows that match the provided matcher function.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eAn array of matching Pages\u003c/p\u003e  \n**Category**: Window Helpers  \n\n| Param | Description |\n| --- | --- |\n| electronApp | \u003cp\u003eThe Playwright ElectronApplication\u003c/p\u003e |\n| matcher | \u003cp\u003eA function that receives a Page and returns true if it matches\u003c/p\u003e |\n| options | \u003cp\u003eOptions with \u003ccode\u003eall: true\u003c/code\u003e to return all matches\u003c/p\u003e |\n\n**Example**  \n```ts\nconst allLargeWindows = await getWindowByMatcher(app, async (page) =\u003e {\n  const size = await page.viewportSize()\n  return size \u0026\u0026 size.width \u003e 1000\n}, { all: true })\n```\n\u003ca name=\"waitForWindowByUrl\"\u003e\u003c/a\u003e\n\n## waitForWindowByUrl(electronApp, pattern, options) ⇒\n\u003cp\u003eWait for a window whose URL matches the given pattern.\u003c/p\u003e\n\u003cp\u003eThis function checks existing windows first, then listens for new windows.\nIt uses polling to handle windows that may have their URL change after opening.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eThe matching Page\u003c/p\u003e  \n**Category**: Window Helpers  \n**Throws**:\n\n- \u003cp\u003eError if timeout is reached before a matching window is found\u003c/p\u003e\n\n\n| Param | Description |\n| --- | --- |\n| electronApp | \u003cp\u003eThe Playwright ElectronApplication\u003c/p\u003e |\n| pattern | \u003cp\u003eA string (substring match) or RegExp to match against the URL\u003c/p\u003e |\n| options | \u003cp\u003eOptional timeout and interval settings\u003c/p\u003e |\n\n**Example**  \n```ts\n// Click something that opens a new window, then wait for it\nawait page.click('#open-settings')\nconst settingsWindow = await waitForWindowByUrl(app, '/settings', { timeout: 5000 })\n```\n\u003ca name=\"waitForWindowByTitle\"\u003e\u003c/a\u003e\n\n## waitForWindowByTitle(electronApp, pattern, options) ⇒\n\u003cp\u003eWait for a window whose title matches the given pattern.\u003c/p\u003e\n\u003cp\u003eThis function checks existing windows first, then listens for new windows.\nIt uses polling to handle windows that may have their title change after opening.\u003c/p\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eThe matching Page\u003c/p\u003e  \n**Category**: Window Helpers  \n**Throws**:\n\n- \u003cp\u003eError if timeout is reached before a matching window is found\u003c/p\u003e\n\n\n| Param | Description |\n| --- | --- |\n| electronApp | \u003cp\u003eThe Playwright ElectronApplication\u003c/p\u003e |\n| pattern | \u003cp\u003eA string (substring match) or RegExp to match against the title\u003c/p\u003e |\n| options | \u003cp\u003eOptional timeout and interval settings\u003c/p\u003e |\n\n**Example**  \n```ts\n// Wait for a window with a specific title to appear\nconst prefsWindow = await waitForWindowByTitle(app, 'Preferences', { timeout: 5000 })\n```\n\u003ca name=\"waitForWindowByMatcher\"\u003e\u003c/a\u003e\n\n## waitForWindowByMatcher(electronApp, matcher, options) ⇒\n\u003cp\u003eWait for a window that matches the provided matcher function.\u003c/p\u003e\n\u003cp\u003eThis function:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eChecks existing windows first\u003c/li\u003e\n\u003cli\u003eListens for new window events\u003c/li\u003e\n\u003cli\u003ePolls existing windows periodically (to catch URL/title changes)\u003c/li\u003e\n\u003c/ol\u003e\n\n**Kind**: global function  \n**Returns**: \u003cp\u003eThe matching Page\u003c/p\u003e  \n**Category**: Window Helpers  \n**Throws**:\n\n- \u003cp\u003eError if timeout is reached before a matching window is found\u003c/p\u003e\n\n\n| Param | Description |\n| --- | --- |\n| electronApp | \u003cp\u003eThe Playwright ElectronApplication\u003c/p\u003e |\n| matcher | \u003cp\u003eA function that receives a Page and returns true if it matches\u003c/p\u003e |\n| options | \u003cp\u003eOptional timeout and interval settings\u003c/p\u003e |\n\n**Example**  \n```ts\nconst window = await waitForWindowByMatcher(app, async (page) =\u003e {\n  const title = await page.title()\n  return title.startsWith('Document:')\n}, { timeout: 10000 })\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspaceagetv%2Felectron-playwright-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspaceagetv%2Felectron-playwright-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspaceagetv%2Felectron-playwright-helpers/lists"}