Skip to content

Commit 3e01474

Browse files
authored
feat: Disable file watching in component tests in run mode (#24097)
1 parent 70f4945 commit 3e01474

File tree

8 files changed

+217
-50
lines changed

8 files changed

+217
-50
lines changed

npm/vite-dev-server/src/resolveConfig.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { Vite } from './getVite'
1616

1717
const debug = debugFn('cypress:vite-dev-server:resolve-config')
1818

19-
export const createViteDevServerConfig = async (config: ViteDevServerConfig, vite: Vite) => {
19+
export const createViteDevServerConfig = async (config: ViteDevServerConfig, vite: Vite): Promise<InlineConfig> => {
2020
const { specs, cypressConfig, viteConfig: viteOverrides } = config
2121
const root = cypressConfig.projectRoot
2222
const { default: findUp } = await importModule('find-up')
@@ -90,6 +90,17 @@ export const createViteDevServerConfig = async (config: ViteDevServerConfig, vit
9090
].filter((p) => p != null),
9191
}
9292

93+
if (config.cypressConfig.isTextTerminal) {
94+
viteBaseConfig.server = {
95+
...(viteBaseConfig.server || {}),
96+
// Disable file watching and HMR when executing tests in `run` mode
97+
watch: {
98+
ignored: '**/*',
99+
},
100+
hmr: false,
101+
}
102+
}
103+
93104
let resolvedOverrides: UserConfig = {}
94105

95106
if (typeof viteOverrides === 'function') {

npm/vite-dev-server/test/resolveConfig.spec.ts

+26
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,30 @@ describe('resolveConfig', function () {
8989
})
9090
})
9191
})
92+
93+
describe('file watching', () => {
94+
let viteDevServerConfig: ViteDevServerConfig
95+
96+
beforeEach(async () => {
97+
const projectRoot = await scaffoldSystemTestProject('vite-inspect')
98+
99+
viteDevServerConfig = getViteDevServerConfig(projectRoot)
100+
})
101+
102+
it('should be disabled in run mode', async () => {
103+
viteDevServerConfig.cypressConfig.isTextTerminal = true
104+
const viteConfig = await createViteDevServerConfig(viteDevServerConfig, vite)
105+
106+
expect(viteConfig.server?.watch?.ignored).to.eql('**/*')
107+
expect(viteConfig.server?.hmr).to.be.false
108+
})
109+
110+
it('uses defaults in open mode', async () => {
111+
viteDevServerConfig.cypressConfig.isTextTerminal = false
112+
const viteConfig = await createViteDevServerConfig(viteDevServerConfig, vite)
113+
114+
expect(viteConfig.server?.watch?.ignored).to.be.undefined
115+
expect(viteConfig.server?.hmr).to.be.undefined
116+
})
117+
})
92118
})

npm/webpack-dev-server/src/createWebpackDevServer.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import debugLib from 'debug'
2-
import type { Configuration } from 'webpack-dev-server-3'
2+
import type { Configuration as WebpackDevServer3Configuration } from 'webpack-dev-server-3'
3+
import type { Configuration as WebpackDevServer4Configuration } from 'webpack-dev-server'
34

