Resolving Yarn2 + Cypress GitHub Action: Cannot find module ‘cypress’

Charles Stover
2 min readOct 23, 2021

An open issue exists for running the Cypress.io end-to-end test GitHub Action in a Yarn2 plug-and-play repository: the action fails with the following error:

Error: Cannot find module 'cypress'
Require stack:
- /home/runner/work/_actions/cypress-io/github-action/v2/dist/index.js

I dug into resolving this myself, and I found the root cause to be this line of the GitHub Action:

// If `command:` is provided, run it.
const customCommand = core.getInput('command')
if (customCommand) {
console.log('Using custom test command: %s', customCommand)
return execCommand(customCommand, true, 'run tests')
}
// If `command-prefix:` is provided, use it.
const commandPrefix = core.getInput('command-prefix')
if (commandPrefix) {
return runTestsUsingCommandLine()
}
// Otherwise, find `cypress` and run it.
debug('Running Cypress tests using NPM module API') debug(`requiring cypress dependency, cwd is ${process.cwd()}`)
debug(`working directory ${workingDirectory}`)
const cypressModulePath =
require.resolve('cypress', {
paths: [workingDirectory]
}) || 'cypress'
debug(`resolved cypress ${cypressModulePath}`)

In the above code, implementations that do not provide a command or command-prefix variable in the GitHub Action’s with configuration fallback to the require.resolve method in Node. This means that implementations that use command (like command: yarn cypress) or a command-prefix will not encounter this error, since they will not reach the line that contains require.resolve.

Resolving the path to cypress fails on a Yarn2 repository, because the GitHub Action executes its Node script using NPM. It therefore makes the assumption that NPM installed its dependencies, despite otherwise checking for Yarn installations. I contributed a request to the original issue to support Yarn’s .pnp.cjs file, which should patch require.resolve to find modules installed using Plug and Play.

To unblock yourself until this gets formal support, add command-prefix: yarn dlx. By replacing cypress run --flags with yarn dlx cypress run --flags, the Node module command is passed through yarn first, which injects the .pnp.cjs file for Plug and Play support.

While you can add a script to your package.json file that contains cypress run — flags, the command-prefix option offers one important benefit over its command alternative: automatically injecting flags as specified by with. When you use command, your configuration in with will be ignored, requiring you to specify all your flags in the NPM script definition in package.json. While this is fine for many use cases, allowing you to easily run your Cypress tests locally, it becomes problematic when using GitHub secrets (such as your record key) in your Cypress run.

For any souls brave to dive deeper than my investigation, the Cypress team might appreciate a pull request to resolve this issue in code. 😉

Charles Stover

Staff front end engineer | Tech lead | Architect | charlesstover.com