Skip to content

Latest commit

 

History

History

README.md

@packages/electron

This package is responsible for installing, building, and managing the Electron binary that powers Cypress. It enables development with an Electron shell that matches the final compiled Cypress binary 1:1 by using symlinks during development.

Build System

The package uses TypeScript to compile to CJS. ESM builds are not run by default, but can be enabled or tested with build:esm.

  • CommonJS: Primary build used by the binary script and other packages
  • ES Modules: Alternative build for modern Node.js applications
  • Output: Compiled JavaScript in dist/cjs/, and a binary in dist/Cypress.

Building

# Build both CommonJS and ES Module versions
yarn workspace @packages/electron build

# Build only CommonJS version
yarn workspace @packages/electron build:cjs

# Build only ES Module version
yarn workspace @packages/electron build:esm

# Clean build artifacts
yarn workspace @packages/electron clean-deps

Note: The build process compiles TypeScript source to JavaScript. The --install command packages the actual Electron binary for your OS-specific platform.

Usage

Command Line Interface

The package provides a binary script cypress-electron with several commands:

# Install/build Electron binary for current platform
./bin/cypress-electron --install

# Show help and usage information
./bin/cypress-electron --help

# Launch an Electron app (development mode)
./bin/cypress-electron /path/to/your/app

# Launch with debugging enabled
./bin/cypress-electron /path/to/your/app --inspect-brk

These commands are parsed out from argv in the cli() function defined in ./lib/electron.ts

Public Interface

/**
 * Checks if Electron binary exists and is up-to-date, installs if needed
 */
function installIfNeeded(): Promise<void>

/**
 * Forces installation of Electron binary with optional arguments
 */
function install(...args: any[]): Promise<void>

/**
 * Launches an Electron app with the specified path and arguments
 * @param appPath - Path to the application to launch
 * @param argv - Command line arguments to pass to the app
 * @param callback - Optional callback when the app exits
 * @returns Promise that resolves to the spawned Electron process
 */
function open(
  appPath: string, 
  argv: string[], 
  callback?: (code: number) => void
): Promise<ChildProcess>

/**
 * Returns the Electron version being used
 * @returns String version (e.g., "36.4.0")
 */
function getElectronVersion(): string

/**
 * Returns the Node.js version bundled with Electron
 * @returns Promise that resolves to Node.js version string
 */
function getElectronNodeVersion(): Promise<string>

/**
 * Returns the icons package for platform-specific icon paths
 * @returns Icons package object
 */
function icons(): any

/**
 * CLI entry point for command-line operations
 * @param argv - Command line arguments array
 */
function cli(argv: string[]): void

Testing

# Run unit tests
yarn workspace @packages/electron test

# Run tests with debugger
yarn workspace @packages/electron test-debug

# Run tests in watch mode
yarn workspace @packages/electron test-watch

Package Structure

packages/electron/
├── bin/                    # Binary scripts
│   └── cypress-electron   # Main CLI script
├── lib/                    # TypeScript source
│   ├── electron.ts        # Main entry point and CLI logic
│   ├── install.ts         # Installation and packaging logic
│   ├── paths.ts           # Platform-specific path resolution
│   └── print-node-version.ts
├── dist/                   # Compiled output
│   ├── cjs/               # CommonJS build
│   ├── esm/               # ES Module build
│   └── Cypress/           # Electron app binary (created by --install)
├── app/                    # App template for packaging
└── test/                   # Test files

Upgrading Electron

The version of electron that is bundled with Cypress should be kept as up-to-date as possible with the stable Electron releases. Many users expect the bundled Chromium and Node.js to be relatively recent. Also, historically, it has been extremely difficult to upgrade over multiple major versions of Electron at once, because of all the breaking changes in Electron and Node.js that impact Cypress.

