Skip to content

Commit

Permalink
fix: Resolve tsconfig.json for plugins file from the plugins directory (
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbreiding authored Aug 24, 2020
1 parent 96c8747 commit 383fa22
Show file tree
Hide file tree
Showing 15 changed files with 95 additions and 82 deletions.
11 changes: 9 additions & 2 deletions packages/server/lib/plugins/child/run_plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const execute = (ipc, event, ids, args = []) => {

let tsRegistered = false

module.exports = (ipc, pluginsFile, projectRoot) => {
const runPlugins = (ipc, pluginsFile, projectRoot) => {
debug('pluginsFile:', pluginsFile)
debug('project root:', projectRoot)
if (!projectRoot) {
Expand All @@ -181,7 +181,7 @@ module.exports = (ipc, pluginsFile, projectRoot) => {
})

if (!tsRegistered) {
registerTsNode(projectRoot)
registerTsNode(projectRoot, pluginsFile)

// ensure typescript is only registered once
tsRegistered = true
Expand Down Expand Up @@ -219,3 +219,10 @@ module.exports = (ipc, pluginsFile, projectRoot) => {
execute(ipc, event, ids, args)
})
}

// for testing purposes
runPlugins.__reset = () => {
tsRegistered = false
}

module.exports = runPlugins
5 changes: 2 additions & 3 deletions packages/server/lib/plugins/preprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const debug = require('debug')('cypress:server:preprocessor')
const Promise = require('bluebird')
const appData = require('../util/app_data')
const plugins = require('../plugins')
const resolve = require('./resolve')
const resolve = require('../util/resolve')

const errorMessage = function (err = {}) {
return (err.stack || err.annotated || err.message || err.toString())
Expand Down Expand Up @@ -46,8 +46,7 @@ const createPreprocessor = function (options) {
const setDefaultPreprocessor = function (config) {
debug('set default preprocessor')

const tsPath = resolve.typescript(config)

const tsPath = resolve.typescript(config.projectRoot)
const options = {
typescript: tsPath,
}
Expand Down
5 changes: 0 additions & 5 deletions packages/server/lib/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const keys = require('./util/keys')
const settings = require('./util/settings')
const specsUtil = require('./util/specs')
const { escapeFilenameInUrl } = require('./util/escape_filename')
const { registerTsNode } = require('./util/ts-node')

const localCwd = cwd()

Expand Down Expand Up @@ -100,10 +99,6 @@ class Project extends EE {

return scaffold.plugins(path.dirname(cfg.pluginsFile), cfg)
}
}).then((cfg) => {
registerTsNode(this.projectRoot)

return cfg
}).then((cfg) => {
return this._initPlugins(cfg, options)
.then((modifiedCfg) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
const resolve = require('resolve')
const env = require('../util/env')
const env = require('./env')
const debug = require('debug')('cypress:server:plugins')

module.exports = {
/**
* Resolves the path to 'typescript' module.
*
* @param {Config} cypress config object
* @param {projectRoot} path to the project root
* @returns {string|null} path if typescript exists, otherwise null
*/
typescript: (config) => {
if (env.get('CYPRESS_INTERNAL_NO_TYPESCRIPT') === '1') {
typescript: (projectRoot) => {
if (env.get('CYPRESS_INTERNAL_NO_TYPESCRIPT') === '1' || !projectRoot) {
return null
}

try {
const options = {
basedir: config.projectRoot,
}

if (!config.projectRoot) {
throw new Error('Config is missing projet root')
basedir: projectRoot,
}

debug('resolving typescript with options %o', options)
Expand Down
19 changes: 12 additions & 7 deletions packages/server/lib/util/ts-node.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
const debug = require('debug')('cypress:server:ts-node')
const path = require('path')
const tsnode = require('ts-node')
const resolve = require('resolve')
const resolve = require('./resolve')

const getTsNodeOptions = (tsPath) => {
const getTsNodeOptions = (tsPath, pluginsFile) => {
return {
compiler: tsPath, // use the user's installed typescript
compilerOptions: {
module: 'CommonJS',
},
// resolves tsconfig.json starting from the plugins directory
// instead of the cwd (the project root)
dir: path.dirname(pluginsFile),
transpileOnly: true, // transpile only (no type-check) for speed
}
}

const registerTsNode = (projectRoot) => {
const registerTsNode = (projectRoot, pluginsFile) => {
try {
const tsPath = resolve.sync('typescript', {
basedir: projectRoot,
})
const tsOptions = getTsNodeOptions(tsPath)
const tsPath = resolve.typescript(projectRoot)

if (!tsPath) return

const tsOptions = getTsNodeOptions(tsPath, pluginsFile)

debug('typescript path: %s', tsPath)
debug('registering project TS with options %o', tsOptions)
Expand Down
7 changes: 7 additions & 0 deletions packages/server/test/e2e/1_typescript_plugins_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,11 @@ describe('e2e typescript in plugins file', function () {
project: Fixtures.projectPath('ts-proj-esmoduleinterop-true'),
})
})

// https://github.com/cypress-io/cypress/issues/8359
it('loads tsconfig.json from plugins directory', function () {
return e2e.exec(this, {
project: Fixtures.projectPath('ts-proj-tsconfig-in-plugins'),
})
})
})
2 changes: 1 addition & 1 deletion packages/server/test/integration/http_requests_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const Project = require(`${root}lib/project`)
const Watchers = require(`${root}lib/watchers`)
const pluginsModule = require(`${root}lib/plugins`)
const preprocessor = require(`${root}lib/plugins/preprocessor`)
const resolve = require(`${root}lib/plugins/resolve`)
const resolve = require(`${root}lib/util/resolve`)
const fs = require(`${root}lib/util/fs`)
const glob = require(`${root}lib/util/glob`)
const CacheBuster = require(`${root}lib/util/cache_buster`)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"supportFile": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
it('passes', () => {
expect(true).to.be.true
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// this tests that the tsconfig.json is loaded from the plugins directory.
// if it isn't, the lack of "downlevelIteration" support will cause this to
// fail at runtime with "RangeError: Invalid array length"
[...Array(100).keys()].map((x) => `${x}`)

export default () => {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"compilerOptions": {
"downlevelIteration": true
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="cypress" />

import fn from './commonjs-export-function'
import * as fn from './commonjs-export-function'

// if esModuleInterop is forced to be true, this will error // with 'fn is
// not a function'. instead, we allow the tsconfig.json to determine the value
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
42 changes: 40 additions & 2 deletions packages/server/test/unit/plugins/child/run_plugins_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ require('../../../spec_helper')

const _ = require('lodash')
const snapshot = require('snap-shot-it')
const tsnode = require('ts-node')

const preprocessor = require(`${root}../../lib/plugins/child/preprocessor`)
const task = require(`${root}../../lib/plugins/child/task`)
const runPlugins = require(`${root}../../lib/plugins/child/run_plugins`)
const util = require(`${root}../../lib/plugins/util`)
const resolve = require(`${root}../../lib/util/resolve`)
const browserUtils = require(`${root}../../lib/browsers/utils`)
const Fixtures = require(`${root}../../test/support/helpers/fixtures`)

Expand All @@ -31,8 +33,7 @@ describe('lib/plugins/child/run_plugins', () => {

afterEach(() => {
mockery.deregisterMock('plugins-file')

return mockery.deregisterSubstitute('plugins-file')
mockery.deregisterSubstitute('plugins-file')
})

it('sends error message if pluginsFile is missing', function () {
Expand Down Expand Up @@ -77,6 +78,43 @@ describe('lib/plugins/child/run_plugins', () => {
return snapshot(JSON.stringify(this.ipc.send.lastCall.args[3]))
})

describe('typescript registration', () => {
beforeEach(function () {
runPlugins.__reset()

this.register = sinon.stub(tsnode, 'register')
sinon.stub(resolve, 'typescript').returns('/path/to/typescript.js')
})

it('registers ts-node if typescript is installed', function () {
runPlugins(this.ipc, '/path/to/plugins/file.js', 'proj-root')

expect(this.register).to.be.calledWith({
transpileOnly: true,
compiler: '/path/to/typescript.js',
dir: '/path/to/plugins',
compilerOptions: {
module: 'CommonJS',
},
})
})

it('only registers ts-node once', function () {
runPlugins(this.ipc, '/path/to/plugins/file.js', 'proj-root')
runPlugins(this.ipc, '/path/to/plugins/file.js', 'proj-root')

expect(this.register).to.be.calledOnce
})

it('does not register ts-node if typescript is not installed', function () {
resolve.typescript.returns(null)

runPlugins(this.ipc, '/path/to/plugins/file.js', 'proj-root')

expect(this.register).not.to.be.called
})
})

describe('on \'load\' message', () => {
it('sends error if pluginsFile function rejects the promise', function (done) {
const err = new Error('foo')
Expand Down
52 changes: 0 additions & 52 deletions packages/server/test/unit/project_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ require('../spec_helper')
const mockedEnv = require('mocked-env')
const path = require('path')
const commitInfo = require('@cypress/commit-info')
const tsnode = require('ts-node')
const Fixtures = require('../support/helpers/fixtures')
const api = require(`${root}lib/api`)
const user = require(`${root}lib/user`)
Expand Down Expand Up @@ -316,57 +315,6 @@ This option will not have an effect in Some-other-name. Tests that rely on web s
expect(config).ok
})
})

describe('out-of-the-box typescript setup', () => {
const tsProjPath = Fixtures.projectPath('ts-installed')
// Root path is used because resolve finds server typescript path when we use a project under `suppert/projects` folder.
const rootPath = path.join(__dirname, '../../../../..')
const projTsPath = path.join(tsProjPath, 'node_modules/typescript/index.js')

let cfg

beforeEach(() => {
return config.get(tsProjPath, {})
.then((c) => {
cfg = c
})
})

const setupProject = (typescript, projectRoot) => {
const proj = new Project(projectRoot)

sinon.stub(proj, 'watchSettingsAndStartWebsockets').resolves()
sinon.stub(proj, 'checkSupportFile').resolves()
sinon.stub(proj, 'scaffold').resolves()
sinon.stub(proj, 'getConfig').resolves({ ...cfg, typescript })

const register = sinon.stub(tsnode, 'register')

return { proj, register }
}

it('ts installed', () => {
const { proj, register } = setupProject('default', tsProjPath)

return proj.open().then(() => {
expect(register).to.be.calledWith({
transpileOnly: true,
compiler: projTsPath,
compilerOptions: {
module: 'CommonJS',
},
})
})
})

it('ts not installed', () => {
const { proj, register } = setupProject('default', rootPath)

return proj.open().then(() => {
expect(register).not.called
})
})
})
})

context('#close', () => {
Expand Down

4 comments on commit 383fa22

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 383fa22 Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/linux-x64/circle-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-430646/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/circle-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-430621/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 383fa22 Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

Instructions are included below, depending on the shell you are using.

In Command Prompt (cmd.exe):

set CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/win32-x64/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

In PowerShell:

$env:CYPRESS_INSTALL_BINARY = https://cdn.cypress.io/beta/binary/5.0.1/win32-x64/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

In Git Bash:

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/win32-x64/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

Using cross-env:

If the above commands do not work for you, you can also try using cross-env:

npm i -g cross-env
cross-env CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/win32-x64/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 383fa22 Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppVeyor has built the win32 ia32 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

Instructions are included below, depending on the shell you are using.

In Command Prompt (cmd.exe):

set CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/win32-ia32/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

In PowerShell:

$env:CYPRESS_INSTALL_BINARY = https://cdn.cypress.io/beta/binary/5.0.1/win32-ia32/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

In Git Bash:

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/win32-ia32/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

Using cross-env:

If the above commands do not work for you, you can also try using cross-env:

npm i -g cross-env
cross-env CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/win32-ia32/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.zip npm install https://cdn.cypress.io/beta/npm/5.0.1/appveyor-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-34828552/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 383fa22 Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

You can install this pre-release platform-specific build using instructions at https://on.cypress.io/installing-cypress#Install-pre-release-version.

You will need to use custom CYPRESS_INSTALL_BINARY url and install Cypress using an url instead of the version.

export CYPRESS_INSTALL_BINARY=https://cdn.cypress.io/beta/binary/5.0.1/darwin-x64/circle-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-430652/cypress.zip
npm install https://cdn.cypress.io/beta/npm/5.0.1/circle-develop-383fa22f10b5805f6970eeaa219bb132f2fec457-430651/cypress.tgz

Please sign in to comment.