diff --git a/packages/server/lib/reporter.js b/packages/server/lib/reporter.js index 1cb6d2e914bf..e4dba7703186 100644 --- a/packages/server/lib/reporter.js +++ b/packages/server/lib/reporter.js @@ -13,6 +13,9 @@ const mochaSymbols = mochaReporters.Base.symbols const debug = require('debug')('cypress:server:reporter') const Promise = require('bluebird') const { overrideRequire } = require('./override_require') +const { tryToFindPnpFile } = require('./util/search-utils') + +const yarnPnpRegistrationPath = new Map() // override calls to `require('mocha*')` when to always resolve with a mocha we control // otherwise mocha will be resolved from project's node_modules and might not work with our code @@ -669,6 +672,21 @@ class Reporter { debug('trying to load reporter:', reporterName) + // we only need to register this once, when the project check dependencies for the first time. + if (!yarnPnpRegistrationPath.get(projectRoot)) { + const pnpFile = tryToFindPnpFile(projectRoot) + + if (pnpFile) { + const pnpapi = require(pnpFile) + + pnpapi.setup() + yarnPnpRegistrationPath.set(projectRoot, true) + } else { + // not using Yarn PnP + yarnPnpRegistrationPath.set(projectRoot, false) + } + } + // Explicitly require this here (rather than dynamically) so that it gets included in the v8 snapshot if (reporterName === 'teamcity') { debug(`${reporterName} is built-in reporter`) diff --git a/packages/server/lib/util/search-utils.js b/packages/server/lib/util/search-utils.js new file mode 100644 index 000000000000..eec6a6dbd51a --- /dev/null +++ b/packages/server/lib/util/search-utils.js @@ -0,0 +1,65 @@ +const findUp = require('find-up') +const path = require('path') +const fs = require('fs-extra') +const Debug = require('debug') + +const debug = Debug('cypress:scaffold-config:searchUtils') + +const ROOT_PATHS = [ + '.git', + 'pnpm-workspace.yaml', + 'rush.json', + 'workspace.json', + 'nx.json', + 'lerna.json', +] + +function hasWorkspacePackageJson (directory) { + try { + const pkg = require(path.join(directory, 'package.json')) + + debug('package file for %s: %o', directory, pkg) + + return !!pkg.workspaces + } catch (e) { + debug('error reading package.json in %s. this is not the repository root', directory) + + return false + } +} + +function isRepositoryRoot (directory) { + if (ROOT_PATHS.some((rootPath) => fs.existsSync(path.join(directory, rootPath)))) { + return true + } + + return hasWorkspacePackageJson(directory) +} + +function tryToFindPnpFile (projectPath) { + return findUp((directory) => { + const isCurrentRepositoryRoot = isRepositoryRoot(directory) + + const file = path.join(directory, '.pnp.cjs') + const hasPnpCjs = fs.existsSync(file) + + if (hasPnpCjs) { + return file + } + + if (isCurrentRepositoryRoot) { + debug('stopping search at %s because it is believed to be the repository root', directory) + + return findUp.stop + } + + // Return undefined to keep searching + return undefined + }, { cwd: projectPath }) +} + +module.exports = { + hasWorkspacePackageJson, + isRepositoryRoot, + tryToFindPnpFile, +}