Skip to content

Commit f7c9847

Browse files
fix: ts-loader detection (false positive) (#32266)
* fix: ts-loader detection (false positive) * add test for ts-loader incorrectly resolcing and removing typescript 4 tests as support is removed in Cypress 15 * fix regex where ts-loader may be an absolute path * chore: fix regex typo * re-add typescript 4 tests and remove in a separate PR * add changelog entry --------- Co-authored-by: Bill Glesias <[email protected]>
1 parent 3c79d12 commit f7c9847

File tree

4 files changed

+152
-109
lines changed

4 files changed

+152
-109
lines changed

cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ _Released 08/12/2025 (PENDING)_
4141
- Fixed an issue where `.fixture()` calls with a specified encoding would sometimes still attempt to parse the file based on its extension. Files with an explicit encoding are now always treated as raw content. Fixes [#32139](https://github.com/cypress-io/cypress/issues/32139).
4242
- Fixed an issue where `.fixture()` calls with different encoding options would return inconsistent content based on execution order. Fixes [#32138](https://github.com/cypress-io/cypress/issues/32138).
4343
- Fixed an issue where Angular Component Testing was printing extraneous warnings to the console by default. By default, errors only will now print to the console. This can still be overridden by passing in a custom webpack config or setting the `verbose` option inside your `angular.json`. Addresses [#26456](https://github.com/cypress-io/cypress/issues/26456).
44+
- Fixed an issue where `ts-loader` was improperly being detected inside `@cypress/webpack-preprocessor`. Fixes [#32265](https://github.com/cypress-io/cypress/issues/32265).
4445

4546
**Misc:**
4647

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const hasTsLoader = (rules) => {
2222
if (!rule.use || !Array.isArray(rule.use)) return false
2323

2424
return rule.use.some((use) => {
25-
return use.loader && use.loader.includes('ts-loader')
25+
return use.loader && use.loader.match(/(^|[^a-zA-Z])ts-loader([^a-zA-Z]|$)/)
2626
})
2727
})
2828
}

npm/webpack-preprocessor/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const getTsLoaderIfExists = (rules) => {
1515

1616
if (Array.isArray(rule.use)) {
1717
const foundRule = rule.use.find((use) => {
18-
return use.loader && use.loader.includes('ts-loader')
18+
return use.loader && use.loader.match(/(^|[^a-zA-Z])ts-loader([^a-zA-Z]|$)/)
1919
})
2020

2121
/**
@@ -35,7 +35,7 @@ const getTsLoaderIfExists = (rules) => {
3535
return tsLoaderRule
3636
}
3737

38-
if (_.isObject(rule.use) && rule.use.loader && rule.use.loader.includes('ts-loader')) {
38+
if (_.isObject(rule.use) && rule.use.loader && rule.use.loader.match(/(^|[^a-zA-Z])ts-loader([^a-zA-Z]|$)/)) {
3939
/**
4040
* If the rule is found, it will look like this:
4141
* rules: [
@@ -64,7 +64,7 @@ const getTsLoaderIfExists = (rules) => {
6464
* }
6565
* ]
6666
*/
67-
return rule.loader && rule.loader.includes('ts-loader')
67+
return rule.loader && rule.loader.match(/(^|[^a-zA-Z])ts-loader([^a-zA-Z]|$)/)
6868
})
6969

7070
return tsLoaderRule

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

Lines changed: 147 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -387,82 +387,165 @@ describe('webpack preprocessor', function () {
387387
},
388388
]
389389

390+
// @see https://github.com/cypress-io/cypress/issues/32266
391+
it('matches ts-loader explicitly and does not add configuration if not ts-loader', function () {
392+
const options = {
393+
webpackOptions: {
394+
module: {
395+
rules: [
396+
{
397+
test: /\.tsx?$/,
398+
exclude: [/node_modules/],
399+
use: {
400+
loader: 'exports-loader',
401+
options: {},
402+
},
403+
},
404+
],
405+
},
406+
},
407+
}
408+
409+
return this.run(options).then(() => {
410+
expect(webpack).to.be.calledWithMatch({
411+
module: {
412+
rules: [
413+
{
414+
test: /\.tsx?$/,
415+
exclude: [/node_modules/],
416+
use: {
417+
loader: 'exports-loader',
418+
options: {},
419+
},
420+
},
421+
],
422+
},
423+
})
424+
})
425+
})
426+
427+
// eslint-disable-next-line quotes
428+
const TS_LOADER_NAMES = ['ts-loader', "ts-loader", 'foo/ts-loader/dist/index.js']
429+
390430
COMPILER_PERMUTATIONS.forEach((compilerOptions) => {
391-
describe(`sets Cypress overrides to compiler options when compiler options are ${compilerOptions ? 'defined' : 'undefined'} when`, function () {
392-
it('rules is an array of "use" objects', function () {
393-
const options = {
394-
webpackOptions: {
395-
module: {
396-
rules: [
397-
{
398-
test: /\.tsx?$/,
399-
exclude: [/node_modules/],
400-
use: {
401-
loader: 'ts-loader',
402-
options: {
403-
compilerOptions,
431+
TS_LOADER_NAMES.forEach((tsLoaderName) => {
432+
describe(`sets Cypress overrides to compiler options when compiler options are ${compilerOptions ? 'defined' : 'undefined'} when`, function () {
433+
it(`rules is an array of "use" objects with ${tsLoaderName}`, function () {
434+
const options = {
435+
webpackOptions: {
436+
module: {
437+
rules: [
438+
{
439+
test: /\.tsx?$/,
440+
exclude: [/node_modules/],
441+
use: {
442+
loader: tsLoaderName,
443+
options: {
444+
compilerOptions,
445+
},
404446
},
405447
},
406-
},
407-
],
448+
],
449+
},
408450
},
409-
},
410-
}
411-
412-
return this.run(options).then(() => {
413-
expect(webpack).to.be.calledWithMatch({
414-
module: {
415-
rules: [
416-
{
417-
test: /\.tsx?$/,
418-
exclude: [/node_modules/],
419-
use: {
420-
loader: 'ts-loader',
421-
options: {
422-
compilerOptions: {
423-
downlevelIteration: true,
424-
inlineSourceMap: false,
425-
inlineSources: false,
426-
sourceMap: true,
451+
}
452+
453+
return this.run(options).then(() => {
454+
expect(webpack).to.be.calledWithMatch({
455+
module: {
456+
rules: [
457+
{
458+
test: /\.tsx?$/,
459+
exclude: [/node_modules/],
460+
use: {
461+
loader: tsLoaderName,
462+
options: {
463+
compilerOptions: {
464+
downlevelIteration: true,
465+
inlineSourceMap: false,
466+
inlineSources: false,
467+
sourceMap: true,
468+
},
427469
},
428470
},
429471
},
430-
},
431-
],
472+
],
473+
},
474+
})
475+
})
476+
})
477+
478+
it(`rules is an array of "use" array objects ${tsLoaderName}`, function () {
479+
const options = {
480+
webpackOptions: {
481+
module: {
482+
rules: [
483+
{
484+
test: /\.tsx?$/,
485+
exclude: [/node_modules/],
486+
use: [{
487+
loader: tsLoaderName,
488+
options: {
489+
compilerOptions,
490+
},
491+
}],
492+
},
493+
],
494+
},
432495
},
496+
}
497+
498+
return this.run(options).then(() => {
499+
expect(webpack).to.be.calledWithMatch({
500+
module: {
501+
rules: [
502+
{
503+
test: /\.tsx?$/,
504+
exclude: [/node_modules/],
505+
use: [{
506+
loader: tsLoaderName,
507+
options: {
508+
compilerOptions: {
509+
downlevelIteration: true,
510+
inlineSourceMap: false,
511+
inlineSources: false,
512+
sourceMap: true,
513+
},
514+
},
515+
}],
516+
},
517+
],
518+
},
519+
})
433520
})
434521
})
435-
})
436522

437-
it('rules is an array of "use" array objects', function () {
438-
const options = {
439-
webpackOptions: {
440-
module: {
441-
rules: [
442-
{
443-
test: /\.tsx?$/,
444-
exclude: [/node_modules/],
445-
use: [{
446-
loader: 'ts-loader',
523+
it(`rules is an array of "loader" objects ${tsLoaderName}`, function () {
524+
const options = {
525+
webpackOptions: {
526+
module: {
527+
rules: [
528+
{
529+
test: /\.tsx?$/,
530+
exclude: [/node_modules/],
531+
loader: tsLoaderName,
447532
options: {
448533
compilerOptions,
449534
},
450-
}],
451-
},
452-
],
535+
},
536+
],
537+
},
453538
},
454-
},
455-
}
456-
457-
return this.run(options).then(() => {
458-
expect(webpack).to.be.calledWithMatch({
459-
module: {
460-
rules: [
461-
{
462-
test: /\.tsx?$/,
463-
exclude: [/node_modules/],
464-
use: [{
465-
loader: 'ts-loader',
539+
}
540+
541+
return this.run(options).then(() => {
542+
expect(webpack).to.be.calledWithMatch({
543+
module: {
544+
rules: [
545+
{
546+
test: /\.tsx?$/,
547+
exclude: [/node_modules/],
548+
loader: tsLoaderName,
466549
options: {
467550
compilerOptions: {
468551
downlevelIteration: true,
@@ -471,51 +554,10 @@ describe('webpack preprocessor', function () {
471554
sourceMap: true,
472555
},
473556
},
474-
}],
475-
},
476-
],
477-
},
478-
})
479-
})
480-
})
481-
482-
it('rules is an array of "loader" objects', function () {
483-
const options = {
484-
webpackOptions: {
485-
module: {
486-
rules: [
487-
{
488-
test: /\.tsx?$/,
489-
exclude: [/node_modules/],
490-
loader: 'ts-loader',
491-
options: {
492-
compilerOptions,
493-
},
494-
},
495-
],
496-
},
497-
},
498-
}
499-
500-
return this.run(options).then(() => {
501-
expect(webpack).to.be.calledWithMatch({
502-
module: {
503-
rules: [
504-
{
505-
test: /\.tsx?$/,
506-
exclude: [/node_modules/],
507-
loader: 'ts-loader',
508-
options: {
509-
compilerOptions: {
510-
downlevelIteration: true,
511-
inlineSourceMap: false,
512-
inlineSources: false,
513-
sourceMap: true,
514-
},
515557
},
516-
},
517-
],
518-
},
558+
],
559+
},
560+
})
519561
})
520562
})
521563
})

0 commit comments

Comments
 (0)