Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add yarn v2 pnp support to default webpack processor #17335

Merged
merged 10 commits into from
Jul 21, 2021
11 changes: 11 additions & 0 deletions cli/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,20 @@ const util = {
.mapValues((value) => { // stringify to 1 or 0
return value ? '1' : '0'
})
.extend(util.getOriginalNodeOptions(options))
.value()
},

getOriginalNodeOptions (options) {
if (process.env.NODE_OPTIONS) {
return {
ORIGINAL_NODE_OPTIONS: process.env.NODE_OPTIONS,
}
}

return {}
},

getForceTty () {
return {
FORCE_STDIN_TTY: util.isTty(process.stdin.fd),
Expand Down
22 changes: 22 additions & 0 deletions cli/test/lib/util_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ require('../spec_helper')
const os = require('os')
const tty = require('tty')
const snapshot = require('../support/snapshot')
const mockedEnv = require('mocked-env')
const supportsColor = require('supports-color')
const proxyquire = require('proxyquire')
const hasha = require('hasha')
Expand Down Expand Up @@ -254,6 +255,27 @@ describe('util', () => {
})
})

context('.getOriginalNodeOptions', () => {
let restoreEnv

afterEach(() => {
if (restoreEnv) {
restoreEnv()
restoreEnv = null
}
})

it('copy NODE_OPTIONS to ORIGINAL_NODE_OPTIONS', () => {
restoreEnv = mockedEnv({
NODE_OPTIONS: '--require foo.js',
})

expect(util.getOriginalNodeOptions({})).to.deep.eq({
ORIGINAL_NODE_OPTIONS: '--require foo.js',
})
})
})

