test: node_modules installs for system-tests, other improvements (#18574)

Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
This commit is contained in:
Zach Bloomquist
2021-11-24 20:10:28 +00:00
committed by GitHub
parent cbfb3cad41
commit 71d92e0e49
66 changed files with 7136 additions and 420 deletions

View File

@@ -149,6 +149,55 @@ commands:
name: Restore all node_modules to proper workspace folders
command: node scripts/circle-cache.js --action unpack
restore_cached_system_tests_deps:
description: 'Restore the cached node_modules for projects in "system-tests/projects/**"'
steps:
- run:
name: Generate Circle Cache key for system tests
command: ./system-tests/scripts/cache-key.sh > system_tests_cache_key
- restore_cache:
name: Restore system tests node_modules cache
keys:
- v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }}
- v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-
update_cached_system_tests_deps:
description: 'Update the cached node_modules for projects in "system-tests/projects/**"'
steps:
- run:
name: Generate Circle Cache key for system tests
command: ./system-tests/scripts/cache-key.sh > system_tests_cache_key
- restore_cache:
name: Restore cache state, to check for known modules cache existence
keys:
- v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }}
- run:
name: Bail if specific cache exists
command: |
if [[ -f "system_tests_node_modules_installed" ]]; then
echo "No updates to system tests node modules, exiting"
circleci-agent step halt
fi
- restore_cache:
name: Restore system tests node_modules cache
keys:
- v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }}
- v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-
- run:
name: Update system-tests node_modules cache
command: yarn workspace @tooling/system-tests projects:yarn:install
- save_cache:
name: Save system tests node_modules cache
key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }}
paths:
- ~/.cache/cy-system-tests-node-modules
- run: touch system_tests_node_modules_installed
- save_cache:
name: Save system tests node_modules cache state key
key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }}
paths:
- system_tests_node_modules_installed
caching-dependency-installer:
description: 'Installs & caches the dependencies based on yarn lock & package json dependencies'
parameters:
@@ -427,6 +476,7 @@ commands:
type: string
steps:
- restore_cached_workspace
- restore_cached_system_tests_deps
- run:
name: Run system tests
command: |
@@ -1083,6 +1133,12 @@ jobs:
path: /tmp/artifacts
- store-npm-logs
system-tests-node-modules-install:
<<: *defaults
steps:
- restore_cached_workspace
- update_cached_system_tests_deps
system-tests-chrome:
<<: *defaults
resource_class: medium
@@ -2007,19 +2063,22 @@ linux-workflow: &linux-workflow
- server-performance-tests:
requires:
- build
- system-tests-node-modules-install:
requires:
- build
- system-tests-chrome:
requires:
- build
- system-tests-node-modules-install
- system-tests-electron:
requires:
- build
- system-tests-node-modules-install
- system-tests-firefox:
requires:
- build
- system-tests-node-modules-install
- system-tests-non-root:
executor: non-root-docker-user
requires:
- build
- system-tests-node-modules-install
- driver-integration-tests-chrome:
requires:
- build

View File

@@ -17,7 +17,15 @@ export const overrideSourceMaps = (sourceMap: boolean, typescriptPath?: string)
return
}
const typescript = require(typescriptPath || 'typescript') as typeof import('typescript')
// when using webpack-preprocessor as a local filesystem dependency (`file:...`),
// require(typescript) will resolve to this repo's `typescript` devDependency, not the
// targeted project's `typescript`, which breaks monkeypatching. resolving from the
// CWD avoids this issue.
const projectTsPath = require.resolve(typescriptPath || 'typescript', {
paths: [process.cwd()],
})
const typescript = require(projectTsPath) as typeof import('typescript')
const { createProgram } = typescript
debug('typescript found, overriding typescript.createProgram()')

View File

@@ -147,7 +147,7 @@ describe('./lib/typescript-overrides', () => {
const err = typescriptOverrides.overrideSourceMaps(true)
expect(err).to.be.instanceOf(Error)
expect(err.message).to.eq(`Cannot find module 'typescript'`)
expect(err.message).to.match(/Cannot find module '.*typescript\.js'/)
})
})
})

View File