Upgrading electron involves more than just bumping this package's package.json. Here are additional tasks to check off when upgrading Electron:

  • Write accurate changelog items. The "User-facing changelog" for an Electron upgrade should mention the new Node.js and Chromium versions bundled. If this is a patch version of electron, a changelog entry might not be needed.

    • For example:
      • Upgraded electron from 21.0.0 to 25.8.4.
      • Upgraded bundled Node.js version from 16.16.0 to 18.15.0.
      • Upgraded bundled Chromium version from 106.0.5249.51 to 114.0.5735.289.
  • Determine if the Electron upgrade is a breaking change. Electron upgrades constitute "breaking changes" in Cypress if:

    • the major version number of Node.js changes, since users rely on the bundled Node.js to load plugins and .js fixtures, or
    • there are changes to Electron that require new shared libraries to be installed on Linux, breaking existing CI setups, or
    • there is some other change that would break existing usage of Cypress (for example, a Web API feature being removed/added to the bundled Chromium)
  • Create and publish Docker base-internal family images matching the Node.js and Chromium versions in Electron. These images live inside the cypress-docker-images repository. The base-internal images will be used inside our CI pipelines. For general use of Cypress in Docker, we encourage the use of the Cypress Docker Factory. This works great for using Cypress as an end user, but doesn't fully suit the needs for developing Cypress, as we require:

    • The installation of packages, such as curl, xauth, and build-essential/make needed for our circleci jobs/pipelines.
    • Specific images targeted to test Cypress on various node versions and distributions of linux, such as different versions of ubuntu.

    These images are currently created on an 'as-needed' basis and are published manually to the cypress docker repository. When creating these images, make sure:

  • Update src/@workflows.yml

    • Ensure it references the new base-internal Docker images
  • Ensure that a matching Node.js version is enforced in the monorepo for local development and CI. When Electron is upgraded, oftentimes, the bundled Node.js version that comes with Electron is updated as well. Because all unit and integration tests run in normal Node.js (not Electron's Node.js), it's important for this Node.js version to be synced with the monorepo. There are a few places where this needs to be done:

    • /.node-version - used by some Node version managers
    • /.nvmrc - used by nvm
    • @types/node used throughout the monorepo to determine compatible node types. The major version of this package must reflect the node version set in /.node-version.
    • github workflows - used for repository templates, vulnerability detection, and V8 snapshots. If the node version for Snyk needs to be updated, then the required pull request check into develop must also be updated. A repository administrator will need to accomplish this.
    • /package.json - update engines
    • docker-compose.yml - update Docker image to the new matching internal image
    • /system-tests/test-binary/* - update binary system tests to use the newly published Ubuntu and Node images mentioned above, if applicable
    • Do a global search for the old Node.js version to identify any new areas that may need updating/unification, and update those locations (and this document!)
  • Update better-sqlite3 version if needed Look through the commit history of better-sqlite3 and find the first version that supports the proper version of electron's prebuilds. Update /packages/server/package.json and /packages/types/package.json to the appropriate version.

  • Update cypress-publish-binary For binary publishing, make sure the electron version that we updated in /package.json matches the electron version inside the publish binary project. This is to make sure add-on tests inside the publish-binary repository work locally, but are not required to install the correct version of electron in CI when publishing the binary. Ensure the electron target in this project's .circleci configuration is updated as well. Set the Remove this before merging, and ensure that branch is merged as well.

    • Create a new branch in cypress-publish-binary
    • Update electron version in package.json
    • Update the target electron version in the circle configuration
    • Update the docker image to the new browsers-internal image made in the previous step
    • Add your branch name to the &full-workflow-filters anchor in @pipeline.yml
    • Trigger the pipeline in CircleCI's UI, and set the publish-binary-branch parameter to the branch you created in the cypress-publish-binary repository.
  • Manually smoke test cypress open. Upgrading Electron can break the desktop-gui in unexpected ways. Since testing in this area is weak, double-check that things like launching cypress open, signing into Cypress Cloud, and launching Electron tests still work.

  • Manually smoke test cypress run in record mode Upgrading Electron can cause better-sqlite3 to SIGSEGV the Electron process.

  • Fix failing tests. Usually, these are due to breaking changes in either Node.js or Electron. Check the changelogs of both to find relevant changes.

  • If needed, update the V8 Snapshot Cache by running the GitHub workflow. Make sure to use the branch that contains the electron updates to populate the 'workflow from' and 'branch to update' arguments. Select 'Generate from scratch' and 'commit directly to branch'. This will usually take 6-8 hours to complete and is best to not be actively developing on the branch when this workflow runs.

Development

Local Development

  1. Build the package: yarn build:cjs (or yarn build for both formats)
  2. Test the binary: ./bin/cypress-electron --install
  3. Run tests: yarn test

Debugging

Enable debug logging by setting the DEBUG environment variable:

DEBUG=cypress:electron* ./bin/cypress-electron --install
DEBUG=cypress:electron:install* ./bin/cypress-electron --install

Common Issues

Build Errors

  • TypeScript compilation errors: Check that all dependencies are installed and TypeScript config is correct
  • Missing dependencies: Ensure @electron/packager and other dev dependencies are available

Runtime Errors

  • Path resolution issues: Verify that the compiled output structure matches the expected paths
  • Binary not found: Run ./bin/cypress-electron --install to create the Electron binary
  • Permission errors: On Linux, ensure proper permissions for the binary directory

Platform-Specific Issues

  • macOS: ARM64 vs x64 architecture detection may need updates
  • Linux: Sandbox issues when running as root (automatically handled)
  • Windows: Junction vs directory symlink handling (automatically handled)

Contributing

When contributing to this package:

  1. Follow the existing patterns for error handling and logging
  2. Test on multiple platforms if making platform-specific changes
  3. Update tests for any new functionality
  4. Rebuild after changes using yarn build:cjs
  5. Test the binary with ./bin/cypress-electron --install

For more detailed information about the build system, see BUILD.md.

Common Upgrade Issues

Integrity Check Failures

Solution: Update the string representation of fs.readFileSync in scripts/binary/binary-integrity-check-source.js to match the string generated by the new version of electron. To do this, create a throw-away script that runs console.log(fs.readFileSync.toString()). Execute this with Electron rather than Node (ie. npm i -g electron@x.y.z && electron throwaway-script.js).

ResizeObserver errors in Component Test

Solution: This error is benign. From time to time, the error message we match against in order to swallow the error changes. Update the necessary support files with the new error message.

Electron crashes immediately after initializing the Protocol database

Solution: This is often due to a mismatched prebuild of better-sqlite3. Ensure your repository is clear of untracked files with git clean -xfd, and run yarn again. If the issue persists, ensure you are running the latest version of your operating system. Electron prebuilds key to darwin/linux/windows, and do not differentiate between versions of the same.

node-abi out of date

If you run into an error like below, please try some of the strategies below.

Could not detect abi for version X.X.X and runtime electron.  Updating "node-abi" might help solve this issue if it is a new release of electron

Solution: See if there's a new version of @electron/rebuild with a newer version of node-abi within it. If there is not a newer version, find the latest release of node-abi that has an updated ABI registry with an abi entry matching the major version of Electron that you're updating to. Set this node-abi version in the resolutions of our package.json file and rerun yarn.