Skip to content

Commit

Permalink
feat: Disable file watching in component tests in run mode (#24097)
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-plummer authored Oct 5, 2022
1 parent 70f4945 commit 3e01474
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 50 deletions.
13 changes: 12 additions & 1 deletion npm/vite-dev-server/src/resolveConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { Vite } from './getVite'

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

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

if (config.cypressConfig.isTextTerminal) {
viteBaseConfig.server = {
...(viteBaseConfig.server || {}),
// Disable file watching and HMR when executing tests in `run` mode
watch: {
ignored: '**/*',
},
hmr: false,
}
}

let resolvedOverrides: UserConfig = {}

if (typeof viteOverrides === 'function') {
Expand Down
26 changes: 26 additions & 0 deletions npm/vite-dev-server/test/resolveConfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,30 @@ describe('resolveConfig', function () {
})
})
})

describe('file watching', () => {
let viteDevServerConfig: ViteDevServerConfig

beforeEach(async () => {
const projectRoot = await scaffoldSystemTestProject('vite-inspect')

viteDevServerConfig = getViteDevServerConfig(projectRoot)
})

it('should be disabled in run mode', async () => {
viteDevServerConfig.cypressConfig.isTextTerminal = true
const viteConfig = await createViteDevServerConfig(viteDevServerConfig, vite)

expect(viteConfig.server?.watch?.ignored).to.eql('**/*')
expect(viteConfig.server?.hmr).to.be.false
})

it('uses defaults in open mode', async () => {
viteDevServerConfig.cypressConfig.isTextTerminal = false
const viteConfig = await createViteDevServerConfig(viteDevServerConfig, vite)

expect(viteConfig.server?.watch?.ignored).to.be.undefined
expect(viteConfig.server?.hmr).to.be.undefined
})
})
})
13 changes: 10 additions & 3 deletions npm/webpack-dev-server/src/createWebpackDevServer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import debugLib from 'debug'
import type { Configuration } from 'webpack-dev-server-3'
import type { Configuration as WebpackDevServer3Configuration } from 'webpack-dev-server-3'
import type { Configuration as WebpackDevServer4Configuration } from 'webpack-dev-server'