@@ -42,7 +42,7 @@ const init = (config, options) => {
// test and warn for incompatible plugin
try {
const retriesPluginPath = path.dirname(resolve.sync('cypress-plugin-retries', {
const retriesPluginPath = path.dirname(resolve.sync('cypress-plugin-retries/package.json', {
basedir: options.projectRoot,
}))

View File

@@ -42,7 +42,7 @@ zlib = Promise.promisifyAll(zlib)
// force supertest-session to use promises provided in supertest
const session = proxyquire('supertest-session', { supertest })
const absolutePathRegex = /"\/[^{}]*?\.projects/g
const absolutePathRegex = /"\/[^{}]*?cy-projects/g
let sourceMapRegex = /\n\/\/# sourceMappingURL\=.*/
const replaceAbsolutePaths = (content) => {

View File

@@ -6,8 +6,9 @@ const Fixtures = require('@tooling/system-tests/lib/fixtures')
const pluginsFile = Fixtures.projectPath('plugin-before-browser-launch-deprecation/cypress/plugins/index.js')
describe('lib/plugins', () => {
beforeEach(() => {
Fixtures.scaffold()
beforeEach(async () => {
Fixtures.scaffoldProject('plugin-before-browser-launch-deprecation')
await Fixtures.scaffoldCommonNodeModules()
})
afterEach(() => {

View File

@@ -25,7 +25,7 @@ describe('lib/files', () => {
return files.readFile(this.projectRoot, 'tests/_fixtures/message.txt').then(({ contents, filePath }) => {
expect(contents).to.eq('foobarbaz')
expect(filePath).to.include('/.projects/todos/tests/_fixtures/message.txt')
expect(filePath).to.include('/cy-projects/todos/tests/_fixtures/message.txt')
})
})
@@ -69,7 +69,7 @@ describe('lib/files', () => {
return files.readFile(this.projectRoot, '.projects/write_file.txt').then(({ contents, filePath }) => {
expect(contents).to.equal('foo')
expect(filePath).to.include('/.projects/todos/.projects/write_file.txt')
expect(filePath).to.include('/cy-projects/todos/.projects/write_file.txt')
})
})
})

View File

@@ -159,21 +159,24 @@ const runFailingProjectTest = function (buildAppExecutable, e2e) {
.then(verifyScreenshots)
}
const test = function (buildAppExecutable) {
Fixtures.scaffold()
const test = async function (buildAppExecutable) {
await Fixtures.scaffoldCommonNodeModules()
Fixtures.scaffoldProject('e2e')
const e2e = Fixtures.projectPath('e2e')
return runSmokeTest(buildAppExecutable)
.then(() => {
return runProjectTest(buildAppExecutable, e2e)
}).then(() => {
return runFailingProjectTest(buildAppExecutable, e2e)
}).then(() => {
return Fixtures.remove()
})
await runSmokeTest(buildAppExecutable)
await runProjectTest(buildAppExecutable, e2e)
await runFailingProjectTest(buildAppExecutable, e2e)
Fixtures.remove()
}
module.exports = {
test,
}
if (require.main === module) {
const buildAppExecutable = path.join(__dirname, `../../build/${os.platform()}-unpacked/Cypress`)
console.log('Script invoked directly, running smoke tests.')
test(buildAppExecutable)
}

View File

@@ -7,7 +7,7 @@ These tests launch the [Cypress server](../packages/server) process for each tes
These tests run in CI in Electron, Chrome, and Firefox under the `system-tests` job family.
## Running system tests
## Running System Tests
```bash
yarn test <path/to/test>
@@ -28,14 +28,14 @@ To debug the Cypress process under test, you can pass `--cypress-inspect-brk`:
yarn test test/go_spec.js --browser chrome --no-exit
```
## Developing tests
## Developing Tests
System tests cover the entire Cypress run, so they are good for testing features that do not fit into a normal integration or unit test. However, they do take more resources to run, so consider carefully if you really *need* to write a system test, or if you could achieve 100% coverage via an integration or unit test instead.
There are two parts to a system test:
1. A test written using the [`systemTests`](./lib/system-tests) Mocha wrapper that lives in [`./test`](./test), and
2. A matching Cypress project that lives in the [`./projects`](./projects) directory.
2. A matching Cypress [test project](#Test-Projects) that lives in the [`./projects`](./projects) directory.
For example, if you initialized a new project in `./projects/my-new-project`, and you wanted to assert that 2 tests fail and take a snapshot of the `stdout`, you'd write a test like this:
@@ -61,10 +61,32 @@ From here, you could run this test with `yarn test my-new-project`.
There are many more options available for `systemTests.it` and `systemTests.setup`. You can massage the stdout, do pre-run tasks, set up HTTP/S servers, and more. Explore the typedocs in [`./lib/system-tests`](./lib/system-tests) for more information.
## Updating snaphots
### Updating Snaphots
Prepend `SNAPSHOT_UPDATE=1` to any test command. See [`snap-shot-it` instructions](https://github.com/bahmutov/snap-shot-it#advanced-use) for more info.
```bash
SNAPSHOT_UPDATE=1 yarn test go_spec
```
### Test Projects
Every folder in [`./projects`](./lib/projects) represents a self-contained Cypress project. When you pass the `project` property to `systemTests.it` or `systemTests.exec`, Cypress launches using this project.
If a test project has a `package.json` file, the `systemTests.exec` helper will attempt to install the correct `node_modules` by running `yarn install` against the project. This is cached in CI and locally to speed up test times.
`systemTests.exec` *copies* the project directory to a temporary folder outside of the monorepo root. This means that temporary projects will not inherit the `node_modules` from this package or the monorepo. So, you must add the dependencies required for your project in `dependencies` or `devDependencies`.
The exception is some commonly used packages that are scaffolded for all projects, like `lodash` and `debug`. You can see the list by looking at `scaffoldCommonNodeModules` in [`./lib/fixtures.ts`](./lib/fixtures.ts) These packages do not need to be added to a test project's `package.json`.
You can also set special properties in a test project's `package.json` to influence the helper's behavior when running `yarn`:
`package.json` Property Name | Type | Description
--- | --- | ---
`_cySkipYarnInstall` | `boolean` | If `true`, skip the automatic `yarn install` for this package, even though it has a `package.json`.
`_cyYarnV2` | `boolean` | Run the yarn v2-style install command instead of yarn v1-style.
`_cyRunScripts` | `boolean` | By default, the automatic `yarn install` will not run postinstall scripts. This option, if set, will cause postinstall scripts to run for this project.
Run `yarn projects:yarn:install` to run `yarn install` for all projects with a `package.json`.
Use the `UPDATE_YARN_LOCK=1` environment variable with `yarn test` or `yarn projects:yarn:install` to allow the `yarn.lock` to be updated and synced back to the monorepo from the temp dir.

View File

@@ -25,6 +25,8 @@ Error: Webpack Compilation Error
./cypress/support/index.js
Module not found: Error: Can't resolve './does/not/exist' in '/foo/bar/.projects/busted-support-file/cypress/support'
Looked for and couldn't find the file at the following paths:
[/foo/bar/.projects/busted-support-file/cypress/support/package.json]
[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist/package.json]
[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist]
[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.js]
[/foo/bar/.projects/busted-support-file/cypress/support/does/not/exist.json]

View File

@@ -90,7 +90,7 @@ Error: Webpack Compilation Error
./cypress/integration/typescript_syntax_error_spec.tsXX:XX
Module parse failed: Unexpected token (3:19)
File was processed with these loaders:
* ../../../npm/webpack-batteries-included-preprocessor/node_modules/ts-loader/index.js
* relative/path/to/webpack-batteries-included-preprocessor/node_modules/ts-loader/index.js
You may need an additional loader to handle the result of these loaders.
| // The code below is ignored by eslint
| // because it tests failing spec.

View File

@@ -1,79 +0,0 @@
const fs = require('fs-extra')
const path = require('path')
const chokidar = require('chokidar')
const root = path.join(__dirname, '..')
const serverRoot = path.join(__dirname, '../../packages/server/')
const projects = path.join(root, 'projects')
const tmpDir = path.join(root, '.projects')
// copy contents instead of deleting+creating new file, which can cause
// filewatchers to lose track of toFile.
const copyContents = (fromFile, toFile) => {
return Promise.all([
fs.open(toFile, 'w'),
fs.readFile(fromFile),
])
.then(([toFd, fromFileBuf]) => {
return fs.write(toFd, fromFileBuf)
.finally(() => {
return fs.close(toFd)
})
})
}
module.exports = {
// copies all of the project fixtures
// to the tmpDir .projects in the root
scaffold () {
return fs.copySync(projects, tmpDir)
},
scaffoldWatch () {
const watchdir = path.resolve(__dirname, '../projects')
console.log('watching files due to --no-exit', watchdir)
chokidar.watch(watchdir, {
})
.on('change', (srcFilepath, stats) => {
const tmpFilepath = path.join(tmpDir, path.relative(watchdir, srcFilepath))
return copyContents(srcFilepath, tmpFilepath)
})
.on('error', console.error)
},
// removes all of the project fixtures
// from the tmpDir .projects in the root
remove () {
return fs.removeSync(tmpDir)
},
async installStubPackage (projectPath, pkgName) {
const pathToPkg = path.join(projectPath, 'node_modules', pkgName)
await fs.outputJSON(path.join(projectPath, 'package.json'), { name: 'some-project' })
await fs.mkdirp(pathToPkg)
await fs.outputFile(path.join(pathToPkg, 'index.js'), '')
},
// returns the path to project fixture
// in the tmpDir
project (...args) {
return this.projectPath.apply(this, args)
},
projectPath (name) {
return path.join(tmpDir, name)
},
get (fixture, encoding = 'utf8') {
return fs.readFileSync(path.join(serverRoot, 'test', 'support', 'fixtures', fixture), encoding)
},
path (fixture) {
return path.join(serverRoot, 'test', 'support', 'fixtures', fixture)
},
}

View File

@@ -0,0 +1,346 @@
import fs from 'fs-extra'
import _path from 'path'
import chokidar from 'chokidar'
import os from 'os'
import cachedir from 'cachedir'
import execa from 'execa'
const root = _path.join(__dirname, '..')
const serverRoot = _path.join(__dirname, '../../packages/server/')
const projects = _path.join(root, 'projects')
const tmpDir = _path.join(os.tmpdir(), 'cy-projects')
// copy contents instead of deleting+creating new file, which can cause
// filewatchers to lose track of toFile.
const copyContents = (fromFile, toFile) => {
return Promise.all([
fs.open(toFile, 'w'),
fs.readFile(fromFile),
])
.then(([toFd, fromFileBuf]) => {
return fs.write(toFd, fromFileBuf)
.finally(() => {
return fs.close(toFd)
})
})
}
// copies all of the project fixtures
// to the tmpDir .projects in the root
export function scaffold () {
fs.copySync(projects, tmpDir)
}
/**
* Given a project name, copy the project's test files to the temp dir.
*/
export function scaffoldProject (project: string): void {
const from = _path.join(projects, project)
const to = _path.join(tmpDir, project)
fs.copySync(from, to)
}
/**
* Symlink the cached `node_modules` directory to the temp project directory's `node_modules`.
*/
async function symlinkNodeModulesFromCache (project: string, cacheDir: string): Promise<void> {
const from = _path.join(projectPath(project), 'node_modules')
try {
await fs.stat(cacheDir)
} catch (err) {
console.log(`📦 Creating a new node_modules cache dir at ${cacheDir}`)
await fs.mkdirp(cacheDir)
}
try {
await fs.symlink(cacheDir, from, 'junction')
} catch (err) {
if (err.code !== 'EEXIST') return
}
console.log(`📦 node_modules symlink created at ${from}`)
}
/**
* Given a package name, returns the path to the module directory on disk.
*/
function pathToPackage (pkg: string): string {
return _path.dirname(require.resolve(`${pkg}/package.json`))
}
/**
* Given a path to a `package.json`, convert any references to development
* versions of packages to absolute paths, so `yarn` will not reach out to
* the Internet to obtain these packages once it runs in the temp dir.
* @returns a list of dependency names that were updated
*/
async function makeWorkspacePackagesAbsolute (pathToPkgJson: string): Promise<string[]> {
const pkgJson = await fs.readJson(pathToPkgJson)
const updatedDeps: string[] = []
for (const deps of [pkgJson.dependencies, pkgJson.devDependencies, pkgJson.optionalDependencies]) {
for (const dep in deps) {
const version = deps[dep]
if (version.startsWith('file:')) {
const absPath = pathToPackage(dep)
console.log(`📦 Setting absolute path in package.json for ${dep}: ${absPath}.`)
deps[dep] = `file:${absPath}`
updatedDeps.push(dep)
}
}
}
await fs.writeJson(pathToPkgJson, pkgJson)
return updatedDeps
}
function getYarnCommand (opts: {
yarnV2: boolean
updateYarnLock: boolean
isCI: boolean
runScripts: boolean
}): string {
let cmd = `yarn install`
if (opts.yarnV2) {
// yarn v2's docs are no longer available on their site now that yarn v3 is out,
// Internet Archive has them here:
// @see https://web.archive.org/web/20210102223647/https://yarnpkg.com/cli/install
if (!opts.runScripts) cmd += ' --skip-builds'
if (!opts.updateYarnLock) cmd += ' --immutable'
return cmd
}
cmd += ' --prefer-offline'
if (!opts.runScripts) cmd += ' --ignore-scripts'
if (!opts.updateYarnLock) cmd += ' --frozen-lockfile'
// yarn v1 has a bug with integrity checking and local cache/dependencies
// @see https://github.com/yarnpkg/yarn/issues/6407
cmd += ' --update-checksums'
// in CircleCI, this offline cache can be used
if (opts.isCI) cmd += ` --cache-folder=~/.yarn-${process.platform} `
else cmd += ` --cache-folder=${_path.join(os.tmpdir(), 'cy-system-tests-yarn-cache', String(Date.now()))}`
return cmd
}
type Dependencies = Record<string, string>
/**
* Type for package.json files for system-tests example projects.
*/
type SystemTestPkgJson = {
/**
* By default, scaffolding will run `yarn install` if there is a `package.json`.
* This option, if set, disables that.
*/
_cySkipYarnInstall?: boolean
/**
* Run the yarn v2-style install command instead of yarn v1-style.
*/
_cyYarnV2?: boolean
/**
* By default, the automatic `yarn install` will not run postinstall scripts. This
* option, if set, will cause postinstall scripts to run for this project.
*/
_cyRunScripts?: boolean
dependencies?: Dependencies
devDependencies?: Dependencies
optionalDependencies?: Dependencies
}
/**
* Given a `system-tests` project name, detect and install the `node_modules`
* specified in the project's `package.json`. No-op if no `package.json` is found.
*/
export async function scaffoldProjectNodeModules (project: string, updateYarnLock: boolean = !!process.env.UPDATE_YARN_LOCK): Promise<void> {
const projectDir = projectPath(project)
const relativePathToMonorepoRoot = _path.relative(
_path.join(projects, project),
_path.join(root, '..'),
)
const projectPkgJsonPath = _path.join(projectDir, 'package.json')
const runCmd = async (cmd) => {
console.log(`📦 Running "${cmd}" in ${projectDir}`)
await execa.shell(cmd, { cwd: projectDir, stdio: 'inherit' })
}
const cacheDir = _path.join(cachedir('cy-system-tests-node-modules'), project, 'node_modules')
async function removeWorkspacePackages (packages: string[]): Promise<void> {
for (const dep of packages) {
const depDir = _path.join(cacheDir, dep)
await fs.remove(depDir)
}
}
try {
// this will throw and exit early if the package.json does not exist
const pkgJson: SystemTestPkgJson = require(projectPkgJsonPath)
console.log(`📦 Found package.json for project ${project}.`)
if (pkgJson._cySkipYarnInstall) {
return console.log(`📦 cySkipYarnInstall set in package.json, skipping yarn steps`)
}
if (!pkgJson.dependencies && !pkgJson.devDependencies && !pkgJson.optionalDependencies) {
return console.log(`📦 No dependencies found, skipping yarn steps`)
}
// 1. Ensure there is a cache directory set up for this test project's `node_modules`.
await symlinkNodeModulesFromCache(project, cacheDir)
// 2. Before running `yarn`, resolve workspace deps to absolute paths.
// This is required to fix `yarn install` for workspace-only packages.
const workspaceDeps = await makeWorkspacePackagesAbsolute(projectPkgJsonPath)
await removeWorkspacePackages(workspaceDeps)
// 3. Fix relative paths in temp dir's `yarn.lock`.
const relativePathToProjectDir = _path.relative(projectDir, _path.join(root, '..'))
const yarnLockPath = _path.join(projectDir, 'yarn.lock')
console.log('📦 Writing yarn.lock with fixed relative paths to temp dir')
try {
const yarnLock = (await fs.readFile(yarnLockPath, 'utf8'))
.replaceAll(relativePathToMonorepoRoot, relativePathToProjectDir)
await fs.writeFile(yarnLockPath, yarnLock)
} catch (err) {
if (err.code !== 'ENOENT' || !updateYarnLock) throw err
console.log('📦 No yarn.lock found, continuing')
}
// 4. Run `yarn install`.
const cmd = getYarnCommand({
updateYarnLock,
yarnV2: pkgJson._cyYarnV2,
isCI: !!process.env.CI,
runScripts: pkgJson._cyRunScripts,
})
await runCmd(cmd)
console.log(`📦 Copying yarn.lock and fixing relative paths for ${project}`)
// Replace workspace dependency paths in `yarn.lock` with tokens so it can be the same
// for all developers
const yarnLock = (await fs.readFile(yarnLockPath, 'utf8'))
.replaceAll(relativePathToProjectDir, relativePathToMonorepoRoot)
await fs.writeFile(_path.join(projects, project, 'yarn.lock'), yarnLock)
// 5. After `yarn install`, we must now symlink *over* all workspace dependencies, or else
// `require` calls from `yarn install`'d workspace deps to peer deps will fail.
await removeWorkspacePackages(workspaceDeps)
for (const dep of workspaceDeps) {
console.log(`📦 Symlinking workspace dependency: ${dep}`)
const depDir = _path.join(cacheDir, dep)
await fs.symlink(pathToPackage(dep), depDir, 'junction')
}
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') return
console.error(`⚠ An error occurred while installing the node_modules for ${project}.`)
console.error([err.message, err.stack].join('\n'))
throw err
}
}
export async function scaffoldCommonNodeModules () {
await Promise.all([
'@cypress/code-coverage',
'@cypress/webpack-dev-server',
'@packages/socket',
'@packages/ts',
'@tooling/system-tests',
'bluebird',
'chai',
'dayjs',
'debug',
'execa',
'fs-extra',
'https-proxy-agent',
'jimp',
'lazy-ass',
'lodash',
'proxyquire',
'react',
'semver',
'systeminformation',
'tslib',
'typescript',
].map(symlinkNodeModule))
}
export async function symlinkNodeModule (pkg) {
const from = _path.join(tmpDir, 'node_modules', pkg)
const to = pathToPackage(pkg)
await fs.ensureDir(_path.dirname(from))
try {
await fs.symlink(to, from, 'junction')
} catch (err) {
if (err.code === 'EEXIST') return
throw err
}
}
export function scaffoldWatch () {
const watchdir = _path.resolve(__dirname, '../projects')
console.log('watching files due to --no-exit', watchdir)
chokidar.watch(watchdir, {
})
.on('change', (srcFilepath, stats) => {
const tmpFilepath = _path.join(tmpDir, _path.relative(watchdir, srcFilepath))
return copyContents(srcFilepath, tmpFilepath)
})
.on('error', console.error)
}
// removes all of the project fixtures
// from the tmpDir .projects in the root
export function remove () {
return fs.removeSync(tmpDir)
}
// returns the path to project fixture
// in the tmpDir
export function project (...args) {
return this.projectPath.apply(this, args)
}
export function projectPath (name) {
return _path.join(tmpDir, name)
}
export function get (fixture, encoding: BufferEncoding = 'utf8') {
return fs.readFileSync(_path.join(serverRoot, 'test', 'support', 'fixtures', fixture), { encoding })
}
export function path (fixture) {
return _path.join(serverRoot, 'test', 'support', 'fixtures', fixture)
}
export default module.exports

View File

@@ -200,9 +200,9 @@ type ExecOptions = {
*/
noTypeScript?: boolean
/**
* If set, a dummy `node_modules` project with this name will be set up.
* Skip scaffolding the project and node_modules.
*/
stubPackage?: string
skipScaffold?: boolean
/**
* Run Cypress with a custom user node path.
*/
@@ -475,12 +475,8 @@ const startServer = function (obj) {
app.use(require('cors')())
}
const s = obj.static
if (s) {
const opts = _.isObject(s) ? s : {}
app.use(express.static(e2ePath, opts))
if (obj.static) {
app.use(express.static(path.join(__dirname, '../projects/e2e'), {}))
}
return new Bluebird((resolve) => {
@@ -670,17 +666,16 @@ const systemTests = {
setup (options: SetupOptions = {}) {
beforeEach(async function () {
// after installing node modules copying all of the fixtures
// can take a long time (5-15 secs)
this.timeout(human('2 minutes'))
Fixtures.scaffold()
// // after installing node modules copying all of the fixtures
// // can take a long time (5-15 secs)
// this.timeout(human('2 minutes'))
if (process.env.NO_EXIT) {
Fixtures.scaffoldWatch()
}
Fixtures.remove()
sinon.stub(process, 'exit')
this.settings = options.settings
if (options.servers) {
const optsServers = [].concat(options.servers)
@@ -690,12 +685,6 @@ const systemTests = {
} else {
this.servers = null
}
const s = options.settings
if (s) {
await settings.write(e2ePath, s)
}
})
afterEach(async function () {
@@ -703,8 +692,6 @@ const systemTests = {
this.timeout(human('2 minutes'))
Fixtures.remove()
const s = this.servers
if (s) {
@@ -725,7 +712,7 @@ const systemTests = {
_.defaults(options, {
browser: 'electron',
headed: process.env.HEADED || false,
project: e2ePath,
project: 'e2e',
timeout: 120000,
originalTitle: null,
expectedExitCode: 0,
@@ -735,6 +722,8 @@ const systemTests = {
inspectBrk: process.env.CYPRESS_INSPECT_BRK,
})
const projectPath = Fixtures.projectPath(options.project)
if (options.exit != null) {
throw new Error(`
passing { exit: false } to system test options is no longer supported
@@ -760,7 +749,7 @@ const systemTests = {
const specDir = options.testingType === 'component' ? 'component' : 'integration'
return path.join(options.project, 'cypress', specDir, spec)
return path.join(projectPath, 'cypress', specDir, spec)
})
// normalize the path to the spec
@@ -776,7 +765,7 @@ const systemTests = {
const args = [
// hides a user warning to go through NPM module
`--cwd=${serverPath}`,
`--run-project=${options.project}`,
`--run-project=${Fixtures.projectPath(options.project)}`,
`--testingType=${options.testingType || 'e2e'}`,
]
@@ -902,7 +891,7 @@ const systemTests = {
console.log(systemTests.normalizeStdout(result.stdout))
```
*/
exec (ctx, options: ExecOptions) {
async exec (ctx, options: ExecOptions) {
debug('systemTests.exec options %o', options)
options = this.options(ctx, options)
debug('processed options %o', options)
@@ -914,8 +903,18 @@ const systemTests = {
ctx.skip()
}
if (options.stubPackage) {
Fixtures.installStubPackage(options.project, options.stubPackage)
if (!options.skipScaffold) {
await Fixtures.scaffoldCommonNodeModules()
Fixtures.scaffoldProject(options.project)
await Fixtures.scaffoldProjectNodeModules(options.project)
}
if (process.env.NO_EXIT) {
Fixtures.scaffoldWatch()
}
if (ctx.settings) {
await settings.write(e2ePath, ctx.settings)
}
args = options.args || ['index.js'].concat(args)
@@ -994,70 +993,73 @@ const systemTests = {
}
}
return new Bluebird((resolve, reject) => {
debug('spawning Cypress %o', { args })
const cmd = options.command || 'node'
const sp = cp.spawn(cmd, args, {
env: _.chain(process.env)
.omit('CYPRESS_DEBUG')
.extend({
// FYI: color will be disabled
// because we are piping the child process
COLUMNS: 100,
LINES: 24,
})
.defaults({
// match CircleCI's filesystem limits, so screenshot names in snapshots match
CYPRESS_MAX_SAFE_FILENAME_BYTES: 242,
FAKE_CWD_PATH: '/XXX/XXX/XXX',
DEBUG_COLORS: '1',
// prevent any Compression progress
// messages from showing up
VIDEO_COMPRESSION_THROTTLE: 120000,
// don't fail our own tests running from forked PR's
CYPRESS_INTERNAL_SYSTEM_TESTS: '1',
// Emulate no typescript environment
CYPRESS_INTERNAL_NO_TYPESCRIPT: options.noTypeScript ? '1' : '0',
// disable frame skipping to make quick Chromium tests have matching snapshots/working video
CYPRESS_EVERY_NTH_FRAME: 1,
// force file watching for use with --no-exit
...(options.noExit ? { CYPRESS_INTERNAL_FORCE_FILEWATCH: '1' } : {}),
})
.extend(options.processEnv)
.value(),
...options.spawnOpts,
debug('spawning Cypress %o', { args })
const cmd = options.command || 'node'
const sp = cp.spawn(cmd, args, {
env: _.chain(process.env)
.omit('CYPRESS_DEBUG')
.extend({
// FYI: color will be disabled
// because we are piping the child process
COLUMNS: 100,
LINES: 24,
})
.defaults({
// match CircleCI's filesystem limits, so screenshot names in snapshots match
CYPRESS_MAX_SAFE_FILENAME_BYTES: 242,
FAKE_CWD_PATH: '/XXX/XXX/XXX',
DEBUG_COLORS: '1',
// prevent any Compression progress
// messages from showing up
VIDEO_COMPRESSION_THROTTLE: 120000,
const ColorOutput = function () {
const colorOutput = new stream.Transform()
// don't fail our own tests running from forked PR's
CYPRESS_INTERNAL_SYSTEM_TESTS: '1',
colorOutput._transform = (chunk, encoding, cb) => cb(null, chalk.magenta(chunk.toString()))
// Emulate no typescript environment
CYPRESS_INTERNAL_NO_TYPESCRIPT: options.noTypeScript ? '1' : '0',
return colorOutput
}
// disable frame skipping to make quick Chromium tests have matching snapshots/working video
CYPRESS_EVERY_NTH_FRAME: 1,
// pipe these to our current process
// so we can see them in the terminal
// color it so we can tell which is test output
sp.stdout
.pipe(ColorOutput())
.pipe(process.stdout)
// force file watching for use with --no-exit
...(options.noExit ? { CYPRESS_INTERNAL_FORCE_FILEWATCH: '1' } : {}),
})
.extend(options.processEnv)
.value(),
...options.spawnOpts,
})
sp.stderr
.pipe(ColorOutput())
.pipe(process.stderr)
const ColorOutput = function () {
const colorOutput = new stream.Transform()
sp.stdout.on('data', (buf) => stdout += buf.toString())
sp.stderr.on('data', (buf) => stderr += buf.toString())
colorOutput._transform = (chunk, encoding, cb) => cb(null, chalk.magenta(chunk.toString()))
return colorOutput
}
// pipe these to our current process
// so we can see them in the terminal
// color it so we can tell which is test output
sp.stdout
.pipe(ColorOutput())
.pipe(process.stdout)
sp.stderr
.pipe(ColorOutput())
.pipe(process.stderr)
sp.stdout.on('data', (buf) => stdout += buf.toString())
sp.stderr.on('data', (buf) => stderr += buf.toString())
const exitCode = await new Promise((resolve, reject) => {
sp.on('error', reject)
sp.on('exit', resolve)
})
return sp.on('exit', resolve)
}).tap(copy)
.then(exit)
await copy()
return exit(exitCode)
},
sendHtml (contents) {

View File

@@ -5,6 +5,7 @@
"private": true,
"main": "index.js",
"scripts": {
"projects:yarn:install": "node ./scripts/projects-yarn-install.js",
"test": "node ./scripts/run.js --glob-in-dir=test",
"test:ci": "node ./scripts/run.js"
},
@@ -29,6 +30,7 @@
"babel-loader": "8.1.0",
"bluebird": "3.7.2",
"body-parser": "1.19.0",
"cachedir": "2.3.0",
"chai": "1.10.0",
"chai-as-promised": "7.1.1",
"chai-subset": "1.6.0",
@@ -47,6 +49,7 @@
"express-useragent": "1.0.15",
"fluent-ffmpeg": "2.1.2",
"fs-extra": "8.1.0",
"glob": "7.2.0",
"http-mitm-proxy": "0.7.0",
"https-proxy-agent": "3.0.1",
"human-interval": "1.0.0",

View File

@@ -0,0 +1,7 @@
{
"name": "@test-projects/config-with-custom-file-js",
"version": "0.0.0-test",
"devDependencies": {
"cypress": "file:../../../cli"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ const _ = require('lodash')
const Jimp = require('jimp')
const path = require('path')
const Promise = require('bluebird')
const { useFixedBrowserLaunchSize } = require('../../../utils')
const { useFixedBrowserLaunchSize } = require('@tooling/system-tests/lib/pluginUtils')
const { startDevServer } = require('@cypress/webpack-dev-server')

View File

@@ -0,0 +1,7 @@
{
"name": "@test-project/plugin-retries",
"version": "0.0.0-test",
"devDependencies": {
"cypress-plugin-retries": "1.5.2"
}
}

View File

@@ -0,0 +1,49 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity "sha1-7dgDYornHATIWuegkG7a00tkiTc= sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
dependencies:
color-convert "^2.0.1"
chalk@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
integrity "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ= sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
cypress-plugin-retries@1.5.2:
version "1.5.2"
resolved "https://registry.npmjs.org/cypress-plugin-retries/-/cypress-plugin-retries-1.5.2.tgz#21d5247cd77013b95bbfdd914f2de66f91f76a2e"
integrity "sha1-IdUkfNdwE7lbv92RTy3mb5H3ai4= sha512-o1xVIGtv4WvNVxoVJ2X08eAuvditPHrePRzHqhwwHbMKu3C2rtxCdanRCZdO5fjh8ww+q4v4V0e9GmysbOvu3A=="
dependencies:
chalk "^3.0.0"
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo= sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="
dependencies:
has-flag "^4.0.0"

View File

@@ -1,6 +1,6 @@
/// <reference types="cypress" />
const { useFixedBrowserLaunchSize } = require('../../../utils')
const { useFixedBrowserLaunchSize } = require('@tooling/system-tests/lib/pluginUtils')
/**
* @type {Cypress.PluginConfig}

View File

@@ -0,0 +1,13 @@
{
"name": "@test-project/webpack-preprocessor-ts-loader-compiler-options",
"version": "0.0.0-test",
"devDependencies": {
"@babel/core": "7.9.0",
"@babel/preset-env": "7.9.0",
"@cypress/webpack-preprocessor": "file:../../../npm/webpack-preprocessor",
"babel-loader": "8.1.0",
"cypress": "file:../../../cli",
"ts-loader": "7.0.4",
"typescript": "4.2.3"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
{
"name": "@test-project/webpack-preprocessor-ts-loader",
"version": "0.0.0-test",
"devDependencies": {
"@cypress/webpack-preprocessor": "file:../../../npm/webpack-preprocessor",
"cypress": "file:../../../cli/build",
"ts-loader": "7.0.4",
"typescript": "4.2.3"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
{
"name": "@test-project/webpack-preprocessor",
"version": "0.0.0-test",
"devDependencies": {
"@babel/core": "7.9.0",
"@babel/preset-env": "7.9.0",
"@cypress/webpack-preprocessor": "file:../../../npm/webpack-preprocessor",
"babel-loader": "8.1.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,5 +7,6 @@
"devDependencies": {
"typescript": "^4.2.4"
},
"license": "MIT"
"license": "MIT",
"_cyYarnV2": true
}

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# NOTE: do not wrap this script with `yarn run`, `npm run`, etc., they add their own stdout
# cd to this "scripts" directory
cd "$(dirname "${BASH_SOURCE[0]}")"
cat ../projects/**/{package.json,yarn.lock}

View File

@@ -0,0 +1,37 @@
require('@packages/ts/register')
const path = require('path')
const { promisify } = require('util')
const glob = promisify(require('glob'))
const Fixtures = require('../lib/fixtures')
const logTag = '[update-cache.js]'
const log = (...args) => console.log(logTag, ...args)
;(async () => {
/**
* For all system test projects that have a package.json, check and update
* the node_modules cache using `yarn`.
*/
Fixtures.remove()
const projectsDir = path.join(__dirname, '../projects')
const packageJsons = await glob('**/package.json', {
cwd: projectsDir,
})
log('Found', packageJsons.length, '`package.json` files in `projects`:', packageJsons)
for (const packageJsonPath of packageJsons) {
const project = path.dirname(packageJsonPath)
const timeTag = `${logTag} ${project} node_modules install`
console.time(timeTag)
log('Scaffolding node_modules for', project)
Fixtures.scaffoldProject(project)
await Fixtures.scaffoldProjectNodeModules(project)
console.timeEnd(timeTag)
}
log('Updated node_modules for', packageJsons.length, 'projects.')
})()

View File

@@ -1,5 +1,5 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
import systemTests from '../lib/system-tests'
import browserUtils from '@packages/server/lib/browsers/utils'
const browser = {
@@ -20,7 +20,7 @@ describe('e2e before:browser:launch', () => {
PATH_TO_CHROME_PROFILE,
},
},
project: Fixtures.projectPath('chrome-browser-preferences'),
project: 'chrome-browser-preferences',
snapshot: true,
spec: 'spec.js',
})
@@ -31,8 +31,12 @@ describe('e2e before:browser:launch', () => {
video: false,
},
headed: true,
project: Fixtures.projectPath('browser-extensions'),
project: 'browser-extensions',
sanitizeScreenshotDimensions: true,
snapshot: true,
onRun: async (exec) => {
Fixtures.scaffoldProject('plugin-extension')
await exec()
},
})
})

View File

@@ -2,7 +2,6 @@ const path = require('path')
const { exec } = require('child_process')
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
const launcher = require('@packages/launcher')
const absPath = (pathStr) => {
@@ -26,7 +25,7 @@ describe('e2e launching browsers by path', () => {
it('fails with bad browser path', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('e2e'),
project: 'e2e',
spec: 'simple_spec.js',
browser: '/this/aint/gonna/be/found',
expectedExitCode: 1,
@@ -53,7 +52,7 @@ describe('e2e launching browsers by path', () => {
.then((absPath))
.then((foundPath) => {
return systemTests.exec(this, {
project: Fixtures.projectPath('e2e'),
project: 'e2e',
spec: 'simple_spec.js',
browser: foundPath,
snapshot: true,

View File

@@ -1,14 +1,11 @@
const Fixtures = require('../lib/fixtures')
const systemTests = require('../lib/system-tests').default
const bustedSupportFile = Fixtures.projectPath('busted-support-file')
describe('e2e busted support file', () => {
systemTests.setup()
it('passes', function () {
return systemTests.exec(this, {
project: bustedSupportFile,
project: 'busted-support-file',
sanitizeScreenshotDimensions: true,
snapshot: true,
expectedExitCode: 1,

View File

@@ -1,3 +1,4 @@
const express = require('express')
const fs = require('fs')
const path = require('path')
const Fixtures = require('../lib/fixtures')
@@ -10,6 +11,11 @@ const e2ePath = Fixtures.projectPath('e2e')
let requestsForCache = 0
const onServer = function (app) {
app.use(express.static(e2ePath, {
// force caching to happen
maxAge: 3600000,
}))
app.post('/write/:text', (req, res) => {
const file = path.join(e2ePath, 'index.html')
@@ -23,7 +29,7 @@ const onServer = function (app) {
})
})
return app.get('/cached', (req, res) => {
app.get('/cached', (req, res) => {
requestsForCache += 1
return res
@@ -37,10 +43,6 @@ describe('e2e cache', () => {
servers: {
port: 1515,
onServer,
static: {
// force caching to happen
maxAge: 3600000,
},
},
})

View File

@@ -1,6 +1,5 @@
import mockedEnv from 'mocked-env'
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e cdp', function () {
systemTests.setup()
@@ -18,7 +17,7 @@ describe('e2e cdp', function () {
// NOTE: this test takes almost a minute and is largely redundant with protocol_spec
systemTests.it.skip('fails when remote debugging port cannot be connected to', {
project: Fixtures.projectPath('remote-debugging-port-removed'),
project: 'remote-debugging-port-removed',
spec: 'spec.ts',
browser: 'chrome',
expectedExitCode: 1,
@@ -26,7 +25,7 @@ describe('e2e cdp', function () {
// https://github.com/cypress-io/cypress/issues/5685
systemTests.it('handles disconnections as expected', {
project: Fixtures.projectPath('remote-debugging-disconnect'),
project: 'remote-debugging-disconnect',
spec: 'spec.ts',
browser: 'chrome',
expectedExitCode: 1,

View File

@@ -20,7 +20,7 @@ describe('e2e config', () => {
it('applies defaultCommandTimeout globally', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-short-timeout'),
project: 'config-with-short-timeout',
snapshot: true,
expectedExitCode: 1,
})
@@ -30,7 +30,7 @@ describe('e2e config', () => {
it('throws error when invalid viewportWidth in the configuration file', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-invalid-viewport'),
project: 'config-with-invalid-viewport',
expectedExitCode: 1,
snapshot: true,
})
@@ -38,7 +38,7 @@ describe('e2e config', () => {
it('throws error when invalid browser in the configuration file', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-invalid-browser'),
project: 'config-with-invalid-browser',
expectedExitCode: 1,
snapshot: true,
})
@@ -46,37 +46,38 @@ describe('e2e config', () => {
it('supports global shadow dom inclusion', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('shadow-dom-global-inclusion'),
project: 'shadow-dom-global-inclusion',
})
})
it('supports custom configFile in JavaScript', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-custom-file-js'),
project: 'config-with-custom-file-js',
configFile: 'cypress.config.custom.js',
})
})
it('supports custom configFile in TypeScript', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-custom-file-ts'),
project: 'config-with-custom-file-ts',
configFile: 'cypress.config.custom.ts',
})
})
it('supports custom configFile in a default JavaScript file', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-js'),
project: 'config-with-js',
})
})
it('supports custom configFile in a default TypeScript file', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('config-with-ts'),
project: 'config-with-ts',
})
})
it('throws error when multiple default config file are found in project', function () {
Fixtures.scaffoldProject('pristine')
const projectRoot = Fixtures.projectPath('pristine')
return Promise.all([
@@ -84,7 +85,7 @@ describe('e2e config', () => {
fs.writeFile(path.join(projectRoot, 'cypress.config.ts'), 'export default {}'),
]).then(() => {
return systemTests.exec(this, {
project: projectRoot,
project: 'pristine',
expectedExitCode: 1,
snapshot: true,
})

View File

@@ -4,16 +4,13 @@ const path = require('path')
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
const nonExistentSpec = Fixtures.projectPath('non-existent-spec')
const e2eProject = Fixtures.projectPath('e2e')
describe('e2e plugins', () => {
systemTests.setup()
it('fails when spec does not exist', function () {
return systemTests.exec(this, {
spec: 'spec.js',
project: nonExistentSpec,
project: 'non-existent-spec',
sanitizeScreenshotDimensions: true,
snapshot: true,
expectedExitCode: 1,
@@ -22,6 +19,7 @@ describe('e2e plugins', () => {
it('handles specs with $, &, and + in file name', function () {
const relativeSpecPath = path.join('dir&1%', '%dir2&', 's%p+ec&.js')
const e2eProject = Fixtures.projectPath('e2e')
const specPath = path.join(e2eProject, 'cypress', 'integration', relativeSpecPath)
return fs.outputFile(specPath, 'it(\'passes\', () => {})')

View File

@@ -1,7 +1,6 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
const beforeBrowserLaunchProject = Fixtures.projectPath('plugin-before-browser-launch-deprecation')
const beforeBrowserLaunchProject = 'plugin-before-browser-launch-deprecation'
describe('deprecated before:browser:launch args', () => {
systemTests.setup()

View File

@@ -10,7 +10,7 @@ describe('e2e downloads', () => {
systemTests.setup()
systemTests.it('handles various file downloads', {
project: downloadsProject,
project: 'downloads',
spec: 'downloads_spec.ts',
config: {
video: false,
@@ -18,11 +18,11 @@ describe('e2e downloads', () => {
})
const fileExists = (fileName) => {
return fs.pathExists(path.join(Fixtures.projectPath('downloads'), 'cypress', 'dls', fileName))
return fs.pathExists(path.join(downloadsProject, 'cypress', 'dls', fileName))
}
systemTests.it('allows changing the downloads folder', {
project: Fixtures.projectPath('downloads'),
project: 'downloads',
spec: '*',
config: {
downloadsFolder: 'cypress/dls',
@@ -39,13 +39,13 @@ describe('e2e downloads', () => {
it('trashes downloads between runs', async function () {
await systemTests.exec(this, {
project: downloadsProject,
project: 'downloads',
spec: 'download_csv_spec.ts',
})
// this run should trash the downloads from the above run
await systemTests.exec(this, {
project: downloadsProject,
project: 'downloads',
spec: 'simple_passing_spec.ts',
})
@@ -57,13 +57,13 @@ describe('e2e downloads', () => {
it('does not trash downloads between runs if trashAssetsBeforeRuns: false', async function () {
await systemTests.exec(this, {
project: downloadsProject,
project: 'downloads',
spec: 'download_csv_spec.ts',
})
// this run should _not_ trash the downloads from the above run
await systemTests.exec(this, {
project: downloadsProject,
project: 'downloads',
spec: 'simple_passing_spec.ts',
config: {
trashAssetsBeforeRuns: false,

View File

@@ -1,6 +1,5 @@
import systemTests, { expect } from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
import path from 'path'
const verifyPassedAndFailedAreSame = (expectedFailures) => {
return ({ stdout }) => {
@@ -13,6 +12,10 @@ const verifyPassedAndFailedAreSame = (expectedFailures) => {
describe('e2e error ui', function () {
systemTests.setup()
beforeEach(() => {
Fixtures.scaffoldProject('e2e')
})
;[
'webpack-preprocessor',
'webpack-preprocessor-ts-loader',
@@ -23,7 +26,7 @@ describe('e2e error ui', function () {
]
.forEach((project) => {
systemTests.it(`handles sourcemaps in webpack for project: ${project}`, {
project: Fixtures.projectPath(project),
project,
spec: 'failing_spec.*',
expectedExitCode: 1,
onRun (exec) {
@@ -34,10 +37,12 @@ describe('e2e error ui', function () {
// https://github.com/cypress-io/cypress/issues/16255
systemTests.it('handles errors when integration folder is outside of project root', {
project: path.join(Fixtures.projectPath('integration-outside-project-root'), 'project-root'),
project: 'integration-outside-project-root/project-root',
spec: '../../../integration/failing_spec.js',
expectedExitCode: 1,
onRun (exec) {
Fixtures.scaffoldProject('integration-outside-project-root')
return exec().then(verifyPassedAndFailedAreSame(1))
},
})

View File

@@ -17,7 +17,7 @@ describe('e2e firefox', function () {
// @see https://github.com/cypress-io/cypress/issues/6187
systemTests.it.skip('can run a lot of tests', {
outputPath,
project: Fixtures.projectPath('firefox-memory'),
project: 'firefox-memory',
spec: 'spec.js',
browser: 'firefox',
expectedExitCode: 0,
@@ -54,7 +54,7 @@ describe('e2e firefox', function () {
systemTests.it('launches maximized by default', {
browser: 'firefox',
project: Fixtures.projectPath('screen-size'),
project: 'screen-size',
spec: 'maximized.spec.js',
onRun: async (exec) => {
const { stderr } = await exec({
@@ -73,7 +73,7 @@ describe('e2e firefox', function () {
// https://github.com/cypress-io/cypress/issues/6392
systemTests.it.skip('can run multiple specs', {
browser: 'firefox',
project: Fixtures.projectPath('e2e'),
project: 'e2e',
spec: 'simple_spec.js,simple_passing_spec.js',
})
})

View File

@@ -1,5 +1,4 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e headless', function () {
systemTests.setup()
@@ -81,13 +80,13 @@ describe('e2e headless', function () {
systemTests.it('launches maximized by default in headless mode (1920x1080)', {
headed: false,
project: Fixtures.projectPath('screen-size'),
project: 'screen-size',
spec: 'default_size.spec.js',
})
systemTests.it('launches at DPR 1x', {
headed: false,
project: Fixtures.projectPath('screen-size'),
project: 'screen-size',
spec: 'device_pixel_ratio.spec.js',
})
})

View File

@@ -1,5 +1,4 @@
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
describe('e2e issue 2891', () => {
systemTests.setup()
@@ -7,7 +6,7 @@ describe('e2e issue 2891', () => {
// https://github.com/cypress-io/cypress/issues/2891
it('passes', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('default-layout'),
project: 'default-layout',
spec: 'default_layout_spec.js',
sanitizeScreenshotDimensions: true,
snapshot: true,

View File

@@ -1,5 +1,4 @@
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
describe('e2e issue 8111 iframe input focus', function () {
systemTests.setup()
@@ -8,7 +7,7 @@ describe('e2e issue 8111 iframe input focus', function () {
// this test is dependent on the browser being Chrome headed
// and also having --auto-open-devtools-for-tabs plugins option
// (which pulls focus from main browser window)
project: Fixtures.projectPath('issue-8111-iframe-input'),
project: 'issue-8111-iframe-input',
spec: 'iframe_input_spec.js',
browser: 'chrome',
headed: true,

View File

@@ -13,7 +13,7 @@ describe('max listeners warning spec', () => {
// @see https://github.com/cypress-io/cypress/issues/1305
systemTests.it('does not log MaxEventListeners error', {
browser: 'electron',
project: projectPath,
project: 'max-listeners',
spec: '*',
processEnv: {
CYPRESS_INTERNAL_ENV: 'production',

View File

@@ -16,7 +16,7 @@ describe('e2e new project', () => {
throw new Error('support folder should not exist')
}).catch(() => {
return systemTests.exec(this, {
project: noScaffoldingPath,
project: 'no-scaffolding',
sanitizeScreenshotDimensions: true,
snapshot: true,
})

View File

@@ -1,5 +1,4 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e non-proxied spec', () => {
systemTests.setup()
@@ -10,7 +9,7 @@ describe('e2e non-proxied spec', () => {
video: false,
},
browser: 'chrome',
project: Fixtures.projectPath('non-proxied'),
project: 'non-proxied',
snapshot: true,
})
})

View File

@@ -22,22 +22,25 @@ describe('e2e readonly fs', function () {
}
}
const onRun = (exec) => {
const onRun = async (exec) => {
Fixtures.scaffoldProject('read-only-project-root')
await Fixtures.scaffoldCommonNodeModules()
chmodr(projectPath, 0o500)
return exec().finally(() => {
chmodr(projectPath, 0o777)
})
await exec()
chmodr(projectPath, 0o777)
}
systemTests.it('warns when unable to write to disk', {
project: projectPath,
project: 'read-only-project-root',
expectedExitCode: 1,
spec: 'spec.js',
snapshot: true,
config: {
video: false,
},
skipScaffold: true,
onRun,
})
})

View File

@@ -1,12 +1,11 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e plugin run events', () => {
systemTests.setup()
systemTests.it('sends events', {
browser: 'electron',
project: Fixtures.projectPath('plugin-run-events'),
project: 'plugin-run-events',
spec: '*',
snapshot: true,
config: {
@@ -16,14 +15,14 @@ describe('e2e plugin run events', () => {
systemTests.it('handles video being deleted in after:spec', {
browser: 'electron',
project: Fixtures.projectPath('plugin-after-spec-deletes-video'),
project: 'plugin-after-spec-deletes-video',
spec: '*',
snapshot: true,
})
systemTests.it('fails run if event handler throws', {
browser: 'electron',
project: Fixtures.projectPath('plugin-run-event-throws'),
project: 'plugin-run-event-throws',
spec: '*',
snapshot: true,
expectedExitCode: 1,

View File

@@ -15,7 +15,7 @@ describe('e2e plugins', function () {
systemTests.it('fails when there is an async error at the root', {
browser: 'chrome',
spec: 'app_spec.js',
project: Fixtures.projectPath('plugins-root-async-error'),
project: 'plugins-root-async-error',
expectedExitCode: 1,
onRun (exec) {
return exec().then(({ stdout }) => {
@@ -28,7 +28,7 @@ describe('e2e plugins', function () {
it('fails when there is an async error inside an event handler', function () {
return systemTests.exec(this, {
spec: 'app_spec.js',
project: Fixtures.projectPath('plugins-async-error'),
project: 'plugins-async-error',
sanitizeScreenshotDimensions: true,
snapshot: true,
expectedExitCode: 1,
@@ -43,7 +43,7 @@ describe('e2e plugins', function () {
spec: 'app_spec.js',
env: 'foo=foo,bar=bar',
config: { pageLoadTimeout: 10000 },
project: Fixtures.projectPath('plugin-config'),
project: 'plugin-config',
sanitizeScreenshotDimensions: true,
snapshot: true,
})
@@ -51,14 +51,14 @@ describe('e2e plugins', function () {
it('passes version correctly', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('plugin-config-version'),
project: 'plugin-config-version',
})
})
it('catches invalid viewportWidth returned from plugins', function () {
// the test project returns config object with a bad value
return systemTests.exec(this, {
project: Fixtures.projectPath('plugin-returns-bad-config'),
project: 'plugin-returns-bad-config',
expectedExitCode: 1,
snapshot: true,
})
@@ -66,7 +66,7 @@ describe('e2e plugins', function () {
it('catches invalid browsers list returned from plugins', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('plugin-returns-empty-browsers-list'),
project: 'plugin-returns-empty-browsers-list',
expectedExitCode: 1,
snapshot: true,
})
@@ -74,7 +74,7 @@ describe('e2e plugins', function () {
it('catches invalid browser returned from plugins', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('plugin-returns-invalid-browser'),
project: 'plugin-returns-invalid-browser',
expectedExitCode: 1,
snapshot: true,
})
@@ -82,7 +82,7 @@ describe('e2e plugins', function () {
it('can filter browsers from config', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('plugin-filter-browsers'),
project: 'plugin-filter-browsers',
// the test project filters available browsers
// and returns a list with JUST Electron browser
// and we ask to run in Chrome
@@ -100,7 +100,7 @@ describe('e2e plugins', function () {
browser: 'chrome',
spec: 'app_spec.js',
headed: true,
project: Fixtures.projectPath('plugin-extension'),
project: 'plugin-extension',
sanitizeScreenshotDimensions: true,
snapshot: true,
})
@@ -116,13 +116,13 @@ describe('e2e plugins', function () {
'cypress/plugins/index.js',
),
},
project: pluginsAbsolutePath,
project: 'plugins-absolute-path',
sanitizeScreenshotDimensions: true,
snapshot: true,
})
})
const pluginAfterScreenshot = Fixtures.projectPath('plugin-after-screenshot')
const pluginAfterScreenshot = 'plugin-after-screenshot'
it('calls after:screenshot for cy.screenshot() and failure screenshots', function () {
return systemTests.exec(this, {
@@ -146,7 +146,7 @@ describe('e2e plugins', function () {
it('fails when invalid event is registered', function () {
return systemTests.exec(this, {
spec: 'app_spec.js',
project: Fixtures.projectPath('plugin-validation-error'),
project: 'plugin-validation-error',
sanitizeScreenshotDimensions: true,
snapshot: true,
expectedExitCode: 1,
@@ -156,7 +156,7 @@ describe('e2e plugins', function () {
it('fails when there is no function exported', function () {
return systemTests.exec(this, {
spec: 'app_spec.js',
project: Fixtures.projectPath('plugin-empty'),
project: 'plugin-empty',
sanitizeScreenshotDimensions: true,
snapshot: true,
expectedExitCode: 1,
@@ -167,7 +167,7 @@ describe('e2e plugins', function () {
it('passes with working preprocessor', function () {
return systemTests.exec(this, {
spec: 'app_spec.js',
project: Fixtures.projectPath('working-preprocessor'),
project: 'working-preprocessor',
sanitizeScreenshotDimensions: true,
snapshot: true,
})

View File

@@ -360,7 +360,7 @@ describe('e2e record', () => {
trashAssetsBeforeRuns: false,
},
})
.get('stdout'),
.then(({ stdout }) => stdout),
// stagger the 2nd run
// starting up a bit
@@ -380,7 +380,7 @@ describe('e2e record', () => {
trashAssetsBeforeRuns: false,
},
})
.get('stdout')
.then(({ stdout }) => stdout)
}),
])
})

View File

@@ -70,8 +70,7 @@ describe('e2e reporters', () => {
spec: 'simple_passing_spec.js',
reporter: 'reporters/uses-file.js',
})
.get('stdout')
.then((stdout) => {
.then(({ stdout }) => {
expect(stdout).to.include('suite.file: cypress/integration/simple_passing_spec.js')
})
})

View File

@@ -1,5 +1,4 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
const it = systemTests.it
@@ -7,7 +6,7 @@ describe('retries', () => {
systemTests.setup()
it('supports retries', {
project: Fixtures.projectPath('retries-2'),
project: 'retries-2',
spec: 'fail-twice.js',
snapshot: true,
})
@@ -18,9 +17,8 @@ describe('retries', () => {
})
it('warns about retries plugin', {
project: Fixtures.projectPath('plugin-retries'),
project: 'plugin-retries',
spec: 'main.spec.js',
stubPackage: 'cypress-plugin-retries',
snapshot: true,
})
})

View File

@@ -1,5 +1,4 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e runnable execution', () => {
systemTests.setup({
@@ -21,14 +20,14 @@ describe('e2e runnable execution', () => {
// but throws correct error
// https://github.com/cypress-io/cypress/issues/1987
systemTests.it('cannot navigate in before hook and test', {
project: Fixtures.projectPath('hooks-after-rerun'),
project: 'hooks-after-rerun',
spec: 'beforehook-and-test-navigation.js',
snapshot: true,
expectedExitCode: 2,
})
systemTests.it('runnables run correct number of times with navigation', {
project: Fixtures.projectPath('hooks-after-rerun'),
project: 'hooks-after-rerun',
spec: 'runnable-run-count.spec.js',
snapshot: true,
})

View File

@@ -1,5 +1,4 @@
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
describe('e2e specs', () => {
systemTests.setup()
@@ -22,30 +21,24 @@ describe('e2e specs', () => {
// @see https://github.com/cypress-io/cypress/issues/14226
it('handles the same integration and fixtures folders', function () {
const project = Fixtures.projectPath('same-fixtures-integration-folders')
return systemTests.exec(this, {
project,
project: 'same-fixtures-integration-folders',
snapshot: false,
expectedExitCode: 0,
})
})
it('handles the fixtures folder being the subfolder of integration', function () {
const project = Fixtures.projectPath('fixture-subfolder-of-integration')
return systemTests.exec(this, {
project,
project: 'fixture-subfolder-of-integration',
snapshot: false,
expectedExitCode: 0,
})
})
it('handles specs with special characters in the file name', function () {
const project = Fixtures.projectPath('spec-name-special-characters')
return systemTests.exec(this, {
project,
project: 'spec-name-special-characters',
snapshot: false,
expectedExitCode: 0,
})

View File

@@ -1,6 +1,6 @@
import path from 'path'
import systemTests from '../lib/system-tests'
import { projectPath } from '../lib/fixtures'
import Fixtures, { projectPath } from '../lib/fixtures'
import { promises as fs } from 'fs'
const snapshotFile = (project, file, folder = 'integration') => {
@@ -20,7 +20,7 @@ describe.skip('e2e studio', function () {
systemTests.setup()
systemTests.it('extends test', {
project: projectPath('studio'),
project: 'studio',
spec: 'extend.spec.js',
snapshot: true,
browser: 'electron',
@@ -32,7 +32,7 @@ describe.skip('e2e studio', function () {
// includes "New Test" in snapshot
// this is the blank new test that's being created
systemTests.it('creates new test', {
project: projectPath('studio'),
project: 'studio',
spec: 'new.spec.js',
browser: 'electron',
snapshot: true,
@@ -42,7 +42,7 @@ describe.skip('e2e studio', function () {
})
systemTests.it('can write to imported files', {
project: projectPath('studio'),
project: 'studio',
spec: 'external.spec.js',
snapshot: true,
browser: 'electron',
@@ -55,21 +55,25 @@ describe.skip('e2e studio', function () {
})
systemTests.it('extends test without source maps', {
project: projectPath('studio-no-source-maps'),
project: 'studio-no-source-maps',
spec: 'extend.spec.js',
snapshot: true,
browser: 'electron',
onRun (exec) {
Fixtures.scaffoldProject('studio')
return exec().then(() => snapshotFile('studio-no-source-maps', 'extend.spec.js'))
},
})
systemTests.it('creates new test without source maps', {
project: projectPath('studio-no-source-maps'),
project: 'studio-no-source-maps',
spec: 'new.spec.js',
browser: 'electron',
snapshot: true,
onRun (exec) {
Fixtures.scaffoldProject('studio')
return exec().then(() => snapshotFile('studio-no-source-maps', 'new.spec.js'))
},
})

View File

@@ -1,8 +1,5 @@
const systemTests = require('../lib/system-tests').default
const execa = require('execa')
const Fixtures = require('../lib/fixtures')
const systemNode = Fixtures.projectPath('system-node')
let expectedNodeVersion
let expectedNodePath
@@ -18,7 +15,7 @@ describe('e2e system node', () => {
it('uses system node when launching plugins file', async function () {
const { stderr } = await systemTests.exec(this, {
project: systemNode,
project: 'system-node',
userNodePath: expectedNodePath,
userNodeVersion: expectedNodeVersion,
config: {
@@ -40,7 +37,7 @@ describe('e2e system node', () => {
it('uses bundled node when launching plugins file', async function () {
const { stderr } = await systemTests.exec(this, {
project: systemNode,
project: 'system-node',
config: {
nodeVersion: 'bundled',
env: {
@@ -59,7 +56,7 @@ describe('e2e system node', () => {
it('uses default node when launching plugins file', async function () {
const { stderr } = await systemTests.exec(this, {
project: systemNode,
project: 'system-node',
userNodePath: expectedNodePath,
userNodeVersion: expectedNodeVersion,
config: {

View File

@@ -1,12 +1,11 @@
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
describe('e2e task', () => {
systemTests.setup()
it('fails', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('task-not-registered'),
project: 'task-not-registered',
spec: 'task_not_registered_spec.js',
sanitizeScreenshotDimensions: true,
snapshot: true,

View File

@@ -1,5 +1,4 @@
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
describe('e2e task', () => {
systemTests.setup()
@@ -22,7 +21,7 @@ describe('e2e task', () => {
it('merges task events on subsequent registrations and logs warning for conflicts', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('multiple-task-registrations'),
project: 'multiple-task-registrations',
spec: 'multiple_task_registrations_spec.js',
sanitizeScreenshotDimensions: true,
snapshot: true,

View File

@@ -1,33 +1,32 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e typescript in plugins file', function () {
systemTests.setup()
it('handles tsconfig with module other than commonjs', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('ts-proj-with-module-esnext'),
project: 'ts-proj-with-module-esnext',
})
})
// https://github.com/cypress-io/cypress/issues/7575
it('defaults to esModuleInterop: false', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('ts-proj'),
project: 'ts-proj',
})
})
// https://github.com/cypress-io/cypress/issues/7575
it('allows esModuleInterop to be overridden with true via tsconfig.json', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('ts-proj-esmoduleinterop-true'),
project: 'ts-proj-esmoduleinterop-true',
})
})
// https://github.com/cypress-io/cypress/issues/8359
it('loads tsconfig.json from plugins directory', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('ts-proj-tsconfig-in-plugins'),
project: 'ts-proj-tsconfig-in-plugins',
})
})
})

View File

@@ -1,5 +1,4 @@
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
describe('e2e typescript in spec and support file', function () {
systemTests.setup()
@@ -16,15 +15,17 @@ describe('e2e typescript in spec and support file', function () {
spec: 'typescript_syntax_error_spec.ts',
snapshot: true,
expectedExitCode: 1,
onStdout: systemTests.normalizeWebpackErrors,
onStdout: (stdout) => {
stdout = stdout.replace(new RegExp('^(.*)npm/(webpack-batteries-included-preprocessor/node_modules/ts-loader/index.js)$', 'm'), ' * relative/path/to/$2')
return systemTests.normalizeWebpackErrors(stdout)
},
})
})
it('project passes', function () {
const projPath = Fixtures.projectPath('ts-proj')
return systemTests.exec(this, {
project: projPath,
project: 'ts-proj',
snapshot: true,
})
})
@@ -34,7 +35,7 @@ describe('e2e typescript in spec and support file', function () {
// @see https://github.com/cypress-io/cypress/issues/8555
it('respects tsconfig paths', function () {
return systemTests.exec(this, {
project: Fixtures.projectPath('ts-proj-with-paths'),
project: 'ts-proj-with-paths',
})
})
})

View File

@@ -1,14 +1,11 @@
const systemTests = require('../lib/system-tests').default
const Fixtures = require('../lib/fixtures')
const uncaughtSupportFile = Fixtures.projectPath('uncaught-support-file')
describe('e2e uncaught support file errors', () => {
systemTests.setup()
it('failing', function () {
return systemTests.exec(this, {
project: uncaughtSupportFile,
project: 'uncaught-support-file',
sanitizeScreenshotDimensions: true,
snapshot: true,
expectedExitCode: 1,

View File

@@ -49,58 +49,48 @@ describe('e2e video compression', () => {
MS_PER_TEST,
},
},
onRun (exec) {
async onRun (exec) {
process.env.VIDEO_COMPRESSION_THROTTLE = 10
return exec()
.tap(() => {
const videosPath = Fixtures.projectPath('e2e/cypress/videos/*')
const { stdout } = await exec()
const videosPath = Fixtures.projectPath('e2e/cypress/videos/*')
const files = await glob(videosPath)
return glob(videosPath)
.tap(async (files) => {
expect(files).to.have.length(1, `globbed for videos and found: ${files.length}. Expected to find 1 video. Search in videosPath: ${videosPath}.`)
expect(files).to.have.length(1, `globbed for videos and found: ${files.length}. Expected to find 1 video. Search in videosPath: ${videosPath}.`)
const lastFrameFile = path.join(path.dirname(files[0]), 'lastFrame.jpg')
const lastFrameFile = path.join(path.dirname(files[0]), 'lastFrame.jpg')
await outputFinalFrameAsJpg(files[0], lastFrameFile)
// https://github.com/cypress-io/cypress/issues/9265
// if video is seekable and not just one frozen frame, this file should exist
await fs.stat(lastFrameFile).catch((err) => {
throw new Error(`Expected video to have seekable ending frame, but it did not. The video may be corrupted.`)
})
return videoCapture.getCodecData(files[0])
.then(({ duration }) => {
const durationMs = videoCapture.getMsFromDuration(duration)
expect(durationMs).to.be.ok
expect(durationMs).to.be.closeTo(EXPECTED_DURATION_MS, humanInterval('15 seconds'))
})
})
.then((files) => {
return videoCapture.getChapters(files[0])
.then(({ chapters }) => {
// There are 40 chapters but we test only the first one
// because what we want to check is if chapters are added properly.
// In a chapter object, there are properties like 'end' and 'end_time'.
// We don't check them here because they return the test time in milliseconds.
// They cannot be guessed correctly and they can cause flakiness.
expect(chapters[0].id).to.eq(0)
expect(chapters[0].start).to.eq(0)
expect(chapters[0].start_time).to.eq(0)
expect(chapters[0]['TAG:title']).to.eq('num: 1 makes some long tests')
expect(chapters[0].time_base).to.eq('1/1000')
expect(chapters[0].end).to.be.a('number')
expect(Number.isNaN(chapters[0].end)).to.be.false
expect(chapters[0].end_time).to.be.a('number')
expect(Number.isNaN(chapters[0].end_time)).to.be.false
})
})
}).get('stdout')
.then((stdout) => {
expect(stdout).to.match(/Compression progress:\s+\d{1,3}%/)
await outputFinalFrameAsJpg(files[0], lastFrameFile)
// https://github.com/cypress-io/cypress/issues/9265
// if video is seekable and not just one frozen frame, this file should exist
await fs.stat(lastFrameFile).catch((err) => {
throw new Error(`Expected video to have seekable ending frame, but it did not. The video may be corrupted.`)
})
const { duration } = await videoCapture.getCodecData(files[0])
const durationMs = videoCapture.getMsFromDuration(duration)
expect(durationMs).to.be.ok
expect(durationMs).to.be.closeTo(EXPECTED_DURATION_MS, humanInterval('15 seconds'))
const { chapters } = await videoCapture.getChapters(files[0])
// There are 40 chapters but we test only the first one
// because what we want to check is if chapters are added properly.
// In a chapter object, there are properties like 'end' and 'end_time'.
// We don't check them here because they return the test time in milliseconds.
// They cannot be guessed correctly and they can cause flakiness.
expect(chapters[0].id).to.eq(0)
expect(chapters[0].start).to.eq(0)
expect(chapters[0].start_time).to.eq(0)
expect(chapters[0]['TAG:title']).to.eq('num: 1 makes some long tests')
expect(chapters[0].time_base).to.eq('1/1000')
expect(chapters[0].end).to.be.a('number')
expect(Number.isNaN(chapters[0].end)).to.be.false
expect(chapters[0].end_time).to.be.a('number')
expect(Number.isNaN(chapters[0].end_time)).to.be.false
expect(stdout).to.match(/Compression progress:\s+\d{1,3}%/)
},
})
})

View File

@@ -1,53 +1,16 @@
import fs from 'fs-extra'
import os from 'os'
import path from 'path'
import cp from 'child_process'
import util from 'util'
import systemTests from '../lib/system-tests'
import Fixtures from '../lib/fixtures'
const exec = async (cmd, ...args) => {
console.log(`Running "${cmd}"...`)
const ret = await util.promisify(cp.exec)(cmd, ...args)
.catch((err) => {
console.error('Error:', err)
return err
})
console.log('stdout:', ret.stdout)
ret.stderr && console.log('stderr:', ret.stderr)
return ret
}
const fixtureDir = Fixtures.projectPath('yarn-v2-pnp')
const cypressCli = path.join(__dirname, '../../cli/bin/cypress')
const projectDir = Fixtures.projectPath('yarn-v2-pnp')
describe('e2e yarn v2', () => {
let projectDir
beforeEach(async function () {
Fixtures.scaffold()
this.timeout(240000)
// copy yarn-v2 to tmpdir so node_modules resolution won't fall back to project root
projectDir = path.join(os.tmpdir(), `cy-yarn-v2-pnp-${Date.now()}`)
console.log(`projectDir`, projectDir)
await fs.mkdir(projectDir)
await fs.copy(fixtureDir, projectDir)
const projectExec = (cmd) => exec(cmd, { cwd: projectDir })
await projectExec('yarn')
})
systemTests.it('can compile plugin and test specs', {
snapshot: false,
command: 'yarn',
browser: 'electron',
project: 'yarn-v2-pnp',
onRun: async (run) => {
await run({
args: `node ${cypressCli} run --dev --project=./`.split(' '),

View File

@@ -3469,7 +3469,7 @@
"@jest/types@^26.3.0", "@jest/types@^26.6.2":
version "26.6.2"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
@@ -7687,7 +7687,7 @@
"@types/cheerio@*", "@types/cheerio@0.22.21":
version "0.22.21"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.21.tgz#5e37887de309ba11b2e19a6e14cad7874b31a8a3"
resolved "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.21.tgz#5e37887de309ba11b2e19a6e14cad7874b31a8a3"
integrity sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q==
dependencies:
"@types/node" "*"
@@ -7789,7 +7789,7 @@
"@types/enzyme@*", "@types/enzyme@3.10.5":
version "3.10.5"
resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.5.tgz#fe7eeba3550369eed20e7fb565bfb74eec44f1f0"
resolved "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.5.tgz#fe7eeba3550369eed20e7fb565bfb74eec44f1f0"
integrity sha512-R+phe509UuUYy9Tk0YlSbipRpfVtIzb/9BHn5pTEtjJTF5LXvUjrIQcZvNyANNEyFrd2YGs196PniNT1fgvOQA==
dependencies:
"@types/cheerio" "*"
@@ -13280,7 +13280,7 @@ cached-path-relative@^1.0.0, cached-path-relative@^1.0.2:
resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.2.tgz#a13df4196d26776220cc3356eb147a52dba2c6db"
integrity sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==
cachedir@^2.3.0:
cachedir@2.3.0, cachedir@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8"
integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==
@@ -20675,7 +20675,7 @@ glob@7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
glob@7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -20687,6 +20687,18 @@ glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glo
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.2.0, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.2.0"
resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^5.0.15:
version "5.0.15"
resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
@@ -31713,7 +31725,7 @@ pretty-error@^2.0.2, pretty-error@^2.1.1:
pretty-format@26.4.0, pretty-format@^24.9.0, pretty-format@^26.6.2:
version "26.4.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.4.0.tgz#c08073f531429e9e5024049446f42ecc9f933a3b"
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.0.tgz#c08073f531429e9e5024049446f42ecc9f933a3b"
integrity sha512-mEEwwpCseqrUtuMbrJG4b824877pM5xald3AkilJ47Po2YLr97/siejYQHqj2oDQBeJNbu+Q0qUuekJ8F0NAPg==
dependencies:
"@jest/types" "^26.3.0"
@@ -35853,7 +35865,7 @@ socket.io-client@4.0.1:
socket.io-parser@4.0.4, socket.io-parser@~3.3.0, socket.io-parser@~3.4.0, socket.io-parser@~4.0.3, socket.io-parser@~4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0"
resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0"
integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==
dependencies:
"@types/component-emitter" "^1.2.10"
@@ -38501,7 +38513,7 @@ typescript@^4.2.3, typescript@^4.4.4:
ua-parser-js@0.7.24, ua-parser-js@^0.7.18:
version "0.7.24"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.24.tgz#8d3ecea46ed4f1f1d63ec25f17d8568105dc027c"
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.24.tgz#8d3ecea46ed4f1f1d63ec25f17d8568105dc027c"
integrity sha512-yo+miGzQx5gakzVK3QFfN0/L9uVhosXBBO7qmnk7c2iw1IhL212wfA3zbnI54B0obGwC/5NWub/iT9sReMx+Fw==
uc.micro@^1.0.1, uc.micro@^1.0.5:
@@ -39942,7 +39954,7 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
vue-template-compiler@2.6.12, vue-template-compiler@^2.6.11:
version "2.6.12"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
resolved "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
integrity sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==
dependencies:
de-indent "^1.0.2"