45
import type { WebpackDevServerConfig } from './devServer'
56
import type { SourceRelativeWebpackResult } from './helpers/sourceRelativeWebpackModules'
@@ -66,8 +67,9 @@ function webpackDevServer4 (
6667
finalWebpackConfig: Record<string, any>,
6768
) {
6869
const { devServerConfig: { cypressConfig: { devServerPublicPathRoute } } } = config
70+
const isOpenMode = !config.devServerConfig.cypressConfig.isTextTerminal
6971
const WebpackDevServer = config.sourceWebpackModulesResult.webpackDevServer.module
70-
const webpackDevServerConfig = {
72+
const webpackDevServerConfig: WebpackDevServer4Configuration = {
7173
host: '127.0.0.1',
7274
port: 'auto',
7375
// @ts-ignore
@@ -77,6 +79,8 @@ function webpackDevServer4 (
7779
stats: finalWebpackConfig.stats ?? 'minimal',
7880
},
7981
hot: false,
82+
// Only enable file watching & reload when executing tests in `open` mode
83+
liveReload: isOpenMode,
8084
}
8185

8286
const server = new WebpackDevServer(webpackDevServerConfig, compiler)
@@ -93,8 +97,9 @@ function webpackDevServer3 (
9397
finalWebpackConfig: Record<string, any>,
9498
) {
9599
const { devServerConfig: { cypressConfig: { devServerPublicPathRoute } } } = config
100+
const isOpenMode = !config.devServerConfig.cypressConfig.isTextTerminal
96101
const WebpackDevServer = config.sourceWebpackModulesResult.webpackDevServer.module
97-
const webpackDevServerConfig: Configuration = {
102+
const webpackDevServerConfig: WebpackDevServer3Configuration = {
98103
// @ts-ignore
99104
...finalWebpackConfig.devServer ?? {},
100105
hot: false,
@@ -103,6 +108,8 @@ function webpackDevServer3 (
103108
publicPath: devServerPublicPathRoute,
104109
noInfo: false,
105110
stats: finalWebpackConfig.stats ?? 'minimal',
111+
// Only enable file watching & reload when executing tests in `open` mode
112+
liveReload: isOpenMode,
106113
}
107114

108115
const server = new WebpackDevServer(compiler, webpackDevServerConfig)

npm/webpack-dev-server/src/makeDefaultWebpackConfig.ts

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export function makeDefaultWebpackConfig (
2020
importPath,
2121
} = config.sourceWebpackModulesResult.htmlWebpackPlugin
2222
const indexHtmlFile = config.devServerConfig.cypressConfig.indexHtmlFile
23+
const isRunMode = config.devServerConfig.cypressConfig.isTextTerminal
2324
const HtmlWebpackPlugin = _HtmlWebpackPlugin as typeof import('html-webpack-plugin-5')
2425

2526
debug(`Using HtmlWebpackPlugin version ${version} from ${importPath}`)
@@ -55,6 +56,13 @@ export function makeDefaultWebpackConfig (
5556
devtool: 'inline-source-map',
5657
} as any
5758

59+
if (isRunMode) {
60+
// Disable file watching when executing tests in `run` mode
61+
finalConfig.watchOptions = {
62+
ignored: '**/*',
63+
}
64+
}
65+
5866
if (config.sourceWebpackModulesResult.webpackDevServer.majorVersion === 4) {
5967
return {
6068
...finalConfig,

npm/webpack-dev-server/test/devServer-e2e.spec.ts

+76-46
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import path from 'path'
22
import { expect } from 'chai'
33
import { once, EventEmitter } from 'events'
44
import http from 'http'
5-
import fs from 'fs'
5+
import fs from 'fs-extra'
66

77
import { devServer } from '..'
88
import { restoreLoadHook } from '../src/helpers/sourceRelativeWebpackModules'
99
import './support'
10+
import type { ConfigHandler } from '../src/devServer'
1011

1112
const requestSpecFile = (file: string, port: number) => {
1213
return new Promise((res) => {
@@ -34,7 +35,7 @@ const requestSpecFile = (file: string, port: number) => {
3435

3536
const root = path.join(__dirname, '..')
3637

37-
const webpackConfig = {
38+
const webpackConfig: ConfigHandler = {
3839
devServer: { static: { directory: root } },
3940
}
4041

@@ -48,6 +49,20 @@ const createSpecs = (name: string): Cypress.Cypress['spec'][] => {
4849
]
4950
}
5051

52+
type DevServerCloseFn = Awaited<ReturnType<typeof devServer>>['close']
53+
54+
const closeServer = async (closeFn: DevServerCloseFn) => {
55+
await new Promise<void>((resolve, reject) => {
56+
closeFn((err?: Error) => {
57+
if (err) {
58+
return reject(err)
59+
}
60+
61+
resolve()
62+
})
63+
})
64+
}
65+
5166
const cypressConfig = {
5267
projectRoot: root,
5368
supportFile: '',
@@ -78,15 +93,7 @@ describe('#devServer', () => {
7893

7994
expect(response).to.eq('const foo = () => {}\n')
8095

81-
await new Promise<void>((resolve, reject) => {
82-
close((err) => {
83-
if (err) {
84-
return reject(err)
85-
}
86-
87-
resolve()
88-
})
89-
})
96+
await closeServer(close)
9097
})
9198

9299
it('serves specs in directory with [] chars via a webpack dev server', async () => {
@@ -101,9 +108,7 @@ describe('#devServer', () => {
101108

102109
expect(response).to.eq(`it('this is a spec with a path containing []', () => {})\n`)
103110

104-
return new Promise((res) => {
105-
close(() => res())
106-
})
111+
return closeServer(close)
107112
})
108113

109114
it('serves specs in directory with non English chars via a webpack dev server', async () => {
@@ -118,9 +123,7 @@ describe('#devServer', () => {
118123

119124
expect(response).to.eq(`it('サイプレス', () => {})\n`)
120125

121-
return new Promise((res) => {
122-
close(() => res())
123-
})
126+
return closeServer(close)
124127
})
125128

126129
it('serves specs in directory with ... in the file name via a webpack dev server', async () => {
@@ -135,9 +138,7 @@ describe('#devServer', () => {
135138

136139
expect(response).to.eq(`it('...bar', () => {})\n`)
137140

138-
return new Promise((res) => {
139-
close(() => res())
140-
})
141+
return closeServer(close)
141142
})
142143

143144
it('serves a file with spaces via a webpack dev server', async () => {
@@ -152,9 +153,7 @@ describe('#devServer', () => {
152153

153154
expect(response).to.eq(`it('this is a spec with a path containing a space', () => {})\n`)
154155

155-
return new Promise((res) => {
156-
close(() => res())
157-
})
156+
return closeServer(close)
158157
})
159158

160159
it('emits dev-server:compile:success event on successful compilation', async () => {
@@ -167,18 +166,13 @@ describe('#devServer', () => {
167166
})
168167

169168
await once(devServerEvents, 'dev-server:compile:success')
170-
await new Promise<void>((resolve, reject) => {
171-
close((err) => {
172-
if (err) {
173-
return reject(err)
174-
}
175169

176-
resolve()
177-
})
178-
})
170+
await closeServer(close)
179171
})
180172

181173
it('touches browser.js when a spec file is added and recompile', async function () {
174+
// File watching only enabled when running in `open` mode
175+
cypressConfig.isTextTerminal = false
182176
const devServerEvents = new EventEmitter()
183177
const { close } = await devServer({
184178
webpackConfig,
@@ -203,14 +197,58 @@ describe('#devServer', () => {
203197

204198
expect(oldmtime).to.not.equal(updatedmtime)
205199

206-
await new Promise<void>((resolve, reject) => {
207-
close((err) => {
208-
if (err) {
209-
return reject(err)
200+
await closeServer(close)
201+
})
202+
203+
;[{
204+
title: 'does not watch/recompile files in `run` mode',
205+
isRunMode: true,
206+
updateExpected: false,
207+
message: 'Files should not be watched in `run` mode',
208+
}, {
209+
title: 'watches and recompiles files on change in `open` mode',
210+
isRunMode: false,
211+
updateExpected: true,
212+
message: 'Files should be watched and automatically rebuild on update in `open` mode',
213+
}].forEach(({ title, isRunMode, updateExpected, message }) => {
214+
it(title, async () => {
215+
const originalContent = await fs.readFile(`./test/fixtures/dependency.js`)
216+
217+
try {
218+
cypressConfig.devServerPublicPathRoute = '/__cypress/src'
219+
cypressConfig.isTextTerminal = isRunMode
220+
const devServerEvents = new EventEmitter()
221+
const { close, port } = await devServer({
222+
webpackConfig: {},
223+
cypressConfig,
224+
specs: createSpecs('bar.spec.js'),
225+
devServerEvents,
226+
})
227+
228+
// Wait for initial "ready" from server
229+
await once(devServerEvents, 'dev-server:compile:success')
230+
231+
// Get the initial version of the bundled spec
232+
const original = await requestSpecFile('/__cypress/src/spec-0.js', port)
233+
234+
// Update a dependency of the spec
235+
await fs.writeFile('./test/fixtures/dependency.js', `window.TEST = true;${originalContent}`)
236+
// Brief wait to give server time to detect changes
237+
await new Promise((resolve) => setTimeout(resolve, 500))
238+
239+
// Re-fetch the spec
240+
const updated = await requestSpecFile('/__cypress/src/spec-0.js', port)
241+
242+
if (updateExpected) {
243+
expect(original, message).not.to.equal(updated)
244+
} else {
245+
expect(original, message).to.equal(updated)
210246
}
211247

212-
resolve()
213-
})
248+
await closeServer(close)
249+
} finally {
250+
fs.writeFile('./test/fixtures/dependency.js', originalContent)
251+
}
214252
})
215253
})
216254

@@ -229,15 +267,7 @@ describe('#devServer', () => {
229267

230268
expect(response).to.eq('const foo = () => {}\n')
231269

232-
await new Promise<void>((resolve, reject) => {
233-
close((err) => {
234-
if (err) {
235-
return reject(err)
236-
}
237-
238-
resolve()
239-
})
240-
})
270+
await closeServer(close)
241271
})
242272
})
243273
.timeout(5000)
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
import './dependency'
2+
13
const bar = () => {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {}

0 commit comments

Comments
 (0)