Skip to content

Commit 74531f0

Browse files
committed
feat: allow for @cypress/webpack-batteries-included-preprocessor to fully resolve the user tsconfig compiler options
throw an error if typescript is installed, but a tsconfig.json cannot be found empty commit to run ci
1 parent 8b8230b commit 74531f0

File tree

13 files changed

+231
-16
lines changed

13 files changed

+231
-16
lines changed

.circleci/workflows.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ mainBuildFilters: &mainBuildFilters
3838
- /^release\/\d+\.\d+\.\d+$/
3939
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
4040
- 'update-v8-snapshot-cache-on-develop'
41-
- 'remove-migration'
41+
- 'feat/wbip_full_resolve_ts_config'
4242

4343
# usually we don't build Mac app - it takes a long time
4444
# but sometimes we want to really confirm we are doing the right thing
@@ -49,7 +49,7 @@ macWorkflowFilters: &darwin-workflow-filters
4949
- equal: [ develop, << pipeline.git.branch >> ]
5050
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
5151
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
52-
- equal: [ 'remove-migration', << pipeline.git.branch >> ]
52+
- equal: [ 'feat/wbip_full_resolve_ts_config', << pipeline.git.branch >> ]
5353
- matches:
5454
pattern: /^release\/\d+\.\d+\.\d+$/
5555
value: << pipeline.git.branch >>
@@ -60,7 +60,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
6060
- equal: [ develop, << pipeline.git.branch >> ]
6161
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
6262
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
63-
- equal: [ 'remove-migration', << pipeline.git.branch >> ]
63+
- equal: [ 'feat/wbip_full_resolve_ts_config', << pipeline.git.branch >> ]
6464
- matches:
6565
pattern: /^release\/\d+\.\d+\.\d+$/
6666
value: << pipeline.git.branch >>
@@ -83,7 +83,7 @@ windowsWorkflowFilters: &windows-workflow-filters
8383
- equal: [ develop, << pipeline.git.branch >> ]
8484
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
8585
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
86-
- equal: [ 'remove-migration', << pipeline.git.branch >> ]
86+
- equal: [ 'feat/wbip_full_resolve_ts_config', << pipeline.git.branch >> ]
8787
- matches:
8888
pattern: /^release\/\d+\.\d+\.\d+$/
8989
value: << pipeline.git.branch >>
@@ -157,7 +157,7 @@ commands:
157157
name: Set environment variable to determine whether or not to persist artifacts
158158
command: |
159159
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
160-
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "remove-migration" ]]; then
160+
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feat/wbip_full_resolve_ts_config" ]]; then
161161
export SHOULD_PERSIST_ARTIFACTS=true
162162
fi' >> "$BASH_ENV"
163163
# You must run `setup_should_persist_artifacts` command and be using bash before running this command