import type { WebpackDevServerConfig } from './devServer'
import type { SourceRelativeWebpackResult } from './helpers/sourceRelativeWebpackModules'
Expand Down Expand Up @@ -66,8 +67,9 @@ function webpackDevServer4 (
finalWebpackConfig: Record<string, any>,
) {
const { devServerConfig: { cypressConfig: { devServerPublicPathRoute } } } = config
const isOpenMode = !config.devServerConfig.cypressConfig.isTextTerminal
const WebpackDevServer = config.sourceWebpackModulesResult.webpackDevServer.module
const webpackDevServerConfig = {
const webpackDevServerConfig: WebpackDevServer4Configuration = {
host: '127.0.0.1',
port: 'auto',
// @ts-ignore
Expand All @@ -77,6 +79,8 @@ function webpackDevServer4 (
stats: finalWebpackConfig.stats ?? 'minimal',
},
hot: false,
// Only enable file watching & reload when executing tests in `open` mode
liveReload: isOpenMode,
}

const server = new WebpackDevServer(webpackDevServerConfig, compiler)
Expand All @@ -93,8 +97,9 @@ function webpackDevServer3 (
finalWebpackConfig: Record<string, any>,
) {
const { devServerConfig: { cypressConfig: { devServerPublicPathRoute } } } = config
const isOpenMode = !config.devServerConfig.cypressConfig.isTextTerminal
const WebpackDevServer = config.sourceWebpackModulesResult.webpackDevServer.module
const webpackDevServerConfig: Configuration = {
const webpackDevServerConfig: WebpackDevServer3Configuration = {
// @ts-ignore
...finalWebpackConfig.devServer ?? {},
hot: false,
Expand All @@ -103,6 +108,8 @@ function webpackDevServer3 (
publicPath: devServerPublicPathRoute,
noInfo: false,
stats: finalWebpackConfig.stats ?? 'minimal',
// Only enable file watching & reload when executing tests in `open` mode
liveReload: isOpenMode,
}

const server = new WebpackDevServer(compiler, webpackDevServerConfig)
Expand Down
8 changes: 8 additions & 0 deletions npm/webpack-dev-server/src/makeDefaultWebpackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function makeDefaultWebpackConfig (
importPath,
} = config.sourceWebpackModulesResult.htmlWebpackPlugin
const indexHtmlFile = config.devServerConfig.cypressConfig.indexHtmlFile
const isRunMode = config.devServerConfig.cypressConfig.isTextTerminal
const HtmlWebpackPlugin = _HtmlWebpackPlugin as typeof import('html-webpack-plugin-5')

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

if (isRunMode) {
// Disable file watching when executing tests in `run` mode
finalConfig.watchOptions = {
ignored: '**/*',
}
}

if (config.sourceWebpackModulesResult.webpackDevServer.majorVersion === 4) {
return {
...finalConfig,
Expand Down
122 changes: 76 additions & 46 deletions npm/webpack-dev-server/test/devServer-e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import path from 'path'
import { expect } from 'chai'
import { once, EventEmitter } from 'events'
import http from 'http'
import fs from 'fs'
import fs from 'fs-extra'

import { devServer } from '..'
import { restoreLoadHook } from '../src/helpers/sourceRelativeWebpackModules'
import './support'
import type { ConfigHandler } from '../src/devServer'

const requestSpecFile = (file: string, port: number) => {
return new Promise((res) => {
Expand Down Expand Up @@ -34,7 +35,7 @@ const requestSpecFile = (file: string, port: number) => {

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

const webpackConfig = {
const webpackConfig: ConfigHandler = {
devServer: { static: { directory: root } },
}

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

type DevServerCloseFn = Awaited<ReturnType<typeof devServer>>['close']

const closeServer = async (closeFn: DevServerCloseFn) => {
await new Promise<void>((resolve, reject) => {
closeFn((err?: Error) => {
if (err) {
return reject(err)
}

resolve()
})
})
}

const cypressConfig = {
projectRoot: root,
supportFile: '',
Expand Down Expand Up @@ -78,15 +93,7 @@ describe('#devServer', () => {

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

await new Promise<void>((resolve, reject) => {
close((err) => {
if (err) {
return reject(err)
}

resolve()
})
})
await closeServer(close)
})

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

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

return new Promise((res) => {
close(() => res())
})
return closeServer(close)
})

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

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

return new Promise((res) => {
close(() => res())
})
return closeServer(close)
})

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

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

return new Promise((res) => {
close(() => res())
})
return closeServer(close)
})

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

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

return new Promise((res) => {
close(() => res())
})
return closeServer(close)
})

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

await once(devServerEvents, 'dev-server:compile:success')
await new Promise<void>((resolve, reject) => {
close((err) => {
if (err) {
return reject(err)
}

resolve()
})
})
await closeServer(close)
})

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

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

await new Promise<void>((resolve, reject) => {
close((err) => {
if (err) {
return reject(err)
await closeServer(close)
})

;[{
title: 'does not watch/recompile files in `run` mode',
isRunMode: true,
updateExpected: false,
message: 'Files should not be watched in `run` mode',
}, {
title: 'watches and recompiles files on change in `open` mode',
isRunMode: false,
updateExpected: true,
message: 'Files should be watched and automatically rebuild on update in `open` mode',
}].forEach(({ title, isRunMode, updateExpected, message }) => {
it(title, async () => {
const originalContent = await fs.readFile(`./test/fixtures/dependency.js`)

try {
cypressConfig.devServerPublicPathRoute = '/__cypress/src'
cypressConfig.isTextTerminal = isRunMode
const devServerEvents = new EventEmitter()
const { close, port } = await devServer({
webpackConfig: {},
cypressConfig,
specs: createSpecs('bar.spec.js'),
devServerEvents,
})

// Wait for initial "ready" from server
await once(devServerEvents, 'dev-server:compile:success')

// Get the initial version of the bundled spec
const original = await requestSpecFile('/__cypress/src/spec-0.js', port)

// Update a dependency of the spec
await fs.writeFile('./test/fixtures/dependency.js', `window.TEST = true;${originalContent}`)
// Brief wait to give server time to detect changes
await new Promise((resolve) => setTimeout(resolve, 500))

// Re-fetch the spec
const updated = await requestSpecFile('/__cypress/src/spec-0.js', port)

if (updateExpected) {
expect(original, message).not.to.equal(updated)
} else {
expect(original, message).to.equal(updated)
}

resolve()
})
await closeServer(close)
} finally {
fs.writeFile('./test/fixtures/dependency.js', originalContent)
}
})
})

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

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

await new Promise<void>((resolve, reject) => {
close((err) => {
if (err) {
return reject(err)
}

resolve()
})
})
await closeServer(close)
})
})
.timeout(5000)
2 changes: 2 additions & 0 deletions npm/webpack-dev-server/test/fixtures/bar.spec.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import './dependency'

const bar = () => {}
1 change: 1 addition & 0 deletions npm/webpack-dev-server/test/fixtures/dependency.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {}
Loading

5 comments on commit 3e01474

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3e01474 Oct 5, 2022

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.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.10.0/linux-x64/develop-3e014743909b35f54b697d2a759e4a2c5b67b5b7/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3e01474 Oct 5, 2022

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 arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.10.0/linux-arm64/develop-3e014743909b35f54b697d2a759e4a2c5b67b5b7/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3e01474 Oct 5, 2022

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 arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.10.0/darwin-arm64/develop-3e014743909b35f54b697d2a759e4a2c5b67b5b7/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3e01474 Oct 5, 2022

Choose a reason for hiding this comment

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

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

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.10.0/win32-x64/develop-3e014743909b35f54b697d2a759e4a2c5b67b5b7/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 3e01474 Oct 5, 2022

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.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.10.0/darwin-x64/develop-3e014743909b35f54b697d2a759e4a2c5b67b5b7/cypress.tgz

Please sign in to comment.