context('.exit', () => {
it('calls process.exit', () => {
process.exit.withArgs(2).withArgs(0)
Expand Down
28 changes: 28 additions & 0 deletions npm/webpack-batteries-included-preprocessor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,28 @@ const addTypeScriptConfig = (file, options) => {
options.__typescriptSupportAdded = true
}

/**
* Config yarn pnp plugin for webpack 4
* @param {*} file file to be processed
* @param {*} options
*/
const addYarnPnpConfig = (file, options) => {
const { makeResolver } = require('pnp-webpack-plugin/resolver')
const findPnpApi = require('module').findPnpApi

if (findPnpApi && file.filePath) {
const pnpapi = findPnpApi(file.filePath)

if (pnpapi) {
const PnpPlugin = {
apply: makeResolver({ pnpapi }),
}

options.webpackOptions.resolve.plugins.push(PnpPlugin)
}
}
}

const getDefaultWebpackOptions = () => {
return {
mode: 'development',
Expand Down Expand Up @@ -125,6 +147,7 @@ const getDefaultWebpackOptions = () => {
'repl': require.resolve('./empty'),
'tls': require.resolve('./empty'),
},
plugins: [],
},
}
}
Expand All @@ -143,6 +166,11 @@ const preprocessor = (options = {}) => {
addTypeScriptConfig(file, options)
}

if (process.versions.pnp) {
// pnp path
addYarnPnpConfig(file, options)
}

return webpackPreprocessor(options)(file)
}
}
Expand Down
3 changes: 2 additions & 1 deletion npm/webpack-batteries-included-preprocessor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"babel-plugin-add-module-exports": "^1.0.2",
"coffee-loader": "^0.9.0",
"coffeescript": "^1.12.7",
"pnp-webpack-plugin": "^1.7.0",
"ts-loader": "^8.0.2",
"tsconfig-package": "npm:tsconfig@^7.0.0",
"tsconfig-paths-webpack-plugin": "^3.3.0",
Expand Down Expand Up @@ -65,4 +66,4 @@
"publishConfig": {
"access": "public"
}
}
}
4 changes: 4 additions & 0 deletions packages/server/lib/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ const init = (config, options) => {
const childArguments = ['--file', pluginsFile, '--projectRoot', options.projectRoot]
const childOptions = {
stdio: 'pipe',
env: {
...process.env,
NODE_OPTIONS: process.env.ORIGINAL_NODE_OPTIONS || '',
},
}

if (config.resolvedNodePath) {
Expand Down
9 changes: 2 additions & 7 deletions packages/server/lib/util/resolve.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const resolve = require('resolve')
const env = require('./env')
const debug = require('debug')('cypress:server:plugins')

Expand All @@ -15,13 +14,9 @@ module.exports = {
}

try {
const options = {
basedir: projectRoot,
}
debug('resolving typescript with projectRoot %o', projectRoot)

debug('resolving typescript with options %o', options)

const resolved = resolve.sync('typescript', options)
const resolved = require.resolve('typescript', { paths: [projectRoot] })

debug('resolved typescript %s', resolved)

Expand Down
59 changes: 59 additions & 0 deletions packages/server/test/e2e/4_yarn_v2_pnp_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
import cp from 'child_process'
import util from 'util'
import e2e from '../support/helpers/e2e'
import Fixtures from '../support/helpers/fixtures'

const exec = async (cmd, ...args) => {
console.log(`Running "${cmd}"...`)
const ret = await util.promisify(cp.exec)(cmd, ...args)
.catch((err) => {
console.error('Error:', err)

return err
})

console.log('stdout:', ret.stdout)
ret.stderr && console.log('stderr:', ret.stderr)

return ret
}

const fixtureDir = Fixtures.path('projects/yarn-v2-pnp')
const cypressCli = path.join(__dirname, '../../../../cli/bin/cypress')

describe('e2e yarn v2', () => {
let projectDir

beforeEach(async function () {
this.timeout(240000)

// copy yarn-v2 to tmpdir so node_modules resolution won't fall back to project root
projectDir = path.join(os.tmpdir(), `cy-yarn-v2-pnp-${Date.now()}`)
console.log(`projectDir`, projectDir)

await fs.mkdir(projectDir)
await fs.copy(fixtureDir, projectDir)

const projectExec = (cmd) => exec(cmd, { cwd: projectDir })

await projectExec('yarn')
})

e2e.it('can compile plugin and test specs', {
snapshot: false,
command: 'yarn',
browser: 'electron',
onRun: async (run) => {
await run({
args: `node ${cypressCli} run --dev --project=./`.split(' '),
spawnOpts: {
cwd: projectDir,
shell: true,
},
})
},
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.yarn
.pnp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yarnPath: "./yarn-berry.cjs"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as head from 'lodash/head'

describe('yarn-v2-pnp', () => {
it('can load package from pnp runtime', () => {
expect(head([1, 2, 3])).to.equal(1)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as head from 'lodash/head'

// Default Cypress plugin function
export default (on, config) => {
// make sure plugin can access dependencies
head([1, 2, 3])

return config
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "yarn-v2-pnp",
"version": "1.0.0",
"dependencies": {
"lodash": "^4.17.21"
},
"devDependencies": {
"typescript": "^4.2.4"
},
"license": "MIT"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"allowJs": true,
"moduleResolution": "node"
},
"include": ["**/*.ts"]
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!

__metadata:
version: 4
cacheKey: 7

"lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: 4983720b9abca930a4a46f18db163d7dad8dd00dbed6db0cc7b499b33b717cce69f80928b27bbb1ff2cbd3b19d251ee90669a8b5ea466072ca81c2ebe91e7468
languageName: node
linkType: hard

typescript@^4.2.4:
version: 4.3.5
resolution: "typescript@npm:4.3.5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: d9a8e78d72dd19896e6bfa73ab2a0fcea6eca2700d1d6e7c33f67a970af54a3e0fed8f715a8c4e6a0ff7fc0995067b394b2003518ab0aa84cd396377e54b760c
languageName: node
linkType: hard

"typescript@patch:typescript@^4.2.4#builtin<compat/typescript>":
version: 4.3.5
resolution: "typescript@patch:typescript@npm%3A4.3.5#builtin<compat/typescript>::version=4.3.5&hash=ddfc1b"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 7f0b8343f71ecac18095be1476b398aca420ab60dc207cc1efe078f381eef5527b80a518297720257114cdbda65612f8839e4b63e85dc95e67ac5cbbade8bdf0
languageName: node
linkType: hard

"yarn-v2-pnp@workspace:.":
version: 0.0.0-use.local
resolution: "yarn-v2-pnp@workspace:."
dependencies:
lodash: ^4.17.21
typescript: ^4.2.4
languageName: unknown
linkType: soft
6 changes: 4 additions & 2 deletions packages/server/test/support/helpers/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ const e2e = {
Fixtures.installStubPackage(options.project, options.stubPackage)
}

args = ['index.js'].concat(args)
args = options.args || ['index.js'].concat(args)

let stdout = ''
let stderr = ''
Expand Down Expand Up @@ -763,7 +763,8 @@ const e2e = {

return new Bluebird((resolve, reject) => {
debug('spawning Cypress %o', { args })
const sp = cp.spawn('node', args, {
const cmd = options.command || 'node'
const sp = cp.spawn(cmd, args, {
env: _.chain(process.env)
.omit('CYPRESS_DEBUG')
.extend({
Expand Down Expand Up @@ -792,6 +793,7 @@ const e2e = {
})
.extend(options.processEnv)
.value(),
...options.spawnOpts,
})

const ColorOutput = function () {
Expand Down
30 changes: 28 additions & 2 deletions packages/server/test/unit/plugins/index_spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require('../../spec_helper')

const _ = require('lodash')
const mockedEnv = require('mocked-env')
const cp = require('child_process')

const util = require(`${root}../lib/plugins/util`)
Expand Down Expand Up @@ -94,7 +96,7 @@ describe('lib/plugins/index', () => {
execPath: systemNode,
}

expect(cp.fork.lastCall.args[2]).to.eql(options)
expect(_.omit(cp.fork.lastCall.args[2], 'env')).to.eql(options)
})
})

Expand All @@ -112,7 +114,7 @@ describe('lib/plugins/index', () => {
stdio: 'pipe',
}

expect(cp.fork.lastCall.args[2]).to.eql(options)
expect(_.omit(cp.fork.lastCall.args[2], 'env')).to.eql(options)
})
})

Expand Down Expand Up @@ -309,6 +311,30 @@ describe('lib/plugins/index', () => {
})
})
})

describe('restore node options', () => {
let restoreEnv

afterEach(() => {
if (restoreEnv) {
restoreEnv()
restoreEnv = null
}
})

it('restore NODE_OPTIONS', () => {
restoreEnv = mockedEnv({
ORIGINAL_NODE_OPTIONS: '--require foo.js',
})

ipc.on.withArgs('loaded').yields([])

return plugins.init({ pluginsFile: 'cypress-plugin' }, getOptions())
.then(() => {
expect(cp.fork.lastCall.args[2].env.NODE_OPTIONS).to.eql('--require foo.js')
})
})
})
})

context('#register', () => {
Expand Down
Loading