npm/vite-dev-server/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"resolveJsonModule": true,
55
"target": "ES2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */,
66
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
7+
"moduleResolution": "node",
78
"lib": [
89
"es2015",
910
"dom"

npm/webpack-batteries-included-preprocessor/index.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
const path = require('path')
22
const Debug = require('debug')
3+
const getTsConfig = require('get-tsconfig')
34
const webpackPreprocessor = require('@cypress/webpack-preprocessor')
45
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
56

67
const debug = Debug('cypress:webpack-batteries-included-preprocessor')
78
const WBADebugNamespace = 'cypress-verbose:webpack-batteries-included-preprocessor:bundle-analyzer'
89

10+
class TsConfigNotFoundError extends Error {
11+
constructor () {
12+
super('No tsconfig.json found, but typescript is installed. ts-loader needs a tsconfig.json file to work. Please add one to your project in either the root or the cypress directory.')
13+
this.name = 'TsConfigNotFoundError'
14+
}
15+
}
16+
917
const hasTsLoader = (rules) => {
1018
return rules.some((rule) => {
1119
if (!rule.use || !Array.isArray(rule.use)) return false
@@ -17,6 +25,17 @@ const hasTsLoader = (rules) => {
1725
}
1826

1927
const addTypeScriptConfig = (file, options) => {
28+
// returns null if tsconfig cannot be found in the path/parent hierarchy
29+
const configFile = getTsConfig.getTsconfig(file.filePath)
30+
31+
if (!configFile && typescriptExtensionRegex.test(file.filePath)) {
32+
debug('no user tsconfig.json found. Throwing TsConfigNotFoundError')
33+
// @see https://github.com/cypress-io/cypress/issues/18938
34+
throw new TsConfigNotFoundError()
35+
}
36+
37+
debug(`found user tsconfig.json at ${configFile?.path} with compilerOptions: ${JSON.stringify(configFile?.config?.compilerOptions)}`)
38+
2039
// shortcut if we know we've already added typescript support
2140
if (options.__typescriptSupportAdded) return options
2241

@@ -36,13 +55,6 @@ const addTypeScriptConfig = (file, options) => {
3655
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
3756
// node will try to load a projects tsconfig.json instead of the node
3857

39-
const getTsConfig = require('get-tsconfig')
40-
41-
// returns null if tsconfig cannot be found in the path/parent hierarchy
42-
const configFile = getTsConfig.getTsconfig(file.filePath)
43-
44-
configFile ? debug(`found user tsconfig.json at ${configFile?.path} with compilerOptions: ${JSON.stringify(configFile?.config?.compilerOptions)}`) : debug('no user tsconfig.json found')
45-
4658
webpackOptions.module.rules.push({
4759
test: /\.tsx?$/,
4860
exclude: [/node_modules/],
@@ -51,6 +63,10 @@ const addTypeScriptConfig = (file, options) => {
5163
loader: require.resolve('ts-loader'),
5264
options: {
5365
compiler: options.typescript,
66+
// pass in the resolved compiler options from the tsconfig file into ts-loader to most accurately transpile the code
67+
...(configFile ? {
68+
compilerOptions: configFile.config.compilerOptions,
69+
} : {}),
5470
logLevel: 'error',
5571
silent: true,
5672
transpileOnly: true,

npm/webpack-batteries-included-preprocessor/test/unit/index.spec.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,16 @@ describe('webpack-batteries-included-preprocessor', () => {
8282
mock.stop('@cypress/webpack-preprocessor')
8383
})
8484

85-
it('always returns loader options even if there is an error discovering the user\'s tsconfig.json', () => {
86-
getTsConfigMock.returns(null)
85+
it('correctly passes the options in the user\'s tsconfig.json options into ts-loader', () => {
86+
getTsConfigMock.returns({
87+
config: {
88+
compilerOptions: {
89+
module: 'ESNext',
90+
moduleResolution: 'Bundler',
91+
},
92+
path: '/foo/tsconfig.json',
93+
},
94+
})
8795

8896
const preprocessorCB = preprocessor({
8997
typescript: true,
@@ -104,8 +112,28 @@ describe('webpack-batteries-included-preprocessor', () => {
104112
expect(tsLoader.options.silent).to.be.true
105113
expect(tsLoader.options.transpileOnly).to.be.true
106114

107-
// compilerOptions are set by `@cypress/webpack-preprocessor` if ts-loader is present
108-
expect(tsLoader.options.compilerOptions).to.be.undefined
115+
// compilerOptions are overridden (sourceMap=true) by `@cypress/webpack-preprocessor` if ts-loader is present
116+
expect(tsLoader.options.compilerOptions).to.deep.equal({
117+
module: 'ESNext',
118+
moduleResolution: 'Bundler',
119+
})
120+
})
121+
122+
// @see https://github.com/cypress-io/cypress/issues/18938. ts-loader needs a tsconfig.json file to work.
123+
it('throws an error if the user\'s tsconfig.json is not found', () => {
124+
getTsConfigMock.returns(null)
125+
126+
const preprocessorCB = preprocessor({
127+
typescript: true,
128+
webpackOptions,
129+
})
130+
131+
expect(() => {
132+
return preprocessorCB({
133+
filePath: 'foo.ts',
134+
outputPath: '.js',
135+
})
136+
}).to.throw('No tsconfig.json found, but typescript is installed. ts-loader needs a tsconfig.json file to work. Please add one to your project in either the root or the cypress directory.')
109137
})
110138
})
111139
})

npm/webpack-dev-server/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"resolveJsonModule": true,
55
"target": "ES2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */,
66
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
7+
"moduleResolution": "node",
78
"lib": [
89
"es2015",
910
"dom"
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
exports['e2e no tsconfig ts js mix / fails with no tsconfig.json error'] = `
2+
3+
====================================================================================================
4+
5+
(Run Starting)
6+
7+
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
8+
│ Cypress: 1.2.3 │
9+
│ Browser: FooBrowser 88 │
10+
│ Specs: 1 found (spec.cy.ts) │
11+
│ Searched: cypress/e2e/spec.cy.ts │
12+
└────────────────────────────────────────────────────────────────────────────────────────────────┘
13+
14+
15+
────────────────────────────────────────────────────────────────────────────────────────────────────
16+
17+
Running: spec.cy.ts (1 of 1)
18+
19+
Oops...we found an error preparing this test file:
20+
21+
> cypress/e2e/spec.cy.ts
22+
23+
The error was:
24+
25+
TsConfigNotFoundError: No tsconfig.json found, but typescript is installed. ts-loader needs a tsconfig.json file to work. Please add one to your project in either the root or the cypress directory.
26+
[stack trace lines]
27+
28+
This occurred while Cypress was compiling and bundling your test code. This is usually caused by:
29+
30+
- A missing file or dependency
31+
- A syntax error in the file or one of its dependencies
32+
33+
Fix the error in your code and re-run your tests.
34+
35+
(Results)
36+
37+
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
38+
│ Tests: 0 │
39+
│ Passing: 0 │
40+
│ Failing: 1 │
41+
│ Pending: 0 │
42+
│ Skipped: 0 │
43+
│ Screenshots: 0 │
44+
│ Video: false │
45+
│ Duration: X seconds │
46+
│ Spec Ran: spec.cy.ts │
47+
└────────────────────────────────────────────────────────────────────────────────────────────────┘
48+
49+
50+
====================================================================================================
51+
52+
(Run Finished)
53+
54+
55+
Spec Tests Passing Failing Pending Skipped
56+
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
57+
│ ✖ spec.cy.ts XX:XX - - 1 - - │
58+
└────────────────────────────────────────────────────────────────────────────────────────────────┘
59+
✖ 1 of 1 failed (100%) XX:XX - - 1 - -
60+
61+
62+
`
63+
64+
exports['e2e no tsconfig ts js mix / passes'] = `
65+
66+
====================================================================================================
67+
68+
(Run Starting)
69+
70+
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
71+
│ Cypress: 1.2.3 │
72+
│ Browser: FooBrowser 88 │
73+
│ Specs: 1 found (spec.cy.js) │
74+
│ Searched: cypress/e2e/spec.cy.js │
75+
└────────────────────────────────────────────────────────────────────────────────────────────────┘
76+
77+
78+
────────────────────────────────────────────────────────────────────────────────────────────────────
79+
80+
Running: spec.cy.js (1 of 1)
81+
82+
83+
✓ is true
84+
85+
1 passing
86+
87+
88+
(Results)
89+
90+
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
91+
│ Tests: 1 │
92+
│ Passing: 1 │
93+
│ Failing: 0 │
94+
│ Pending: 0 │
95+
│ Skipped: 0 │
96+
│ Screenshots: 0 │
97+
│ Video: false │
98+
│ Duration: X seconds │
99+
│ Spec Ran: spec.cy.js │
100+
└────────────────────────────────────────────────────────────────────────────────────────────────┘
101+
102+
103+
====================================================================================================
104+
105+
(Run Finished)
106+
107+
108+
Spec Tests Passing Failing Pending Skipped
109+
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
110+
│ ✔ spec.cy.js XX:XX 1 1 - - - │
111+
└────────────────────────────────────────────────────────────────────────────────────────────────┘
112+
✔ All specs passed! XX:XX 1 1 - - -
113+
114+
115+
`
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
e2e: {
3+
setupNodeEvents (on, config) {
4+
return config
5+
},
6+
},
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
it('is true', () => {
2+
expect(true).to.be.true
3+
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
it('is true', () => {
2+
expect(true).to.be.true
3+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// intentionally left empty
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "no-tsconfig-ts-js-mix",
3+
"version": "0.0.0-test",
4+
"devDependencies": {
5+
"typescript": "^5.6.0"
6+
}
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
typescript@^5.6.0:
6+
version "5.8.3"
7+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
8+
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import systemTests from '../lib/system-tests'
2+
3+
describe('e2e no tsconfig ts js mix', () => {
4+
systemTests.setup()
5+
6+
systemTests.it('passes', {
7+
spec: 'spec.cy.js',
8+
browser: 'chrome',
9+
project: 'no-tsconfig-ts-js-mix',
10+
snapshot: true,
11+
})
12+
13+
systemTests.it('fails with no tsconfig.json error', {
14+
spec: 'spec.cy.ts',
15+
browser: 'chrome',
16+
project: 'no-tsconfig-ts-js-mix',
17+
snapshot: true,
18+
expectedExitCode: 1,
19+
async onRun (exec, browserName) {
20+
const { stdout } = await exec()
21+
22+
expect(stdout).to.include('TsConfigNotFoundError: No tsconfig.json found, but typescript is installed. ts-loader needs a tsconfig.json file to work. Please add one to your project in either the root or the cypress directory.')
23+
},
24+
})
25+
})

0 commit comments

Comments
 (0)