Files
cypress/packages/server/lib/socket-e2e.ts
Lachlan Miller 792980ac12 feat: support specPattern, deprecate integrationFolder and componentFolder (#19319)
* use new specPattern API

* remove projectApi.findSpecs

* do not require integration folder

* support --spec

* support --spec

* remove old code

* remove old code

* nuke old code

* no appvetor

* update

* correct url for ct

* work on migrating launchpad

* update ct spec url

* types

* types

* dead code

* remove old endpiont

* revert back circle.yml

* update missing config

* delete spec util

* update config

* update config

* config again

* update spec pattern

* updated vue config

* update spec pattern for ui components

* update config for vite dev server

* update snapshots

* update config

* update design system config

* fix spec pattern in reporter

* update default

* update deprecated spec snapshots

* update system tests

* update run mode output

* revert changes

* lint

* remove scaffold tests

* update angular

* fix CT

* update circle yml

* fix system tests for ct

* fix tests

* work on server unit tests

* patch package

* patch package again

* update test

* try not to rely on config async loading too much

* normalize specPattern to array

* update snapshot

* use base name

* deal with react-scripts later

* update snapshot

* hacky way to update snapshots

* new hack to update snapshots

* trying again

* hacky fix

* ci: snapshots

* ci: snapshots

* snapshots

* mas updates

* update spec API

* fix test

* fix test

* update

* update test

* fix test

* update plugin

* update spec

* webpack optinos

* Update launchpad tests

* fix screenshot paths

* updated snapshot

* change pattern

* guard

* fix smoke test

* patch code coverage

* update percy config

* fix specs

* try updating example project

* update snapshots

* remove old test

* remove snapshot hack

* add back appveyor

* remove old code

* update snapshot

* Fix tests

* wip

* revert snapshot

* reverted all snaps

* remove only

* remove commnet

* remove old code

* reverted file

* lint

* revert video compression spec

* update snapshot

* update spec path logic

* update snap

* updated snap

* snaps

* snaps

* fix spec

* rename ignoreTestFiles to ignoreSpecPattern

* update screenshot dir for runner-ct

* update deprecations

* update

* upate

* fix test

* update snaps

* update snap

* updating snap

* added missing snaps

* updated cypress run mode integration spec

* electron snapshot

* ensure newly scaffold specs are cached

* fix launchpad spec

* types

* update test

* transpile based on spec pattern

* add back example

* remove unnecessary async and nodeVersion

* removed old test

* update spec pattern and add defensive check around platform

* remove unused feature flag

* added tests

* fix react example

* update test

* update config

* fix spec finding in run mode

* fix tests

* fixing specs

* fix switching between specs

* remove invalid test

* increase timeout

Co-authored-by: estrada9166 <estrada9166@hotmail.com>
2022-01-04 14:24:24 +10:00

145 lines
4.5 KiB
TypeScript

import Debug from 'debug'
import preprocessor from './plugins/preprocessor'
import { SocketBase } from './socket-base'
import { fs } from './util/fs'
import type { DestroyableHttpServer } from './util/server_destroy'
import * as studio from './studio'
import type { DataContext } from '@packages/data-context'
import type { FoundSpec } from '@packages/types'
const debug = Debug('cypress:server:socket-e2e')
const isSpecialSpec = (name) => {
return name.endsWith('__all')
}
export class SocketE2E extends SocketBase {
private testFilePath: string | null
constructor (config: Record<string, any>, ctx: DataContext) {
super(config, ctx)
this.testFilePath = null
this.onTestFileChange = this.onTestFileChange.bind(this)
this.onStudioTestFileChange = this.onStudioTestFileChange.bind(this)
this.removeOnStudioTestFileChange = this.removeOnStudioTestFileChange.bind(this)
if (config.watchForFileChanges) {
preprocessor.emitter.on('file:updated', this.onTestFileChange)
}
}
onStudioTestFileChange (filePath) {
// wait for the studio test file to be written to disk, then reload the test
// and remove the listener (since this handler is only invoked when watchForFileChanges is false)
return this.onTestFileChange(filePath).then(() => {
this.removeOnStudioTestFileChange()
})
}
removeOnStudioTestFileChange () {
return preprocessor.emitter.off('file:updated', this.onStudioTestFileChange)
}
onTestFileChange = (filePath) => {
debug('test file changed %o', filePath)
return fs.statAsync(filePath)
.then(() => {
return this.io.emit('watched:file:changed')
}).catch(() => {
return debug('could not find test file that changed %o', filePath)
})
}
watchTestFileByPath (config, specConfig: FoundSpec) {
debug('watching spec with config %o', specConfig)
// previously we have assumed that we pass integration spec path with "integration/" prefix
// now we pass spec config object that tells what kind of spec it is, has relative path already
// so the only special handling remains for special paths like "integration/__all"
// bail if this is special path like "__all"
// maybe the client should not ask to watch non-spec files?
if (isSpecialSpec(specConfig.relative)) {
return
}
if (specConfig.relative.startsWith('/')) {
specConfig.relative = specConfig.relative.slice(1)
}
// bail if we're already watching this exact file
if (specConfig.relative === this.testFilePath) {
return
}
// remove the existing file by its path
if (this.testFilePath) {
preprocessor.removeFile(this.testFilePath, config)
}
// store this location
this.testFilePath = specConfig.relative
debug('will watch test file path %o', specConfig.relative)
return preprocessor.getFile(specConfig.relative, config)
// ignore errors b/c we're just setting up the watching. errors
// are handled by the spec controller
.catch(() => {})
}
startListening (server: DestroyableHttpServer, automation, config, options) {
return super.startListening(server, automation, config, options, {
onSocketConnection: (socket) => {
socket.on('watch:test:file', (specInfo: FoundSpec, cb = function () { }) => {
debug('watch:test:file %o', specInfo)
this.watchTestFileByPath(config, specInfo)
// callback is only for testing purposes
return cb()
})
socket.on('studio:init', (cb) => {
studio.getStudioModalShown()
.then(cb)
})
socket.on('studio:save', (saveInfo, cb) => {
// even if the user has turned off file watching
// we want to force a reload on save
if (!config.watchForFileChanges) {
preprocessor.emitter.on('file:updated', this.onStudioTestFileChange)
}
studio.save(saveInfo)
.then((err) => {
cb(err)
// onStudioTestFileChange will remove itself after being called
// but if there's an error, it never gets called so we manually remove it
if (err && !config.watchForFileChanges) {
this.removeOnStudioTestFileChange()
}
})
.catch(() => {})
})
socket.on('studio:get:commands:text', (commands, cb) => {
const commandsText = studio.getCommandsText(commands)
cb(commandsText)
})
},
})
}
close () {
preprocessor.emitter.removeListener('file:updated', this.onTestFileChange)
super.close()
}
}