fix: Remove default esModuleInterop option from ts-node and preprocessor (#8143)

* make tests preprocessor agnostic

* update eslintignore

* put back deps needed for e2e test

* remove obselete snapshot

it was replaced by 1_typescript_support_spec.ts.js

* switch from browserify to webpack preprocessor

* cmon github

* fix/update tests

* bump preprocessor and update snapshots

* update snapshots

* bump preprocessor to gain json support

* fix e2e tests with webpack-originated errors

* bump preprocessor version, fix node globals

* update snapshot

* remove support for ? in file path

* bump preprocessor version

* bump preprocessor again

* bump preprocessor

* bump preprocessor

* update snapshots

* bump preprocessor version

* bump preprocessor, quiet the paths plugin

* add test verifying tsconfig paths work

* refactor registering ts-node

* separate spec/support file typescript tests from plugins file typescript tests

* fix unit tests

* fix: Remove esModuleInterop default from ts-node (#7808)

* Remove esModuleInterop from ts-node.

* Add e2e test.

* Fix test.
Change test name.
Add comment.

* Fix test snapshot name.

* update snapshotting

Co-authored-by: Chris Breiding <chrisbreiding@gmail.com>

* clean up e2e project

* bump preprocessor to 1.3.2, which removes esModuleInterop default value

* improve esmoduleinterop e2e tests

* change spec file

* bump batteries-included preprocessor and install latest webpack preprocessor beside it

* update snapshots

* put back snapshot

* update snapshot

* update snapshot

Co-authored-by: Kukhyeon Heo <sainthkh@naver.com>
Co-authored-by: Brian Mann <brian.mann86@gmail.com>
This commit is contained in:
Chris Breiding
2020-08-10 18:18:30 -04:00
committed by GitHub
parent 474bcddbd3
commit daeab10e46
32 changed files with 129 additions and 194 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ packages/server/lib/scaffold/plugins/index.js
packages/server/lib/scaffold/support/index.js
packages/server/lib/scaffold/support/commands.js
packages/server/test/support/fixtures/projects/e2e/cypress/integration/stdout_exit_early_failing_spec.js
packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_failing_spec.ts
packages/server/test/support/fixtures/projects/e2e/cypress/integration/typescript_syntax_error_spec.ts
**/.projects
**/*.d.ts
@@ -1,4 +1,4 @@
exports['e2e typescript spec passes 1'] = `
exports['e2e typescript in spec and support file spec passes 1'] = `
====================================================================================================
@@ -62,7 +62,7 @@ exports['e2e typescript spec passes 1'] = `
`
exports['e2e typescript spec fails 1'] = `
exports['e2e typescript in spec and support file spec fails with syntax error 1'] = `
====================================================================================================
@@ -71,23 +71,23 @@ exports['e2e typescript spec fails 1'] = `
Cypress: 1.2.3
Browser: FooBrowser 88
Specs: 1 found (typescript_failing_spec.ts)
Searched: cypress/integration/typescript_failing_spec.ts
Specs: 1 found (typescript_syntax_error_spec.ts)
Searched: cypress/integration/typescript_syntax_error_spec.ts
Running: typescript_failing_spec.ts (1 of 1)
Running: typescript_syntax_error_spec.ts (1 of 1)
Oops...we found an error preparing this test file:
/foo/bar/.projects/e2e/cypress/integration/typescript_failing_spec.ts
/foo/bar/.projects/e2e/cypress/integration/typescript_syntax_error_spec.ts
The error was:
Error: Webpack Compilation Error
./cypress/integration/typescript_failing_spec.tsXX:XX
./cypress/integration/typescript_syntax_error_spec.tsXX:XX
Module parse failed: Unexpected token (4:19)
File was processed with these loaders:
* ../../../../node_modules/@cypress/webpack-batteries-included-preprocessor/node_modules/ts-loader/index.js
@@ -115,14 +115,15 @@ Fix the error in your code and re-run your tests.
Screenshots: 0
Video: true
Duration: X seconds
Spec Ran: typescript_failing_spec.ts
Spec Ran: typescript_syntax_error_spec.ts
(Video)
- Started processing: Compressing to 32 CRF
- Finished processing: /XXX/XXX/XXX/cypress/videos/typescript_failing_spec.ts.mp4 (X second)
- Finished processing: /XXX/XXX/XXX/cypress/videos/typescript_syntax_error_spec.ts (X second)
.mp4
====================================================================================================
@@ -132,14 +133,14 @@ Fix the error in your code and re-run your tests.
Spec Tests Passing Failing Pending Skipped
typescript_failing_spec.ts XX:XX - - 1 - -
typescript_syntax_error_spec.ts XX:XX - - 1 - -
1 of 1 failed (100%) XX:XX - - 1 - -
`
exports['e2e typescript project passes 1'] = `
exports['e2e typescript in spec and support file project passes 1'] = `
====================================================================================================
@@ -227,20 +228,3 @@ exports['e2e typescript project passes 1'] = `
`
exports['typescript with tsconfig run'] = `
(Run Finished)
Spec Tests Passing Failing Pending Skipped
app_spec.ts XX:XX 1 1 - - -
js-spec.js XX:XX 2 2 - - -
math.ts XX:XX - - - - -
All specs passed! XX:XX 3 3 - - -
`
@@ -4,15 +4,13 @@
const _ = require('lodash')
const debug = require('debug')('cypress:server:plugins:child')
const Promise = require('bluebird')
const tsnode = require('ts-node')
const resolve = require('resolve')
const errors = require('../../errors')
const preprocessor = require('./preprocessor')
const task = require('./task')
const util = require('../util')
const validateEvent = require('./validate_event')
const tsNodeOptions = require('../../util/ts-node-options')
const { registerTsNode } = require('../../util/ts-node')
const ARRAY_METHODS = ['concat', 'push', 'unshift', 'slice', 'pop', 'shift', 'slice', 'splice', 'filter', 'map', 'forEach', 'reduce', 'reverse', 'splice', 'includes']
@@ -183,21 +181,7 @@ module.exports = (ipc, pluginsFile, projectRoot) => {
})
if (!tsRegistered) {
try {
const tsPath = resolve.sync('typescript', {
basedir: projectRoot,
})
const tsOptions = tsNodeOptions.getTsNodeOptions(tsPath)
debug('typescript path: %s', tsPath)
debug('registering plugins TS with options %o', tsOptions)
tsnode.register(tsOptions)
} catch (e) {
debug(`typescript doesn't exist. ts-node setup failed.`)
debug('error message: %s', e.message)
}
registerTsNode(projectRoot)
// ensure typescript is only registered once
tsRegistered = true
+2 -18
View File
@@ -6,8 +6,6 @@ const Promise = require('bluebird')
const commitInfo = require('@cypress/commit-info')
const la = require('lazy-ass')
const check = require('check-more-types')
const tsnode = require('ts-node')
const resolve = require('resolve')
const scaffoldDebug = require('debug')('cypress:server:scaffold')
const debug = require('debug')('cypress:server:project')
const cwd = require('./cwd')
@@ -31,7 +29,7 @@ const keys = require('./util/keys')
const settings = require('./util/settings')
const specsUtil = require('./util/specs')
const { escapeFilenameInUrl } = require('./util/escape_filename')
const tsNodeOptions = require('./util/ts-node-options')
const { registerTsNode } = require('./util/ts-node')
const localCwd = cwd()
@@ -103,21 +101,7 @@ class Project extends EE {
return scaffold.plugins(path.dirname(cfg.pluginsFile), cfg)
}
}).then((cfg) => {
try {
const tsPath = resolve.sync('typescript', {
basedir: this.projectRoot,
})
const tsOptions = tsNodeOptions.getTsNodeOptions(tsPath)
debug('typescript path: %s', tsPath)
debug('registering project TS with options %o', tsOptions)
tsnode.register(tsOptions)
} catch (e) {
debug(`typescript doesn't exist. ts-node setup failed.`)
debug('error message %s', e.message)
}
registerTsNode(this.projectRoot)
return cfg
}).then((cfg) => {
@@ -1,29 +0,0 @@
// returns options for ts-node registration
// https://github.com/TypeStrong/ts-node
const _ = require('lodash')
/**
* Default ts - node options.We want to output CommonJS modules.
* And we want to run fast - thus transpile only mode (no type checking)
*/
const tsOptions = {
transpileOnly: true,
compilerOptions: {
module: 'CommonJS',
esModuleInterop: true,
},
}
/**
* Returns combined object with ts-node options.
* @param {string} tsPath Path to TypeScript
*/
function getTsNodeOptions (tsPath) {
const merged = _.cloneDeep(tsOptions)
merged.compiler = tsPath
return merged
}
module.exports = { getTsNodeOptions }
+34
View File
@@ -0,0 +1,34 @@
const debug = require('debug')('cypress:server:ts-node')
const tsnode = require('ts-node')
const resolve = require('resolve')
const getTsNodeOptions = (tsPath) => {
return {
compiler: tsPath, // use the user's installed typescript
compilerOptions: {
module: 'CommonJS',
},
transpileOnly: true, // transpile only (no type-check) for speed
}
}
const registerTsNode = (projectRoot) => {
try {
const tsPath = resolve.sync('typescript', {
basedir: projectRoot,
})
const tsOptions = getTsNodeOptions(tsPath)
debug('typescript path: %s', tsPath)
debug('registering project TS with options %o', tsOptions)
tsnode.register(tsOptions)
} catch (err) {
debug(`typescript doesn't exist. ts-node setup failed.`)
debug('error message: %s', err.message)
}
}
module.exports = {
registerTsNode,
}
@@ -0,0 +1,26 @@
import e2e from '../support/helpers/e2e'
import Fixtures from '../support/helpers/fixtures'
describe('e2e typescript in plugins file', function () {
e2e.setup()
it('handles tsconfig with module other than commonjs', function () {
return e2e.exec(this, {
project: Fixtures.projectPath('ts-proj-with-module-esnext'),
})
})
// https://github.com/cypress-io/cypress/issues/7575
it('defaults to esModuleInterop: false', function () {
return e2e.exec(this, {
project: Fixtures.projectPath('ts-proj'),
})
})
// https://github.com/cypress-io/cypress/issues/7575
it('allows esModuleInterop to be overridden with true via tsconfig.json', function () {
return e2e.exec(this, {
project: Fixtures.projectPath('ts-proj-esmoduleinterop-true'),
})
})
})
@@ -1,9 +1,7 @@
import snapshot from 'snap-shot-it'
import e2e from '../support/helpers/e2e'
import Fixtures from '../support/helpers/fixtures'
describe('e2e typescript', function () {
describe('e2e typescript in spec and support file', function () {
e2e.setup()
it('spec passes', function () {
@@ -13,9 +11,9 @@ describe('e2e typescript', function () {
})
})
it('spec fails', function () {
it('spec fails with syntax error', function () {
return e2e.exec(this, {
spec: 'typescript_failing_spec.ts',
spec: 'typescript_syntax_error_spec.ts',
snapshot: true,
expectedExitCode: 1,
onStdout: e2e.normalizeWebpackErrors,
@@ -36,19 +34,4 @@ describe('e2e typescript', function () {
project: Fixtures.projectPath('ts-proj-with-paths'),
})
})
it('handles tsconfig with module other than commonjs', function () {
const projPath = Fixtures.projectPath('ts-proj-with-own-tsconfig')
return e2e.exec(this, {
project: projPath,
config: {
video: false,
},
}).then((result) => {
const runSummary = e2e.leaveRunFinishedTable(e2e.normalizeStdout(result.stdout))
snapshot('typescript with tsconfig run', runSummary)
})
})
})
@@ -0,0 +1,3 @@
{
"supportFile": false
}
@@ -0,0 +1,3 @@
it('passes', () => {
expect(true).to.be.true
})
@@ -0,0 +1,3 @@
exports.export1 = 'export1'
exports.export2 = 'export2'
@@ -0,0 +1,12 @@
/// <reference types="cypress" />
import commonjsExports from './commonjs-export'
if (commonjsExports.export1 !== 'export1' || commonjsExports.export2 !== 'export2') {
throw new Error('Imported values do not match exported values')
}
// Default Cypress plugin function
export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => {
}
@@ -0,0 +1,5 @@
{
"compilerOptions": {
"esModuleInterop": true
}
}
@@ -0,0 +1,3 @@
{
"supportFolder": false
}
@@ -0,0 +1,5 @@
describe('uses task that is in typescript plugins file', () => {
it('calls task', () => {
cy.task('hello', 'TS').should('equal', 'Hello, TS!')
})
})
@@ -0,0 +1,3 @@
export const asyncGreeting = async (greeting: string) => {
return Promise.resolve(`Hello, ${greeting}!`)
}
@@ -1,5 +0,0 @@
import { add } from './math'
it('is true', () => {
expect(add(1, 2)).to.eq(3)
})
@@ -1,11 +0,0 @@
import { add } from './math'
describe('JS spec', () => {
it('adds 2 and 2 together', () => {
expect(add(2, 2)).to.equal(4)
})
it('calls task', () => {
cy.task('hello', 'TS').should('equal', 'Hello, TS!')
})
})
@@ -1,3 +0,0 @@
export const add = (a: number, b: number) => {
return a + b
}
@@ -1,3 +0,0 @@
export const asyncGreeting = async (greeting) => {
return Promise.resolve(`Hello, ${greeting}!`)
}
@@ -1,9 +0,0 @@
{
"parserOptions": {
"parser": "@typescript-eslint/parser",
"project": "packages/server/test/support/fixtures/projects/ts-proj-with-own-tsconfig/tsconfig.json"
},
"rules": {
"@typescript-eslint/no-misused-promises": "error"
}
}
@@ -1,13 +0,0 @@
/// <reference types="cypress" />
// Copied an example command from https://on.cypress.io/custom-commands
Cypress.Commands.add('clickLink', (label: string | number | RegExp) => {
cy.get('a').contains(label).click()
})
// https://github.com/cypress-io/cypress/issues/7510
// The code below fails when @typescript-eslint/no-misused-promises is error
// and the return type of function in Cypress.Commands.add doesn't support Chainable.
Cypress.Commands.add('dataCy', (value) => {
return cy.get(`[data-cy=${value}]`)
})
@@ -1,20 +0,0 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')
@@ -1,5 +1,6 @@
import { add } from './math'
it('is true', () => {
// @ts-ignore
expect(add(1, 2)).to.eq(3)
})
@@ -0,0 +1 @@
module.exports = () => {}
@@ -1,17 +1,13 @@
// Copied an example from https://docs.cypress.io/api/plugins/browser-launch-api.html#Use-fake-video-for-webcam-testing
/// <reference types="cypress" />
import 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
// of esModuleInterop
fn()
// Default Cypress plugin function
export default (on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) => {
on('before:browser:launch', (browser, launchOptions) => {
if (browser.family === 'chromium' && browser.name !== 'electron') {
// Mac/Linux
//launchOptions.args.push('--use-file-for-fake-video-capture=cypress/fixtures/my-video.y4m')
// Windows
// launchOptions.args.push('--use-file-for-fake-video-capture=c:\\path\\to\\video\\my-video.y4m')
}
return launchOptions
})
}
+2 -2
View File
@@ -1856,7 +1856,7 @@ describe('lib/config', () => {
})
it('sets the pluginsFile to index.ts if it exists', () => {
const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj')
const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj-with-module-esnext')
const obj = {
projectRoot,
@@ -1873,7 +1873,7 @@ describe('lib/config', () => {
})
it('sets the pluginsFile to index.ts if it exists (without ts require hook)', () => {
const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj')
const projectRoot = path.join(process.cwd(), 'test/support/fixtures/projects/ts-proj-with-module-esnext')
const pluginsFolder = `${projectRoot}/cypress/plugins`
const pluginsFilename = `${pluginsFolder}/index.ts`
@@ -354,7 +354,6 @@ This option will not have an effect in Some-other-name. Tests that rely on web s
compiler: projTsPath,
compilerOptions: {
module: 'CommonJS',
esModuleInterop: true,
},
})
})