mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-03 21:40:28 -05:00
@@ -42,7 +42,3 @@ npm/webpack-preprocessor/examples/use-babelrc/cypress/integration/spec.js
|
||||
**/.git
|
||||
|
||||
/npm/react/bin/*
|
||||
/npm/react/**/coverage
|
||||
**/.next/**
|
||||
/npm/create-cypress-tests/initial-template
|
||||
/npm/create-cypress-tests/**/*.template.*
|
||||
|
||||
+1
-5
@@ -26,7 +26,7 @@ npm/**/cypress/screenshots
|
||||
# from example
|
||||
packages/example/app
|
||||
packages/example/build
|
||||
packages/example/cypress/integration
|
||||
packages/example/cypress
|
||||
|
||||
# from server
|
||||
packages/server/.cy
|
||||
@@ -39,10 +39,6 @@ packages/server/test/support/fixtures/server/libs
|
||||
/npm/react/bin/*
|
||||
/npm/react/cypress/videos
|
||||
|
||||
# from npm/create-cypress-tests
|
||||
/npm/create-cypress-tests/initial-template
|
||||
/npm/create-cypress-tests/src/test-output
|
||||
|
||||
# Building app binary
|
||||
scripts/support
|
||||
package-lock.json
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- v6.0-release
|
||||
- revert-create-cypress-tests
|
||||
- /win*/
|
||||
|
||||
# https://www.appveyor.com/docs/lang/nodejs-iojs/
|
||||
|
||||
-15
@@ -958,17 +958,6 @@ jobs:
|
||||
command: yarn test
|
||||
working_directory: npm/react/<<parameters.path>>
|
||||
|
||||
|
||||
npm-create-cypress-tests:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: yarn workspace create-cypress-tests build
|
||||
- run:
|
||||
name: Run unit test
|
||||
command: yarn workspace create-cypress-tests test
|
||||
|
||||
npm-eslint-plugin-dev:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -1799,10 +1788,6 @@ linux-workflow: &linux-workflow
|
||||
requires:
|
||||
- npm-react
|
||||
|
||||
- npm-create-cypress-tests:
|
||||
requires:
|
||||
- build
|
||||
|
||||
- npm-eslint-plugin-dev:
|
||||
requires:
|
||||
- build
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"cypress",
|
||||
"@cypress/dev"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/general",
|
||||
"plugin:@cypress/dev/tests"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": {
|
||||
"cypress/globals": true
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"mocha/no-global-tests": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"lib/*"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"**/*.json"
|
||||
],
|
||||
"rules": {
|
||||
"quotes": "off",
|
||||
"comma-dangle": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"watch-ignore": [
|
||||
"node_modules"
|
||||
],
|
||||
"require": "ts-node/register",
|
||||
"exit": true
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
./src/
|
||||
./initial-template/
|
||||
scripts/
|
||||
__snapshots__/
|
||||
@@ -1,52 +0,0 @@
|
||||
# Create Cypress Tests
|
||||
|
||||
Installs and injects all the required configuration to run cypress tests.
|
||||
|
||||
## Quick overview
|
||||
|
||||
```
|
||||
cd my-app
|
||||
npx create-cypress-test
|
||||
npx cypress open
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Package manager
|
||||
|
||||
This wizard will automatically determine which package do you use. If `yarn` available as global dependency it will use yarn to install dependencies and create lock file.
|
||||
|
||||
If you need to use `npm` over `yarn` you can do the following
|
||||
|
||||
```
|
||||
npx create-cypress-tests --use-npm
|
||||
```
|
||||
|
||||
By the way you can use yarn to run the installation wizard 😉
|
||||
|
||||
```
|
||||
yarn create cypress tests
|
||||
```
|
||||
|
||||
## Typescript
|
||||
|
||||
This package will also automatically determine if typescript if available in this project and inject the required typescript configuration for cypress. If you are starting a new project and want to create typescript configuration, please do the following:
|
||||
|
||||
```
|
||||
npm init
|
||||
npm install typescript
|
||||
npx create-cypress-tests
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Here is a list of available configuration options:
|
||||
|
||||
`--use-npm` – use npm if yarn available
|
||||
`--ignore-typescript` – will not create typescript configuration if available
|
||||
`--ignore-examples` – will create a 1 empty spec file (`cypress/integration/spec.js`) to start with
|
||||
`--component-tests` – will not ask should setup component testing or not
|
||||
|
||||
## License
|
||||
|
||||
The project is licensed under the terms of [MIT license](../../LICENSE)
|
||||
@@ -1,10 +0,0 @@
|
||||
exports['babel installation template correctly generates plugins config 1'] = `
|
||||
const preprocessor = require('@cypress/react/plugins/babel');
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
@@ -1,50 +0,0 @@
|
||||
exports['Injects guessed next.js template cypress.json'] = `
|
||||
const preprocessor = require("@cypress/react/plugins/next");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
|
||||
`
|
||||
|
||||
exports['Injects guessed next.js template plugins/index.js'] = `
|
||||
const preprocessor = require("@cypress/react/plugins/next");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
|
||||
`
|
||||
|
||||
exports['Injects guessed next.js template support/index.js'] = `
|
||||
import "@cypress/react/support";
|
||||
|
||||
`
|
||||
|
||||
exports['Injected overridden webpack template cypress.json'] = `
|
||||
const preprocessor = require("@cypress/react/plugins/react-scripts");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
|
||||
`
|
||||
|
||||
exports['Injected overridden webpack template plugins/index.js'] = `
|
||||
const preprocessor = require("@cypress/react/plugins/react-scripts");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
|
||||
`
|
||||
|
||||
exports['Injected overridden webpack template support/index.js'] = `
|
||||
import "./commands.js";
|
||||
import "@cypress/react/support";
|
||||
|
||||
`
|
||||
@@ -1,10 +0,0 @@
|
||||
exports['next.js install template correctly generates plugins config 1'] = `
|
||||
const preprocessor = require('@cypress/react/plugins/next');
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
@@ -1,10 +0,0 @@
|
||||
exports['create-react-app install template correctly generates plugins config 1'] = `
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts');
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
@@ -1,24 +0,0 @@
|
||||
exports['webpack-file install template correctly generates plugins config when webpack config path is missing 1'] = `
|
||||
const preprocessor = require("@cypress/react/plugins/load-webpack");
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
// TODO replace with valid webpack config path
|
||||
config.env.webpackFilename = './webpack.config.js';
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
|
||||
exports['webpack-file install template correctly generates plugins config when webpack config path is provided 1'] = `
|
||||
const preprocessor = require("@cypress/react/plugins/load-webpack");
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
config.env.webpackFilename = 'config/webpack.config.js';
|
||||
preprocessor(on, config);
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
@@ -1,32 +0,0 @@
|
||||
exports['rollup-file install template correctly generates plugins config when webpack config path is missing 1'] = `
|
||||
const rollupPreprocessor = require("@bahmutov/cy-rollup");
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on('file:preprocessor', rollupPreprocessor({
|
||||
// TODO replace with valid rollup config path
|
||||
configFile: 'rollup.config.js'
|
||||
}));
|
||||
|
||||
require('@cypress/code-coverage/task')(on, config);
|
||||
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
|
||||
exports['rollup-file install template correctly generates plugins config when webpack config path is provided 1'] = `
|
||||
const rollupPreprocessor = require("@bahmutov/cy-rollup");
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on('file:preprocessor', rollupPreprocessor({
|
||||
configFile: 'config/rollup.config.js'
|
||||
}));
|
||||
|
||||
require('@cypress/code-coverage/task')(on, config);
|
||||
|
||||
return config; // IMPORTANT to return the config object
|
||||
};
|
||||
`
|
||||
@@ -1,11 +0,0 @@
|
||||
exports['vue webpack-file install template correctly generates plugins for vue-cli-service 1'] = `
|
||||
const preprocessor = require("@cypress/vue/dist/plugins/webpack");
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config); // IMPORTANT return the config object
|
||||
|
||||
return config;
|
||||
};
|
||||
`
|
||||
@@ -1,24 +0,0 @@
|
||||
exports['vue webpack-file install template correctly generates plugins config when webpack config path is missing 1'] = `
|
||||
const {
|
||||
onFilePreprocessor
|
||||
} = require('@cypress/vue/dist/preprocessor/webpack');
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
// TODO replace with valid webpack config path
|
||||
on('file:preprocessor', onFilePreprocessor('./webpack.config.js'));
|
||||
};
|
||||
`
|
||||
|
||||
exports['vue webpack-file install template correctly generates plugins config when webpack config path is provided 1'] = `
|
||||
const {
|
||||
onFilePreprocessor
|
||||
} = require('@cypress/vue/dist/preprocessor/webpack');
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on('file:preprocessor', onFilePreprocessor('build/webpack.config.js'));
|
||||
};
|
||||
`
|
||||
@@ -1,29 +0,0 @@
|
||||
exports['webpack-options template correctly generates plugins config 1'] = `
|
||||
const webpackPreprocessor = require("@cypress/webpack-preprocessor");
|
||||
|
||||
const something = require("something");
|
||||
|
||||
module.exports = (on, config) => {
|
||||
const opts = webpackPreprocessor.defaultOptions;
|
||||
const babelLoader = opts.webpackOptions.module.rules[0].use[0]; // add React preset to be able to transpile JSX
|
||||
|
||||
babelLoader.options.presets.push(require.resolve('@babel/preset-react')); // We can also push Babel istanbul plugin to instrument the code on the fly
|
||||
// and get code coverage reports from component tests (optional)
|
||||
|
||||
if (!babelLoader.options.plugins) {
|
||||
babelLoader.options.plugins = [];
|
||||
}
|
||||
|
||||
babelLoader.options.plugins.push(require.resolve('babel-plugin-istanbul')); // in order to mock named imports, need to include a plugin
|
||||
|
||||
babelLoader.options.plugins.push([require.resolve('@babel/plugin-transform-modules-commonjs'), {
|
||||
loose: true
|
||||
}]); // add code coverage plugin
|
||||
|
||||
require('@cypress/code-coverage/task')(on, config);
|
||||
|
||||
on('file:preprocessor', webpackPreprocessor(opts)); // if adding code coverage, important to return updated config
|
||||
|
||||
return config;
|
||||
};
|
||||
`
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 MiB |
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "create-cypress-tests",
|
||||
"version": "0.0.0-development",
|
||||
"description": "Cypress smart installation wizard",
|
||||
"private": false,
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "yarn prepare-example && tsc -p ./tsconfig.json && chmod +x dist/src/index.js && node scripts/example copy-to ./dist/initial-template",
|
||||
"prepare-example": "node scripts/example copy-to ./initial-template",
|
||||
"test": "cross-env TS_NODE_PROJECT=./tsconfig.test.json mocha --config .mocharc.json './src/**/*.test.ts'",
|
||||
"test:watch": "yarn test -w"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.5.4",
|
||||
"@babel/plugin-transform-typescript": "^7.2.0",
|
||||
"@babel/template": "^7.5.4",
|
||||
"@babel/types": "^7.5.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-highlight": "2.1.4",
|
||||
"commander": "6.1.0",
|
||||
"find-up": "5.0.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"glob": "^7.1.6",
|
||||
"inquirer": "7.3.3",
|
||||
"ora": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/babel__core": "^7.1.2",
|
||||
"@types/inquirer": "7.3.1",
|
||||
"@types/mock-fs": "4.10.0",
|
||||
"@types/node": "9.6.49",
|
||||
"@types/ora": "^3.2.0",
|
||||
"mocha": "7.1.1",
|
||||
"mock-fs": "4.13.0",
|
||||
"typescript": "4.0.3"
|
||||
},
|
||||
"bin": {
|
||||
"create-cypress-tests": "dist/src/index.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/cypress-io/cypress.git",
|
||||
"author": "Cypress.io team"
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
const fs = require('fs-extra')
|
||||
const chalk = require('chalk')
|
||||
const path = require('path')
|
||||
const program = require('commander')
|
||||
|
||||
program
|
||||
.command('copy-to [destination]')
|
||||
.description('copy cypress/packages/example into destination')
|
||||
.action(async (destination) => {
|
||||
const exampleFolder = path.resolve(__dirname, '..', '..', '..', 'packages', 'example')
|
||||
const destinationPath = path.resolve(process.cwd(), destination)
|
||||
|
||||
await fs.remove(destinationPath)
|
||||
await fs.copy(exampleFolder, destinationPath, { recursive: true })
|
||||
|
||||
console.log(`✅ Example was successfully created at ${chalk.cyan(destination)}`)
|
||||
})
|
||||
|
||||
program.parse(process.argv)
|
||||
@@ -1,85 +0,0 @@
|
||||
import * as babel from '@babel/core'
|
||||
import { expect } from 'chai'
|
||||
import { createSupportBabelPlugin, createTransformPluginsFileBabelPlugin } from './babelTransform'
|
||||
|
||||
describe('babel transform utils', () => {
|
||||
context('support babel template', () => {
|
||||
it('injects import after the last import in the file', () => {
|
||||
const plugin = createSupportBabelPlugin('import "@cypress/react"')
|
||||
|
||||
const output = babel.transformSync([
|
||||
'import "./commands.js"',
|
||||
].join('\n'), {
|
||||
plugins: [plugin],
|
||||
})?.code
|
||||
|
||||
expect(output).to.equal([
|
||||
'import "./commands.js";',
|
||||
'import "@cypress/react";',
|
||||
].join('\n'))
|
||||
})
|
||||
|
||||
it('injects import after the last import if a lot of imports and code inside', () => {
|
||||
const plugin = createSupportBabelPlugin('import "@cypress/react"')
|
||||
|
||||
const output = babel.transformSync([
|
||||
'import "./commands.js";',
|
||||
'import "./commands4.js";',
|
||||
'import "./commands3.js";',
|
||||
'import "./commands2.js";',
|
||||
'',
|
||||
'function hello() {',
|
||||
' console.log("world");',
|
||||
'}',
|
||||
].join('\n'), {
|
||||
plugins: [plugin],
|
||||
})?.code
|
||||
|
||||
expect(output).to.equal([
|
||||
'import "./commands.js";',
|
||||
'import "./commands4.js";',
|
||||
'import "./commands3.js";',
|
||||
'import "./commands2.js";',
|
||||
'import "@cypress/react";',
|
||||
'',
|
||||
'function hello() {',
|
||||
' console.log("world");',
|
||||
'}',
|
||||
].join('\n'))
|
||||
})
|
||||
|
||||
it('adds import as 1st line if no imports or require found', () => {
|
||||
const plugin = createSupportBabelPlugin('import "@cypress/react"')
|
||||
|
||||
const output = babel.transformSync('', { plugins: [plugin] })?.code
|
||||
|
||||
expect(output).to.equal('import "@cypress/react";')
|
||||
})
|
||||
})
|
||||
|
||||
context('Plugins config babel plugin', () => {
|
||||
it('injects code into the plugins file based on ast', () => {
|
||||
const plugin = createTransformPluginsFileBabelPlugin({
|
||||
Require: babel.template.ast('require("something")'),
|
||||
ModuleExportsBody: babel.template.ast('yey()'),
|
||||
})
|
||||
|
||||
const output = babel.transformSync([
|
||||
'module.exports = (on, config) => {',
|
||||
'on("do")',
|
||||
'}',
|
||||
].join('\n'), {
|
||||
plugins: [plugin],
|
||||
})?.code
|
||||
|
||||
expect(output).to.equal([
|
||||
'require("something");',
|
||||
'',
|
||||
'module.exports = (on, config) => {',
|
||||
' on("do");',
|
||||
' yey();',
|
||||
'};',
|
||||
].join(`\n`))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,147 +0,0 @@
|
||||
import path from 'path'
|
||||
import * as fs from 'fs-extra'
|
||||
import * as babel from '@babel/core'
|
||||
import * as babelTypes from '@babel/types'
|
||||
|
||||
export type PluginsConfigAst = Record<'Require' | 'ModuleExportsBody', ReturnType<typeof babel.template.ast>>
|
||||
|
||||
function tryRequirePrettier () {
|
||||
try {
|
||||
return require('prettier')
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function transformFileViaPlugin (filePath: string, babelPlugin: babel.PluginObj) {
|
||||
try {
|
||||
const initialCode = await fs.readFile(filePath, { encoding: 'utf-8' })
|
||||
|
||||
const updatedResult = await babel.transformAsync(initialCode, {
|
||||
filename: path.basename(filePath),
|
||||
filenameRelative: path.relative(process.cwd(), filePath),
|
||||
plugins: [babelPlugin],
|
||||
presets: [],
|
||||
})
|
||||
|
||||
if (!updatedResult) {
|
||||
return false
|
||||
}
|
||||
|
||||
let finalCode = updatedResult.code
|
||||
|
||||
if (finalCode === initialCode) {
|
||||
return false
|
||||
}
|
||||
|
||||
const maybePrettier = tryRequirePrettier()
|
||||
|
||||
if (maybePrettier && maybePrettier.format) {
|
||||
finalCode = maybePrettier.format(finalCode, { parser: 'babel' })
|
||||
}
|
||||
|
||||
await fs.writeFile(filePath, finalCode)
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function createTransformPluginsFileBabelPlugin (ast: PluginsConfigAst): babel.PluginObj {
|
||||
return {
|
||||
visitor: {
|
||||
Program: (path) => {
|
||||
path.unshiftContainer('body', ast.Require)
|
||||
},
|
||||
Function: (path) => {
|
||||
if (!babelTypes.isAssignmentExpression(path.parent)) {
|
||||
return
|
||||
}
|
||||
|
||||
const assignment = path.parent.left
|
||||
|
||||
const isModuleExports =
|
||||
babelTypes.isMemberExpression(assignment)
|
||||
&& babelTypes.isIdentifier(assignment.object)
|
||||
&& assignment.object.name === 'module'
|
||||
&& babelTypes.isIdentifier(assignment.property)
|
||||
&& assignment.property.name === 'exports'
|
||||
|
||||
if (isModuleExports && babelTypes.isFunction(path.parent.right)) {
|
||||
const paramsLength = path.parent.right.params.length
|
||||
|
||||
if (paramsLength === 0) {
|
||||
path.parent.right.params.push(babelTypes.identifier('on'))
|
||||
path.parent.right.params.push(babelTypes.identifier('config'))
|
||||
}
|
||||
|
||||
if (paramsLength === 1) {
|
||||
path.parent.right.params.push(babelTypes.identifier('config'))
|
||||
}
|
||||
|
||||
path.get('body').pushContainer('body' as never, ast.ModuleExportsBody)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function injectPluginsCode (pluginsFilePath: string, ast: PluginsConfigAst) {
|
||||
return transformFileViaPlugin(pluginsFilePath, createTransformPluginsFileBabelPlugin(ast))
|
||||
}
|
||||
|
||||
export async function getPluginsSourceExample (ast: PluginsConfigAst) {
|
||||
const exampleCode = [
|
||||
'module.exports = (on, config) => {',
|
||||
'',
|
||||
'}',
|
||||
].join('\n')
|
||||
|
||||
try {
|
||||
const babelResult = await babel.transformAsync(exampleCode, {
|
||||
filename: 'nothing.js',
|
||||
plugins: [createTransformPluginsFileBabelPlugin(ast)],
|
||||
presets: [],
|
||||
})
|
||||
|
||||
if (!babelResult?.code) {
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
return babelResult.code
|
||||
} catch (e) {
|
||||
throw new Error('Can not generate code example for plugins file because of unhandled error. Please update the plugins file manually.')
|
||||
}
|
||||
}
|
||||
|
||||
export function createSupportBabelPlugin (importCode: string): babel.PluginObj<any> {
|
||||
const template = babel.template.ast(importCode)
|
||||
|
||||
const plugin: babel.PluginObj<{
|
||||
root: babel.NodePath<babel.types.Program>
|
||||
lastImport: babel.NodePath<babel.types.ImportDeclaration> |null
|
||||
}> = {
|
||||
visitor: {
|
||||
Program (path) {
|
||||
this.root = path
|
||||
},
|
||||
ImportDeclaration (path) {
|
||||
this.lastImport = path
|
||||
},
|
||||
},
|
||||
post () {
|
||||
if (this.lastImport) {
|
||||
this.lastImport.insertAfter(template)
|
||||
} else if (this.root) {
|
||||
this.root.unshiftContainer('body', template)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return plugin
|
||||
}
|
||||
|
||||
export async function injectImportSupportCode (supportFilePath: string, importCode: string) {
|
||||
return transformFileViaPlugin(supportFilePath, createSupportBabelPlugin(importCode))
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import snapshot from 'snap-shot-it'
|
||||
import { expect, use } from 'chai'
|
||||
import sinon, { SinonStub, SinonSpy } from 'sinon'
|
||||
import chalk from 'chalk'
|
||||
import mockFs from 'mock-fs'
|
||||
import { initComponentTesting } from './init-component-testing'
|
||||
import inquirer from 'inquirer'
|
||||
import sinonChai from 'sinon-chai'
|
||||
import childProcess from 'child_process'
|
||||
import { someOfSpyCallsIncludes } from '../test-utils'
|
||||
|
||||
use(sinonChai)
|
||||
|
||||
describe('init component tests script', () => {
|
||||
let promptSpy: SinonStub<any> | null = null
|
||||
let logSpy: SinonSpy | null = null
|
||||
let processExitStub: SinonStub<any> | null = null
|
||||
let execStub: SinonStub | null = null
|
||||
|
||||
const e2eTestOutputPath = path.resolve(__dirname, '..', 'test-output')
|
||||
const cypressConfigPath = path.join(e2eTestOutputPath, 'cypress.json')
|
||||
|
||||
beforeEach(async () => {
|
||||
logSpy = sinon.spy(global.console, 'log')
|
||||
// @ts-ignores
|
||||
execStub = sinon.stub(childProcess, 'exec').callsFake((command, callback) => callback())
|
||||
processExitStub = sinon.stub(process, 'exit').callsFake(() => {
|
||||
throw new Error(`${chalk.red('process.exit')} should not be called`)
|
||||
})
|
||||
|
||||
await fs.remove(e2eTestOutputPath)
|
||||
await fs.mkdir(e2eTestOutputPath)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore()
|
||||
logSpy?.restore()
|
||||
promptSpy?.restore()
|
||||
processExitStub?.restore()
|
||||
execStub?.restore()
|
||||
})
|
||||
|
||||
function createTempFiles (tempFiles: Record<string, string>) {
|
||||
Object.entries(tempFiles).forEach(([fileName, content]) => {
|
||||
fs.outputFileSync(
|
||||
path.join(e2eTestOutputPath, fileName),
|
||||
content,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function snapshotGeneratedFiles (name: string) {
|
||||
snapshot(
|
||||
`${name} cypress.json`,
|
||||
fs.readFileSync(
|
||||
path.join(e2eTestOutputPath, 'cypress', 'plugins', 'index.js'),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
)
|
||||
|
||||
snapshot(
|
||||
`${name} plugins/index.js`,
|
||||
fs.readFileSync(
|
||||
path.join(e2eTestOutputPath, 'cypress', 'plugins', 'index.js'),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
)
|
||||
|
||||
snapshot(
|
||||
`${name} support/index.js`,
|
||||
fs.readFileSync(
|
||||
path.join(e2eTestOutputPath, 'cypress', 'support', 'index.js'),
|
||||
{ encoding: 'utf-8' },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
it('determines more presumable configuration to suggest', async () => {
|
||||
createTempFiles({
|
||||
'/cypress.json': '{}',
|
||||
'/cypress/support/index.js': '',
|
||||
'/cypress/plugins/index.js': 'module.exports = (on, config) => {}',
|
||||
// For next.js user will have babel config, but we want to suggest to use the closest config for the application code
|
||||
'/babel.config.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({ dependencies: { react: '^17.x', next: '^9.2.0' } }),
|
||||
})
|
||||
|
||||
promptSpy = sinon.stub(inquirer, 'prompt').returns(Promise.resolve({
|
||||
chosenTemplateName: 'next.js',
|
||||
componentFolder: 'src',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
|
||||
const [{ choices }] = (inquirer.prompt as any).args[0][0]
|
||||
|
||||
expect(choices[0]).to.equal('next.js')
|
||||
snapshotGeneratedFiles('Injects guessed next.js template')
|
||||
})
|
||||
|
||||
it('automatically suggests to the user which config to use', async () => {
|
||||
createTempFiles({
|
||||
'/cypress.json': '{}',
|
||||
'/cypress/support/index.js': 'import "./commands.js";',
|
||||
'/cypress/plugins/index.js': 'module.exports = () => {}',
|
||||
'/package.json': JSON.stringify({
|
||||
dependencies: {
|
||||
react: '^16.10.0',
|
||||
},
|
||||
}),
|
||||
'/webpack.config.js': 'module.exports = { }',
|
||||
})
|
||||
|
||||
promptSpy = sinon.stub(inquirer, 'prompt').returns(Promise.resolve({
|
||||
chosenTemplateName: 'create-react-app',
|
||||
componentFolder: 'cypress/component',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
const [{ choices, message }] = (inquirer.prompt as any).args[0][0]
|
||||
|
||||
expect(choices[0]).to.equal('webpack')
|
||||
expect(message).to.contain(
|
||||
`Press ${chalk.inverse(' Enter ')} to continue with ${chalk.green(
|
||||
'webpack',
|
||||
)} configuration`,
|
||||
)
|
||||
|
||||
snapshotGeneratedFiles('Injected overridden webpack template')
|
||||
})
|
||||
|
||||
it('Asks for preferred bundling tool if can not determine the right one', async () => {
|
||||
createTempFiles({
|
||||
'/cypress.json': '{}',
|
||||
'/webpack.config.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({ dependencies: { } }),
|
||||
})
|
||||
|
||||
promptSpy = sinon.stub(inquirer, 'prompt')
|
||||
.onCall(0)
|
||||
.returns(Promise.resolve({
|
||||
framework: 'vue',
|
||||
}) as any)
|
||||
.onCall(1)
|
||||
.returns(Promise.resolve({
|
||||
chosenTemplateName: 'webpack',
|
||||
componentFolder: 'src',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
|
||||
expect(
|
||||
someOfSpyCallsIncludes(global.console.log, 'We were unable to automatically determine your framework 😿'),
|
||||
).to.be.true
|
||||
})
|
||||
|
||||
it('Asks for framework if more than 1 option was auto detected', async () => {
|
||||
createTempFiles({
|
||||
'/cypress.json': '{}',
|
||||
'/webpack.config.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({ dependencies: { react: '*', vue: '*' } }),
|
||||
})
|
||||
|
||||
promptSpy = sinon.stub(inquirer, 'prompt')
|
||||
.onCall(0)
|
||||
.returns(Promise.resolve({
|
||||
framework: 'vue',
|
||||
}) as any)
|
||||
.onCall(1)
|
||||
.returns(Promise.resolve({
|
||||
chosenTemplateName: 'webpack',
|
||||
componentFolder: 'src',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
|
||||
expect(
|
||||
someOfSpyCallsIncludes(global.console.log, `It looks like all these frameworks: ${chalk.yellow('react, vue')} are available from this directory.`),
|
||||
).to.be.true
|
||||
})
|
||||
|
||||
it('installs the right adapter', () => {
|
||||
|
||||
})
|
||||
|
||||
it('suggest the right instruction based on user template choice', async () => {
|
||||
createTempFiles({
|
||||
'/package.json': JSON.stringify({
|
||||
dependencies: {
|
||||
react: '^16.0.0',
|
||||
},
|
||||
}),
|
||||
'/cypress.json': '{}',
|
||||
})
|
||||
|
||||
promptSpy = sinon.stub(inquirer, 'prompt').returns(Promise.resolve({
|
||||
chosenTemplateName: 'create-react-app',
|
||||
componentFolder: 'src',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
expect(
|
||||
someOfSpyCallsIncludes(
|
||||
global.console.log,
|
||||
'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/react-scripts',
|
||||
),
|
||||
).to.be.true
|
||||
})
|
||||
|
||||
it('suggests right docs example and cypress.json config based on the `componentFolder` answer', async () => {
|
||||
createTempFiles({
|
||||
'/cypress.json': '{}',
|
||||
'/package.json': JSON.stringify({
|
||||
dependencies: {
|
||||
react: '^16.0.0',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
sinon.stub(inquirer, 'prompt').returns(Promise.resolve({
|
||||
chosenTemplateName: 'create-react-app',
|
||||
componentFolder: 'cypress/component',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
|
||||
const injectedCode = fs.readFileSync(path.join(e2eTestOutputPath, 'cypress.json'), { encoding: 'utf-8' })
|
||||
|
||||
expect(injectedCode).to.equal(JSON.stringify(
|
||||
{
|
||||
experimentalComponentTesting: true,
|
||||
componentFolder: 'cypress/component',
|
||||
testFiles: '**/*.spec.{js,ts,jsx,tsx}',
|
||||
},
|
||||
null,
|
||||
2,
|
||||
))
|
||||
})
|
||||
|
||||
it('Shows help message if cypress files are not created', async () => {
|
||||
createTempFiles({
|
||||
'/cypress.json': '{}',
|
||||
'/package.json': JSON.stringify({
|
||||
dependencies: {
|
||||
react: '^16.0.0',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
sinon.stub(inquirer, 'prompt').returns(Promise.resolve({
|
||||
chosenTemplateName: 'create-react-app',
|
||||
componentFolder: 'cypress/component',
|
||||
}) as any)
|
||||
|
||||
await initComponentTesting({ config: {}, cypressConfigPath, useYarn: true })
|
||||
|
||||
expect(
|
||||
someOfSpyCallsIncludes(
|
||||
global.console.log,
|
||||
'was not updated automatically. Please add the following config manually:',
|
||||
),
|
||||
).to.be.true
|
||||
})
|
||||
})
|
||||
@@ -1,216 +0,0 @@
|
||||
import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import chalk from 'chalk'
|
||||
import inquirer from 'inquirer'
|
||||
import highlight from 'cli-highlight'
|
||||
import { Template } from './templates/Template'
|
||||
import { guessTemplate } from './templates/guessTemplate'
|
||||
import { installFrameworkAdapter } from './installFrameworkAdapter'
|
||||
import { injectImportSupportCode, injectPluginsCode, getPluginsSourceExample } from './babel/babelTransform'
|
||||
|
||||
async function injectOrShowConfigCode (injectFn: () => Promise<boolean>, {
|
||||
code,
|
||||
filePath,
|
||||
fallbackFileMessage,
|
||||
language,
|
||||
}: {
|
||||
code: string
|
||||
filePath: string
|
||||
language: string
|
||||
fallbackFileMessage: string
|
||||
}) {
|
||||
const fileExists = fs.existsSync(filePath)
|
||||
const readableFilePath = fileExists ? path.relative(process.cwd(), filePath) : fallbackFileMessage
|
||||
|
||||
const printCode = () => {
|
||||
console.log()
|
||||
console.log(highlight(code, { language }))
|
||||
console.log()
|
||||
}
|
||||
|
||||
const printSuccess = () => {
|
||||
console.log(`✅ ${chalk.bold.green(readableFilePath)} was updated with the following config:`)
|
||||
printCode()
|
||||
}
|
||||
|
||||
const printFailure = () => {
|
||||
console.log(`❌ ${chalk.bold.red(readableFilePath)} was not updated automatically. Please add the following config manually: `)
|
||||
printCode()
|
||||
}
|
||||
|
||||
if (!fileExists) {
|
||||
printFailure()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// something get completely wrong when using babel or something. Print error message.
|
||||
const injected = await injectFn().catch(() => false)
|
||||
|
||||
injected ? printSuccess() : printFailure()
|
||||
}
|
||||
|
||||
async function injectAndShowCypressJsonConfig (
|
||||
cypressJsonPath: string,
|
||||
componentFolder: string,
|
||||
) {
|
||||
const configToInject = {
|
||||
experimentalComponentTesting: true,
|
||||
componentFolder,
|
||||
testFiles: '**/*.spec.{js,ts,jsx,tsx}',
|
||||
}
|
||||
|
||||
async function autoInjectCypressJson () {
|
||||
const currentConfig = JSON.parse(await fs.readFile(cypressJsonPath, { encoding: 'utf-8' }))
|
||||
|
||||
await fs.writeFile(cypressJsonPath, JSON.stringify({
|
||||
...currentConfig,
|
||||
...configToInject,
|
||||
}, null, 2))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
await injectOrShowConfigCode(autoInjectCypressJson, {
|
||||
code: JSON.stringify(configToInject, null, 2),
|
||||
language: 'js',
|
||||
filePath: cypressJsonPath,
|
||||
fallbackFileMessage: 'cypress.json config file',
|
||||
})
|
||||
}
|
||||
|
||||
async function injectAndShowSupportConfig (supportFilePath: string, framework: string) {
|
||||
const importCode = framework === 'vue'
|
||||
? `import '@cypress/vue/dist/support'` // todo change vue bundle to output the right declaration
|
||||
: `import \'@cypress/${framework}/support\'`
|
||||
|
||||
await injectOrShowConfigCode(() => injectImportSupportCode(supportFilePath, importCode), {
|
||||
code: importCode,
|
||||
language: 'js',
|
||||
filePath: supportFilePath,
|
||||
fallbackFileMessage: 'support file (https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests.html#Support-file)',
|
||||
})
|
||||
}
|
||||
|
||||
async function injectAndShowPluginConfig<T> (template: Template<T>, {
|
||||
templatePayload,
|
||||
pluginsFilePath,
|
||||
cypressProjectRoot,
|
||||
}: {
|
||||
templatePayload: T | null
|
||||
pluginsFilePath: string
|
||||
cypressProjectRoot: string
|
||||
}) {
|
||||
const ast = template.getPluginsCodeAst(templatePayload, { cypressProjectRoot })
|
||||
|
||||
await injectOrShowConfigCode(() => injectPluginsCode(pluginsFilePath, ast), {
|
||||
code: await getPluginsSourceExample(ast),
|
||||
language: 'js',
|
||||
filePath: pluginsFilePath,
|
||||
fallbackFileMessage: 'plugins file (https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests.html#Plugin-files)',
|
||||
})
|
||||
}
|
||||
|
||||
type InitComponentTestingOptions = {
|
||||
config: Record<string, string>
|
||||
cypressConfigPath: string
|
||||
useYarn: boolean
|
||||
}
|
||||
|
||||
export async function initComponentTesting<T> ({ config, useYarn, cypressConfigPath }: InitComponentTestingOptions) {
|
||||
const cypressProjectRoot = path.resolve(cypressConfigPath, '..')
|
||||
|
||||
const framework = await installFrameworkAdapter(cypressProjectRoot, { useYarn })
|
||||
const {
|
||||
possibleTemplates,
|
||||
defaultTemplate,
|
||||
defaultTemplateName,
|
||||
templatePayload,
|
||||
} = await guessTemplate<T>(framework, cypressProjectRoot)
|
||||
|
||||
const pluginsFilePath = path.resolve(
|
||||
cypressProjectRoot,
|
||||
config.pluginsFile ?? './cypress/plugins/index.js',
|
||||
)
|
||||
|
||||
const supportFilePath = path.resolve(
|
||||
cypressProjectRoot,
|
||||
config.supportFile ?? './cypress/support/index.js',
|
||||
)
|
||||
|
||||
const templateChoices = Object.keys(possibleTemplates).sort((key) => {
|
||||
return key === defaultTemplateName ? -1 : 0
|
||||
})
|
||||
|
||||
const {
|
||||
chosenTemplateName,
|
||||
componentFolder,
|
||||
}: Record<string, string> = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'chosenTemplateName',
|
||||
choices: templateChoices,
|
||||
default: defaultTemplate ? 0 : undefined,
|
||||
message: defaultTemplate?.message
|
||||
? `${defaultTemplate?.message}\n\n Press ${chalk.inverse(
|
||||
' Enter ',
|
||||
)} to continue with ${chalk.green(
|
||||
defaultTemplateName,
|
||||
)} configuration or select another template from the list:`
|
||||
: 'We were not able to automatically determine which framework or bundling tool you are using. Please choose one from the list:',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'componentFolder',
|
||||
filter: (input) => input.trim(),
|
||||
validate: (input) => {
|
||||
return input === '' || !/^[a-zA-Z].*/.test(input)
|
||||
? `Directory "${input}" is invalid`
|
||||
: true
|
||||
},
|
||||
message: 'Which folder would you like to use for your component tests?',
|
||||
default: (answers: { chosenTemplateName: keyof typeof possibleTemplates }) => {
|
||||
return possibleTemplates[answers.chosenTemplateName].recommendedComponentFolder
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const chosenTemplate = possibleTemplates[chosenTemplateName] as Template<T>
|
||||
|
||||
console.log()
|
||||
console.log(`Here are instructions of how to get started with component testing for ${chalk.cyan(chosenTemplateName)}:`)
|
||||
console.log()
|
||||
|
||||
await injectAndShowCypressJsonConfig(cypressConfigPath, componentFolder)
|
||||
await injectAndShowSupportConfig(supportFilePath, framework)
|
||||
await injectAndShowPluginConfig(chosenTemplate, {
|
||||
templatePayload,
|
||||
pluginsFilePath,
|
||||
cypressProjectRoot,
|
||||
})
|
||||
|
||||
if (chosenTemplate.printHelper) {
|
||||
chosenTemplate.printHelper()
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Find examples of component tests for ${chalk.green(
|
||||
chosenTemplateName,
|
||||
)} in ${chalk.underline(chosenTemplate.getExampleUrl({ componentFolder }))}.`,
|
||||
)
|
||||
|
||||
if (framework === 'react') {
|
||||
console.log()
|
||||
|
||||
console.log(
|
||||
`Docs for different recipes of bundling tools: ${chalk.bold.underline(
|
||||
'https://github.com/cypress-io/cypress/tree/develop/npm/react/docs/recipes.md',
|
||||
)}`,
|
||||
)
|
||||
}
|
||||
|
||||
// render delimiter
|
||||
console.log()
|
||||
console.log(new Array(process.stdout.columns).fill('═').join(''))
|
||||
console.log()
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import chalk from 'chalk'
|
||||
import inquirer from 'inquirer'
|
||||
import { scanFSForAvailableDependency } from '../findPackageJson'
|
||||
import { installDependency } from '../utils'
|
||||
|
||||
async function guessOrAskForFramework (cwd: string): Promise<'react' | 'vue'> {
|
||||
// please sort this alphabetically
|
||||
const frameworks = {
|
||||
react: () => scanFSForAvailableDependency(cwd, ['react', 'react-dom']),
|
||||
vue: () => scanFSForAvailableDependency(cwd, ['vue']),
|
||||
}
|
||||
|
||||
const guesses = Object.keys(frameworks).filter((framework) => {
|
||||
return frameworks[framework as keyof typeof frameworks]()
|
||||
}) as Array<'react' | 'vue'>
|
||||
|
||||
// found 1 precise guess. Continue
|
||||
if (guesses.length === 1) {
|
||||
const framework = guesses[0]
|
||||
|
||||
console.log(`\nThis project is using ${chalk.bold.cyan(framework)}. Let's install the right adapter:`)
|
||||
|
||||
return framework
|
||||
}
|
||||
|
||||
if (guesses.length === 0) {
|
||||
console.log(`We were unable to automatically determine your framework 😿. ${chalk.grey('Make sure to run this command from the directory where your components located in order to make smart detection works. Or continue with manual setup:')}`)
|
||||
}
|
||||
|
||||
if (guesses.length > 0) {
|
||||
console.log(`It looks like all these frameworks: ${chalk.yellow(guesses.join(', '))} are available from this directory. ${chalk.grey('Make sure to run this command from the directory where your components located in order to make smart detection works. Or continue with manual setup:')}`)
|
||||
}
|
||||
|
||||
const { framework } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'framework',
|
||||
choices: Object.keys(frameworks),
|
||||
message: `Which framework do you use?`,
|
||||
},
|
||||
])
|
||||
|
||||
return framework
|
||||
}
|
||||
|
||||
type InstallAdapterOptions = {
|
||||
useYarn: boolean
|
||||
}
|
||||
|
||||
export async function installFrameworkAdapter (cwd: string, options: InstallAdapterOptions) {
|
||||
const framework = await guessOrAskForFramework(cwd)
|
||||
|
||||
await installDependency(`@cypress/${framework}`, options)
|
||||
|
||||
return framework
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { PluginsConfigAst } from '../babel/babelTransform'
|
||||
|
||||
export interface Template<T = unknown> {
|
||||
message: string
|
||||
getExampleUrl: ({ componentFolder }: { componentFolder: string }) => string
|
||||
recommendedComponentFolder: string
|
||||
test(rootPath: string): { success: boolean, payload?: T }
|
||||
getPluginsCodeAst: (
|
||||
payload: T | null,
|
||||
options: { cypressProjectRoot: string },
|
||||
) => PluginsConfigAst
|
||||
printHelper?: () => void
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { Template } from './Template'
|
||||
import { reactTemplates } from './react'
|
||||
import { vueTemplates } from './vue'
|
||||
|
||||
const allTemplates = {
|
||||
react: reactTemplates,
|
||||
vue: vueTemplates,
|
||||
}
|
||||
|
||||
export async function guessTemplate<T> (framework: keyof typeof allTemplates, cwd: string) {
|
||||
const templates = allTemplates[framework]
|
||||
|
||||
for (const [name, template] of Object.entries(templates)) {
|
||||
const typedTemplate = template as Template<T>
|
||||
const { success, payload } = typedTemplate.test(cwd)
|
||||
|
||||
if (success) {
|
||||
return {
|
||||
defaultTemplate: typedTemplate,
|
||||
defaultTemplateName: name,
|
||||
templatePayload: payload ?? null,
|
||||
possibleTemplates: templates,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
templatePayload: null,
|
||||
defaultTemplate: null,
|
||||
defaultTemplateName: null,
|
||||
possibleTemplates: templates,
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { BabelTemplate } from './babel'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
|
||||
describe('babel installation template', () => {
|
||||
beforeEach(mockFs.restore)
|
||||
|
||||
it('resolves babel.config.json', () => {
|
||||
mockFs({
|
||||
'/babel.config.json': JSON.stringify({
|
||||
presets: [],
|
||||
plugins: [],
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = BabelTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('resolves babel.config.js', () => {
|
||||
mockFs({
|
||||
'/project/babel.config.js':
|
||||
'module.exports = { presets: [], plugins: [] };',
|
||||
'/project/index/package.json': 'dev/null',
|
||||
})
|
||||
|
||||
const { success } = BabelTemplate.test('/project/index')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('resolves babel config from the deep folder', () => {
|
||||
mockFs({
|
||||
'/some/.babelrc': JSON.stringify({
|
||||
presets: [],
|
||||
plugins: [],
|
||||
}),
|
||||
'/some/deep/folder/text.txt': '1',
|
||||
})
|
||||
|
||||
const { success } = BabelTemplate.test('/some/deep/folder')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('fails if no babel config found', () => {
|
||||
mockFs({
|
||||
'/some.txt': '1',
|
||||
})
|
||||
|
||||
const { success } = BabelTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(false)
|
||||
})
|
||||
|
||||
it('resolves babel.config from package.json', () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({
|
||||
babel: {
|
||||
presets: [],
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = BabelTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config', () => snapshotPluginsAstCode(BabelTemplate))
|
||||
})
|
||||
@@ -1,43 +0,0 @@
|
||||
import chalk from 'chalk'
|
||||
import findUp from 'find-up'
|
||||
import * as babel from '@babel/core'
|
||||
import { Template } from '../Template'
|
||||
import { createFindPackageJsonIterator } from '../../../findPackageJson'
|
||||
|
||||
export const BabelTemplate: Template = {
|
||||
message: `It looks like you have babel config defined. We can use it to transpile your components for testing.\n ${chalk.red(
|
||||
'>>',
|
||||
)} This is not a replacement for bundling tool. We will use ${chalk.red(
|
||||
'webpack',
|
||||
)} to bundle the components for testing.`,
|
||||
recommendedComponentFolder: 'cypress/component',
|
||||
getExampleUrl: () => 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/babel',
|
||||
getPluginsCodeAst: () => {
|
||||
return {
|
||||
Require: babel.template.ast('const preprocessor = require(\'@cypress/react/plugins/babel\')'),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
'preprocessor(on, config)',
|
||||
'return config // IMPORTANT to return the config object',
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
test: (cwd) => {
|
||||
const babelConfig = findUp.sync(
|
||||
['babel.config.js', 'babel.config.json', '.babelrc', '.babelrc.json'],
|
||||
{ type: 'file', cwd },
|
||||
)
|
||||
|
||||
if (babelConfig) {
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
// babel config can also be declared in package.json with `babel` key https://babeljs.io/docs/en/configuration#packagejson
|
||||
const packageJsonIterator = createFindPackageJsonIterator(cwd)
|
||||
|
||||
return packageJsonIterator.map(({ babel }) => {
|
||||
return {
|
||||
success: Boolean(babel),
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Template } from '../Template'
|
||||
import { NextTemplate } from './next'
|
||||
import { WebpackTemplate } from './reactWebpackFile'
|
||||
import { ReactScriptsTemplate } from './react-scripts'
|
||||
import { BabelTemplate } from './babel'
|
||||
import { WebpackOptions } from './webpack-options'
|
||||
|
||||
export const reactTemplates: Record<string, Template<any>> = {
|
||||
'create-react-app': ReactScriptsTemplate,
|
||||
'next.js': NextTemplate,
|
||||
webpack: WebpackTemplate,
|
||||
babel: BabelTemplate,
|
||||
'default (webpack options)': WebpackOptions,
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import sinon, { SinonSpy } from 'sinon'
|
||||
import { expect, use } from 'chai'
|
||||
import sinonChai from 'sinon-chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { NextTemplate } from './next'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
|
||||
use(sinonChai)
|
||||
|
||||
describe('next.js install template', () => {
|
||||
let warnSpy: SinonSpy | null = null
|
||||
|
||||
beforeEach(() => {
|
||||
warnSpy = sinon.spy(global.console, 'warn')
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore()
|
||||
warnSpy?.restore()
|
||||
})
|
||||
|
||||
it('finds the closest package.json and checks that next is declared as dependency', () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({
|
||||
dependencies: {
|
||||
next: '^9.2.3',
|
||||
},
|
||||
scripts: {
|
||||
build: 'next',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = NextTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('works if next is declared in the devDependencies as well', () => {
|
||||
mockFs({
|
||||
'./package.json': JSON.stringify({
|
||||
devDependencies: {
|
||||
next: '^9.2.3',
|
||||
},
|
||||
scripts: {
|
||||
build: 'next',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = NextTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('warns and fails if version is not supported', () => {
|
||||
mockFs({
|
||||
'./package.json': JSON.stringify({
|
||||
devDependencies: {
|
||||
next: '^8.2.3',
|
||||
},
|
||||
scripts: {
|
||||
build: 'next',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = NextTemplate.test('i/am/in/some/deep/folder')
|
||||
|
||||
console.log(global.console.warn)
|
||||
expect(success).to.equal(false)
|
||||
|
||||
expect(global.console.warn).to.be.called
|
||||
})
|
||||
|
||||
it('correctly generates plugins config', () => snapshotPluginsAstCode(NextTemplate))
|
||||
})
|
||||
@@ -1,54 +0,0 @@
|
||||
import * as babel from '@babel/core'
|
||||
import { createFindPackageJsonIterator } from '../../../findPackageJson'
|
||||
import { Template } from '../Template'
|
||||
import { validateSemverVersion } from '../../../utils'
|
||||
import { MIN_SUPPORTED_VERSION } from '../../versions'
|
||||
|
||||
export const NextTemplate: Template = {
|
||||
message: 'It looks like you are using next.js.',
|
||||
getExampleUrl: () => {
|
||||
return 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/nextjs'
|
||||
},
|
||||
recommendedComponentFolder: 'cypress/component',
|
||||
getPluginsCodeAst: () => {
|
||||
return {
|
||||
Require: babel.template.ast('const preprocessor = require(\'@cypress/react/plugins/next\')'),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
'preprocessor(on, config)',
|
||||
'return config // IMPORTANT to return the config object',
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
test: (cwd) => {
|
||||
const packageJsonIterator = createFindPackageJsonIterator(cwd)
|
||||
|
||||
return packageJsonIterator.map(({ dependencies, devDependencies }, path) => {
|
||||
if (!dependencies && !devDependencies) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
const allDeps = {
|
||||
...(devDependencies || {}),
|
||||
...(dependencies || {}),
|
||||
} as Record<string, string>
|
||||
|
||||
const nextVersion = allDeps['next']
|
||||
|
||||
if (!nextVersion) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
if (
|
||||
!validateSemverVersion(
|
||||
nextVersion,
|
||||
MIN_SUPPORTED_VERSION['next'],
|
||||
'next.js',
|
||||
)
|
||||
) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
return { success: true }
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import sinon, { SinonSpy } from 'sinon'
|
||||
import { expect, use } from 'chai'
|
||||
import sinonChai from 'sinon-chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { ReactScriptsTemplate } from './react-scripts'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
|
||||
use(sinonChai)
|
||||
|
||||
describe('create-react-app install template', () => {
|
||||
let warnSpy: SinonSpy | null = null
|
||||
|
||||
beforeEach(() => {
|
||||
warnSpy = sinon.spy(global.console, 'warn')
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore()
|
||||
warnSpy?.restore()
|
||||
})
|
||||
|
||||
it('finds the closest package.json and checks that react-scripts is declared as dependency', () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({
|
||||
dependencies: {
|
||||
'react-scripts': '^3.2.3',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = ReactScriptsTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('works if react-scripts is declared in the devDependencies as well', () => {
|
||||
mockFs({
|
||||
'./package.json': JSON.stringify({
|
||||
devDependencies: {
|
||||
'react-scripts': '^3.2.3',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = ReactScriptsTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('warns and fails if version is not supported', () => {
|
||||
mockFs({
|
||||
'./package.json': JSON.stringify({
|
||||
devDependencies: {
|
||||
'react-scripts': '^2.2.3',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = ReactScriptsTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(false)
|
||||
expect(global.console.warn).to.be.called
|
||||
})
|
||||
|
||||
it('correctly generates plugins config', () => snapshotPluginsAstCode(ReactScriptsTemplate))
|
||||
})
|
||||
@@ -1,61 +0,0 @@
|
||||
import chalk from 'chalk'
|
||||
import { createFindPackageJsonIterator } from '../../../findPackageJson'
|
||||
import { Template } from '../Template'
|
||||
import { validateSemverVersion } from '../../../utils'
|
||||
import { MIN_SUPPORTED_VERSION } from '../../versions'
|
||||
import * as babel from '@babel/core'
|
||||
|
||||
export const ReactScriptsTemplate: Template = {
|
||||
recommendedComponentFolder: 'src',
|
||||
message: 'It looks like you are using create-react-app.',
|
||||
getExampleUrl: ({ componentFolder }) => {
|
||||
return componentFolder === 'src'
|
||||
? 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/react-scripts'
|
||||
: 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/react-scripts-folder'
|
||||
},
|
||||
getPluginsCodeAst: () => {
|
||||
return {
|
||||
Require: babel.template.ast('const preprocessor = require(\'@cypress/react/plugins/react-scripts\')'),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
'preprocessor(on, config)',
|
||||
'return config // IMPORTANT to return the config object',
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
test: () => {
|
||||
// TODO also determine ejected create react app
|
||||
const packageJsonIterator = createFindPackageJsonIterator(process.cwd())
|
||||
|
||||
return packageJsonIterator.map(({ dependencies, devDependencies }) => {
|
||||
if (dependencies || devDependencies) {
|
||||
const allDeps = { ...devDependencies, ...dependencies } || {}
|
||||
|
||||
if (!allDeps['react-scripts']) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
if (
|
||||
!validateSemverVersion(
|
||||
allDeps['react-scripts'],
|
||||
MIN_SUPPORTED_VERSION['react-scripts'],
|
||||
)
|
||||
) {
|
||||
console.warn(
|
||||
`It looks like you are using ${chalk.green(
|
||||
'create-react-app',
|
||||
)}, but we support only projects with version ${chalk.bold(
|
||||
MIN_SUPPORTED_VERSION['react-scripts'],
|
||||
)} of react-scripts.`,
|
||||
)
|
||||
|
||||
// yey found the template
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
return { success: true }
|
||||
}
|
||||
|
||||
return { success: false }
|
||||
})
|
||||
},
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
import { WebpackTemplate } from './reactWebpackFile'
|
||||
|
||||
describe('webpack-file install template', () => {
|
||||
afterEach(mockFs.restore)
|
||||
|
||||
it('resolves webpack.config.js', () => {
|
||||
mockFs({
|
||||
'/webpack.config.js': 'module.exports = { }',
|
||||
})
|
||||
|
||||
const { success, payload } = WebpackTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.webpackConfigPath).to.equal('/webpack.config.js')
|
||||
})
|
||||
|
||||
it('finds the closest package.json and tries to fetch webpack config path from scrips', () => {
|
||||
mockFs({
|
||||
'/configs/webpack.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({
|
||||
scripts: {
|
||||
build: 'webpack --config configs/webpack.js',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success, payload } = WebpackTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.webpackConfigPath).to.equal('/configs/webpack.js')
|
||||
})
|
||||
|
||||
it('looks for package.json in the upper folder', () => {
|
||||
mockFs({
|
||||
'/i/am/in/some/deep/folder/withFile': 'test',
|
||||
'/somewhere/configs/webpack.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({
|
||||
scripts: {
|
||||
build: 'webpack --config somewhere/configs/webpack.js',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success, payload } = WebpackTemplate.test(
|
||||
'i/am/in/some/deep/folder',
|
||||
)
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.webpackConfigPath).to.equal('/somewhere/configs/webpack.js')
|
||||
})
|
||||
|
||||
it('returns success:false if cannot find webpack config', () => {
|
||||
mockFs({
|
||||
'/a.js': '1',
|
||||
'/b.js': '2',
|
||||
})
|
||||
|
||||
const { success, payload } = WebpackTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(false)
|
||||
expect(payload).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config when webpack config path is missing', () => {
|
||||
snapshotPluginsAstCode(WebpackTemplate)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config when webpack config path is provided', () => {
|
||||
snapshotPluginsAstCode(WebpackTemplate, { webpackConfigPath: '/config/webpack.config.js' })
|
||||
})
|
||||
})
|
||||
@@ -1,41 +0,0 @@
|
||||
import * as babel from '@babel/core'
|
||||
import path from 'path'
|
||||
import { Template } from '../Template'
|
||||
import { findWebpackConfig } from '../templateUtils'
|
||||
|
||||
export const WebpackTemplate: Template<{ webpackConfigPath: string }> = {
|
||||
message:
|
||||
'It looks like you have custom `webpack.config.js`. We can use it to bundle the components for testing.',
|
||||
getExampleUrl: () => {
|
||||
return 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/webpack-file'
|
||||
},
|
||||
recommendedComponentFolder: 'cypress/component',
|
||||
getPluginsCodeAst: (payload, { cypressProjectRoot }) => {
|
||||
const includeWarnComment = !payload
|
||||
const webpackConfigPath = payload
|
||||
? path.relative(cypressProjectRoot, payload.webpackConfigPath)
|
||||
: './webpack.config.js'
|
||||
|
||||
return {
|
||||
Require: babel.template.ast('const preprocessor = require("@cypress/react/plugins/load-webpack")'),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
includeWarnComment
|
||||
? '// TODO replace with valid webpack config path'
|
||||
: '',
|
||||
`config.env.webpackFilename = '${webpackConfigPath}'`,
|
||||
'preprocessor(on, config)',
|
||||
'return config // IMPORTANT to return the config object',
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
test: (root) => {
|
||||
const webpackConfigPath = findWebpackConfig(root)
|
||||
|
||||
return webpackConfigPath ? {
|
||||
success: true,
|
||||
payload: { webpackConfigPath },
|
||||
} : {
|
||||
success: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
import { RollupTemplate } from './rollup'
|
||||
|
||||
describe('rollup-file install template', () => {
|
||||
afterEach(mockFs.restore)
|
||||
|
||||
it('resolves rollup.config.js', () => {
|
||||
mockFs({
|
||||
'/rollup.config.js': 'module.exports = { }',
|
||||
})
|
||||
|
||||
const { success, payload } = RollupTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.rollupConfigPath).to.equal('/rollup.config.js')
|
||||
})
|
||||
|
||||
it('finds the closest package.json and tries to fetch rollup config path from scrips', () => {
|
||||
mockFs({
|
||||
'/configs/rollup.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({
|
||||
scripts: {
|
||||
build: 'rollup --config configs/rollup.js',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success, payload } = RollupTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.rollupConfigPath).to.equal('/configs/rollup.js')
|
||||
})
|
||||
|
||||
it('looks for package.json in the upper folder', () => {
|
||||
mockFs({
|
||||
'/i/am/in/some/deep/folder/withFile': 'test',
|
||||
'/somewhere/configs/rollup.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({
|
||||
scripts: {
|
||||
build: 'rollup --config somewhere/configs/rollup.js',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success, payload } = RollupTemplate.test('i/am/in/some/deep/folder')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.rollupConfigPath).to.equal('/somewhere/configs/rollup.js')
|
||||
})
|
||||
|
||||
it('returns success:false if cannot find rollup config', () => {
|
||||
mockFs({
|
||||
'/b.js': '2',
|
||||
'/a.js': '1',
|
||||
})
|
||||
|
||||
const { success, payload } = RollupTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(false)
|
||||
expect(payload).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config when webpack config path is missing', () => {
|
||||
snapshotPluginsAstCode(RollupTemplate)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config when webpack config path is provided', () => {
|
||||
snapshotPluginsAstCode(RollupTemplate, { rollupConfigPath: '/config/rollup.config.js' })
|
||||
})
|
||||
})
|
||||
@@ -1,122 +0,0 @@
|
||||
import path from 'path'
|
||||
import chalk from 'chalk'
|
||||
import findUp from 'find-up'
|
||||
import highlight from 'cli-highlight'
|
||||
import { createFindPackageJsonIterator } from '../../../findPackageJson'
|
||||
import { Template } from '../Template'
|
||||
import * as babel from '@babel/core'
|
||||
|
||||
export function extractRollupConfigPathFromScript (script: string) {
|
||||
if (script.includes('rollup ')) {
|
||||
const cliArgs = script.split(' ').map((part) => part.trim())
|
||||
const configArgIndex = cliArgs.findIndex(
|
||||
(arg) => arg === '--config' || arg === '-c',
|
||||
)
|
||||
|
||||
return configArgIndex === -1 ? null : cliArgs[configArgIndex + 1]
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export const RollupTemplate: Template<{ rollupConfigPath: string }> = {
|
||||
message:
|
||||
'It looks like you have custom `rollup.config.js`. We can use it to bundle the components for testing.',
|
||||
getExampleUrl: () => {
|
||||
return 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/rollup'
|
||||
},
|
||||
recommendedComponentFolder: 'src',
|
||||
getPluginsCodeAst: (payload, { cypressProjectRoot }) => {
|
||||
const includeWarnComment = !payload
|
||||
const rollupConfigPath = payload
|
||||
? path.relative(cypressProjectRoot, payload.rollupConfigPath)
|
||||
: 'rollup.config.js'
|
||||
|
||||
return {
|
||||
Require: babel.template.ast('const rollupPreprocessor = require("@bahmutov/cy-rollup")'),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
`on(`,
|
||||
` 'file:preprocessor',`,
|
||||
` rollupPreprocessor({`,
|
||||
includeWarnComment
|
||||
? ' // TODO replace with valid rollup config path'
|
||||
: '',
|
||||
` configFile: '${rollupConfigPath}',`,
|
||||
` }),`,
|
||||
`)`,
|
||||
``,
|
||||
`require('@cypress/code-coverage/task')(on, config)`,
|
||||
`return config // IMPORTANT to return the config object`,
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
printHelper: () => {
|
||||
console.log(
|
||||
`Make sure that it is also required to add some additional configuration to the ${chalk.red(
|
||||
'rollup.config.js',
|
||||
)}. Here is whats required:`,
|
||||
)
|
||||
|
||||
const code = highlight(
|
||||
[
|
||||
`import replace from '@rollup/plugin-replace'`,
|
||||
`import commonjs from '@rollup/plugin-commonjs'`,
|
||||
`import nodeResolve from '@rollup/plugin-node-resolve'`,
|
||||
``,
|
||||
`export default [`,
|
||||
` {`,
|
||||
` plugins: [`,
|
||||
` nodeResolve(),`,
|
||||
` // process @cypress/react-code`,
|
||||
` commonjs(),`,
|
||||
` // required for react sources`,
|
||||
` replace({ 'process.env.NODE_ENV': JSON.stringify('development') }),`,
|
||||
` ]`,
|
||||
` }`,
|
||||
`]`,
|
||||
].join('\n'),
|
||||
{ language: 'js' },
|
||||
)
|
||||
|
||||
console.log(`\n${code}\n`)
|
||||
},
|
||||
test: (root) => {
|
||||
const rollupConfigPath = findUp.sync('rollup.config.js', { cwd: root })
|
||||
|
||||
if (rollupConfigPath) {
|
||||
return {
|
||||
success: true,
|
||||
payload: { rollupConfigPath },
|
||||
}
|
||||
}
|
||||
|
||||
const packageJsonIterator = createFindPackageJsonIterator(root)
|
||||
|
||||
return packageJsonIterator.map(({ scripts }, packageJsonPath) => {
|
||||
if (!scripts) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
for (const script of Object.values(scripts)) {
|
||||
const rollupConfigRelativePath = extractRollupConfigPathFromScript(
|
||||
script,
|
||||
)
|
||||
|
||||
if (rollupConfigRelativePath) {
|
||||
const directoryRoot = path.resolve(packageJsonPath, '..')
|
||||
const rollupConfigPath = path.resolve(
|
||||
directoryRoot,
|
||||
rollupConfigRelativePath,
|
||||
)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
payload: { rollupConfigPath },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { success: false }
|
||||
})
|
||||
},
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
const opts = webpackPreprocessor.defaultOptions
|
||||
const babelLoader = opts.webpackOptions.module.rules[0].use[0]
|
||||
|
||||
// add React preset to be able to transpile JSX
|
||||
babelLoader.options.presets.push(require.resolve('@babel/preset-react'))
|
||||
|
||||
// We can also push Babel istanbul plugin to instrument the code on the fly
|
||||
// and get code coverage reports from component tests (optional)
|
||||
if (!babelLoader.options.plugins) {
|
||||
babelLoader.options.plugins = []
|
||||
}
|
||||
|
||||
babelLoader.options.plugins.push(require.resolve('babel-plugin-istanbul'))
|
||||
|
||||
// in order to mock named imports, need to include a plugin
|
||||
babelLoader.options.plugins.push([
|
||||
require.resolve('@babel/plugin-transform-modules-commonjs'),
|
||||
{
|
||||
loose: true,
|
||||
},
|
||||
])
|
||||
|
||||
// add code coverage plugin
|
||||
require('@cypress/code-coverage/task')(on, config)
|
||||
|
||||
on('file:preprocessor', webpackPreprocessor(opts))
|
||||
|
||||
// if adding code coverage, important to return updated config
|
||||
return config
|
||||
@@ -1,31 +0,0 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import * as babel from '@babel/core'
|
||||
import chalk from 'chalk'
|
||||
import { Template } from '../Template'
|
||||
|
||||
export const WebpackOptions: Template = {
|
||||
// this should never show ideally
|
||||
message: `Unable to detect where webpack options are.`,
|
||||
getExampleUrl: () => {
|
||||
return 'https://github.com/cypress-io/cypress/tree/develop/npm/react/examples/webpack-options'
|
||||
},
|
||||
test: () => ({ success: false }),
|
||||
recommendedComponentFolder: 'src',
|
||||
getPluginsCodeAst: () => {
|
||||
return {
|
||||
Require: babel.template.ast('const webpackPreprocessor = require("@cypress/webpack-preprocessor")'),
|
||||
ModuleExportsBody: babel.template.ast(
|
||||
fs.readFileSync(path.resolve(__dirname, 'webpack-options-module-exports.template.js'), { encoding: 'utf-8' }),
|
||||
{ preserveComments: true },
|
||||
),
|
||||
}
|
||||
},
|
||||
printHelper: () => {
|
||||
console.log(
|
||||
`${chalk.inverse('Important:')} this configuration is using ${chalk.blue(
|
||||
'new webpack configuration ',
|
||||
)}to bundle components. If you are using some framework (e.g. next) or bundling tool (e.g. rollup/parcel) consider using them to bundle component specs for cypress. \n`,
|
||||
)
|
||||
},
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { WebpackOptions } from './webpack-options'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
|
||||
describe('webpack-options template', () => {
|
||||
it('correctly generates plugins config', () => snapshotPluginsAstCode(WebpackOptions))
|
||||
})
|
||||
@@ -1,53 +0,0 @@
|
||||
import findUp from 'find-up'
|
||||
import path from 'path'
|
||||
import { createFindPackageJsonIterator } from '../../findPackageJson'
|
||||
|
||||
export function extractWebpackConfigPathFromScript (script: string) {
|
||||
if (script.includes('webpack ') || script.includes('webpack-dev-server ')) {
|
||||
const webpackCliArgs = script.split(' ').map((part) => part.trim())
|
||||
const configArgIndex = webpackCliArgs.findIndex((arg) => arg === '--config')
|
||||
|
||||
return configArgIndex === -1 ? null : webpackCliArgs[configArgIndex + 1]
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export function findWebpackConfig (root: string) {
|
||||
const webpackConfigPath = findUp.sync('webpack.config.js', { cwd: root })
|
||||
|
||||
if (webpackConfigPath) {
|
||||
return webpackConfigPath
|
||||
}
|
||||
|
||||
const packageJsonIterator = createFindPackageJsonIterator(root)
|
||||
|
||||
const { success, payload } = packageJsonIterator.map(({ scripts }, packageJsonPath) => {
|
||||
if (!scripts) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
for (const script of Object.values(scripts)) {
|
||||
const webpackConfigRelativePath = extractWebpackConfigPathFromScript(
|
||||
script,
|
||||
)
|
||||
|
||||
if (webpackConfigRelativePath) {
|
||||
const directoryRoot = path.resolve(packageJsonPath, '..')
|
||||
const webpackConfigPath = path.resolve(
|
||||
directoryRoot,
|
||||
webpackConfigRelativePath,
|
||||
)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
payload: { webpackConfigPath },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { success: false }
|
||||
})
|
||||
|
||||
return success ? payload?.webpackConfigPath : null
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Template } from '../Template'
|
||||
import { VueCliTemplate } from './vueCli'
|
||||
import { VueWebpackTemplate } from './vueWebpackFile'
|
||||
|
||||
export const vueTemplates: Record<string, Template<any>> = {
|
||||
webpack: VueWebpackTemplate,
|
||||
'vue-cli': VueCliTemplate,
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
import { VueCliTemplate } from './vueCli'
|
||||
|
||||
describe('vue webpack-file install template', () => {
|
||||
beforeEach(mockFs.restore)
|
||||
|
||||
it('resolves webpack.config.js', () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({
|
||||
'devDependencies': {
|
||||
'@vue/cli-plugin-babel': '~4.5.0',
|
||||
'@vue/cli-plugin-eslint': '~4.5.0',
|
||||
'@vue/cli-plugin-router': '~4.5.0',
|
||||
'@vue/cli-service': '~4.5.0',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = VueCliTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(true)
|
||||
})
|
||||
|
||||
it('returns success:false if vue-cli-service is not installed', () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({
|
||||
'devDependencies': {
|
||||
'webpack': '*',
|
||||
'vue': '2.x',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success } = VueCliTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(false)
|
||||
})
|
||||
|
||||
it('correctly generates plugins for vue-cli-service', () => {
|
||||
snapshotPluginsAstCode(VueCliTemplate)
|
||||
})
|
||||
})
|
||||
@@ -1,29 +0,0 @@
|
||||
import * as babel from '@babel/core'
|
||||
import { scanFSForAvailableDependency } from '../../../findPackageJson'
|
||||
import { Template } from '../Template'
|
||||
|
||||
export const VueCliTemplate: Template = {
|
||||
message:
|
||||
'It looks like you are using vue-cli-service to run and build an application.',
|
||||
getExampleUrl: () => 'https://github.com/cypress-io/cypress/tree/develop/npm/vue/examples/cli',
|
||||
recommendedComponentFolder: 'src',
|
||||
getPluginsCodeAst: () => {
|
||||
return {
|
||||
Require: babel.template.ast(
|
||||
'const preprocessor = require("@cypress/vue/dist/plugins/webpack");',
|
||||
),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
'preprocessor(on, config);',
|
||||
'// IMPORTANT return the config object',
|
||||
'return config',
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
test: (root) => {
|
||||
const hasVueCliService = scanFSForAvailableDependency(root, ['@vue/cli-service'])
|
||||
|
||||
return {
|
||||
success: hasVueCliService,
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import mockFs from 'mock-fs'
|
||||
import { snapshotPluginsAstCode } from '../../../test-utils'
|
||||
import { VueWebpackTemplate } from './vueWebpackFile'
|
||||
|
||||
describe('vue webpack-file install template', () => {
|
||||
beforeEach(mockFs.restore)
|
||||
|
||||
it('resolves webpack.config.js', () => {
|
||||
mockFs({
|
||||
'/webpack.config.js': 'module.exports = { }',
|
||||
})
|
||||
|
||||
const { success, payload } = VueWebpackTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.webpackConfigPath).to.equal('/webpack.config.js')
|
||||
})
|
||||
|
||||
it('finds the closest package.json and tries to fetch webpack config path from scrips', () => {
|
||||
mockFs({
|
||||
'/configs/webpack.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({
|
||||
scripts: {
|
||||
build: 'webpack --config configs/webpack.js',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success, payload } = VueWebpackTemplate.test(process.cwd())
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.webpackConfigPath).to.equal('/configs/webpack.js')
|
||||
})
|
||||
|
||||
it('looks for package.json in the upper folder', () => {
|
||||
mockFs({
|
||||
'/some/deep/folder/withFile': 'test',
|
||||
'/somewhere/configs/webpack.js': 'module.exports = { }',
|
||||
'/package.json': JSON.stringify({
|
||||
scripts: {
|
||||
build: 'webpack --config somewhere/configs/webpack.js',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
const { success, payload } = VueWebpackTemplate.test(
|
||||
'/some/deep/folder',
|
||||
)
|
||||
|
||||
expect(success).to.equal(true)
|
||||
expect(payload?.webpackConfigPath).to.equal('/somewhere/configs/webpack.js')
|
||||
})
|
||||
|
||||
it('returns success:false if cannot find webpack config', () => {
|
||||
mockFs({
|
||||
'/a.js': '1',
|
||||
'/b.js': '2',
|
||||
})
|
||||
|
||||
const { success, payload } = VueWebpackTemplate.test('/')
|
||||
|
||||
expect(success).to.equal(false)
|
||||
expect(payload).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config when webpack config path is missing', () => {
|
||||
snapshotPluginsAstCode(VueWebpackTemplate)
|
||||
})
|
||||
|
||||
it('correctly generates plugins config when webpack config path is provided', () => {
|
||||
snapshotPluginsAstCode(VueWebpackTemplate, { webpackConfigPath: '/build/webpack.config.js' })
|
||||
})
|
||||
})
|
||||
@@ -1,41 +0,0 @@
|
||||
import * as babel from '@babel/core'
|
||||
import path from 'path'
|
||||
import { Template } from '../Template'
|
||||
import { findWebpackConfig } from '../templateUtils'
|
||||
|
||||
export const VueWebpackTemplate: Template<{ webpackConfigPath: string }> = {
|
||||
message:
|
||||
'It looks like you have custom `webpack.config.js`. We can use it to bundle the components for testing.',
|
||||
getExampleUrl: () => 'https://github.com/cypress-io/cypress/tree/develop/npm/vue/examples/cli',
|
||||
recommendedComponentFolder: 'cypress/component',
|
||||
getPluginsCodeAst: (payload, { cypressProjectRoot }) => {
|
||||
const includeWarnComment = !payload
|
||||
const webpackConfigPath = payload
|
||||
? path.relative(cypressProjectRoot, payload.webpackConfigPath)
|
||||
: './webpack.config.js'
|
||||
|
||||
return {
|
||||
Require: babel.template.ast([
|
||||
'const {',
|
||||
' onFilePreprocessor',
|
||||
'} = require(\'@cypress/vue/dist/preprocessor/webpack\')',
|
||||
].join('\n')),
|
||||
ModuleExportsBody: babel.template.ast([
|
||||
includeWarnComment
|
||||
? '// TODO replace with valid webpack config path'
|
||||
: '',
|
||||
`on('file:preprocessor', onFilePreprocessor('${webpackConfigPath}'))`,
|
||||
].join('\n'), { preserveComments: true }),
|
||||
}
|
||||
},
|
||||
test: (root) => {
|
||||
const webpackConfigPath = findWebpackConfig(root)
|
||||
|
||||
return webpackConfigPath ? {
|
||||
success: true,
|
||||
payload: { webpackConfigPath },
|
||||
} : {
|
||||
success: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export const MIN_SUPPORTED_VERSION = {
|
||||
'react-scripts': '^=3.x || ^=4.x',
|
||||
next: '^=9.x',
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import findUp from 'find-up'
|
||||
|
||||
type PackageJsonLike = {
|
||||
name?: string
|
||||
scripts?: Record<string, string>
|
||||
dependencies?: Record<string, string>
|
||||
devDependencies?: Record<string, string>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
type FindPackageJsonResult =
|
||||
| {
|
||||
packageData: PackageJsonLike
|
||||
filename: string
|
||||
done: false
|
||||
}
|
||||
| {
|
||||
packageData: undefined
|
||||
filename: undefined
|
||||
done: true
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parsed package.json that we find in a parent folder.
|
||||
*
|
||||
* @returns {Object} Value, filename and indication if the iteration is done.
|
||||
*/
|
||||
export function createFindPackageJsonIterator (rootPath = process.cwd()) {
|
||||
function scanForPackageJson (cwd: string): FindPackageJsonResult {
|
||||
const packageJsonPath = findUp.sync('package.json', { cwd })
|
||||
|
||||
if (!packageJsonPath) {
|
||||
return {
|
||||
packageData: undefined,
|
||||
filename: undefined,
|
||||
done: true,
|
||||
}
|
||||
}
|
||||
|
||||
const packageData = JSON.parse(
|
||||
fs.readFileSync(packageJsonPath, {
|
||||
encoding: 'utf-8',
|
||||
}),
|
||||
)
|
||||
|
||||
return {
|
||||
packageData,
|
||||
filename: packageJsonPath,
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
map: <TPayload>(
|
||||
cb: (
|
||||
data: PackageJsonLike,
|
||||
packageJsonPath: string,
|
||||
) => { success: boolean, payload?: TPayload },
|
||||
) => {
|
||||
let stepPathToScan = rootPath
|
||||
|
||||
// eslint-disable-next-line
|
||||
while (true) {
|
||||
const result = scanForPackageJson(stepPathToScan)
|
||||
|
||||
if (result.done) {
|
||||
// didn't find the package.json
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
if (result.packageData) {
|
||||
const cbResult = cb(result.packageData, result.filename)
|
||||
|
||||
if (cbResult.success) {
|
||||
return { success: true, payload: cbResult.payload }
|
||||
}
|
||||
}
|
||||
|
||||
const nextStepPathToScan = path.resolve(stepPathToScan, '..')
|
||||
|
||||
if (nextStepPathToScan === stepPathToScan) {
|
||||
// we are at the root. Give up
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
stepPathToScan = nextStepPathToScan
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function scanFSForAvailableDependency (cwd: string, deps: string[]) {
|
||||
const { success } = createFindPackageJsonIterator(cwd)
|
||||
.map(({ dependencies, devDependencies }, path) => {
|
||||
if (!dependencies && !devDependencies) {
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
return {
|
||||
success: Object.keys({ ...dependencies, ...devDependencies })
|
||||
.some((dependency) => deps.includes(dependency)),
|
||||
}
|
||||
})
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
export type PackageJsonIterator = ReturnType<typeof createFindPackageJsonIterator>
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { program } from 'commander'
|
||||
import { main } from './main'
|
||||
import { version } from '../package.json'
|
||||
|
||||
program
|
||||
.option('--ignore-examples', 'Ignore generating example tests and fixtures by creating one ready-to-fill spec file')
|
||||
.option('--use-npm', 'Use npm even if yarn is available')
|
||||
.option('--ignore-ts', 'Ignore typescript if available')
|
||||
.option('--component-tests', 'Run component testing installation without asking')
|
||||
|
||||
program.version(version, '-v --version')
|
||||
program.parse(process.argv)
|
||||
|
||||
main({
|
||||
useNpm: program.useNpm,
|
||||
ignoreTs: program.ignoreTs,
|
||||
ignoreExamples: Boolean(program.ignoreExamples),
|
||||
setupComponentTesting: program.componentTests,
|
||||
}).catch(console.error)
|
||||
@@ -1,71 +0,0 @@
|
||||
import fs from 'fs-extra'
|
||||
import findUp from 'find-up'
|
||||
import path from 'path'
|
||||
import example from '../initial-template'
|
||||
import { installDependency } from './utils'
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
|
||||
type InstallCypressOpts = {
|
||||
useYarn: boolean
|
||||
useTypescript: boolean
|
||||
ignoreExamples: boolean
|
||||
}
|
||||
|
||||
async function copyFiles ({ ignoreExamples, useTypescript }: InstallCypressOpts) {
|
||||
let fileSpinner = ora('Creating config files').start()
|
||||
|
||||
await fs.outputFile(path.resolve(process.cwd(), 'cypress.json'), '{}\n')
|
||||
await fs.copy(example.getPathToPlugins(), path.resolve('cypress', 'plugins/index.js'))
|
||||
const supportFiles: string[] = await example.getPathToSupportFiles()
|
||||
|
||||
await Promise.all(
|
||||
supportFiles.map((supportFilePath) => {
|
||||
const newSupportFilePath = path.resolve('cypress', 'support', path.basename(supportFilePath))
|
||||
|
||||
return fs.copy(supportFilePath, newSupportFilePath)
|
||||
}),
|
||||
)
|
||||
|
||||
if (useTypescript) {
|
||||
await fs.copy(example.getPathToTsConfig(), path.resolve('cypress', 'tsconfig.json'))
|
||||
}
|
||||
|
||||
// TODO think about better approach
|
||||
if (ignoreExamples) {
|
||||
const dummySpec = [
|
||||
'describe("Spec", () => {',
|
||||
'',
|
||||
'})',
|
||||
'',
|
||||
]
|
||||
const specFileToCreate = path.resolve('cypress', 'integration', useTypescript ? 'spec.ts' : 'spec.js')
|
||||
|
||||
await fs.outputFile(path.resolve('cypress', 'integration', useTypescript ? 'spec.js' : 'spec.ts'), dummySpec)
|
||||
console.log(`In order to ignore examples a spec file ${chalk.green(path.relative(process.cwd(), specFileToCreate))}.`)
|
||||
}
|
||||
|
||||
fileSpinner.succeed()
|
||||
}
|
||||
|
||||
export async function findInstalledOrInstallCypress (options: InstallCypressOpts) {
|
||||
let cypressJsonPath = await findUp('cypress.json')
|
||||
|
||||
if (!cypressJsonPath) {
|
||||
await installDependency('cypress', options)
|
||||
await copyFiles(options)
|
||||
|
||||
cypressJsonPath = await findUp('cypress.json')
|
||||
}
|
||||
|
||||
if (!cypressJsonPath) {
|
||||
throw new Error('Unexpected error during cypress installation.')
|
||||
}
|
||||
|
||||
return {
|
||||
cypressConfigPath: cypressJsonPath,
|
||||
config: JSON.parse(
|
||||
fs.readFileSync(cypressJsonPath, { encoding: 'utf-8' }).toString(),
|
||||
) as Record<string, string>,
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
import { expect, use } from 'chai'
|
||||
import path from 'path'
|
||||
import sinon, { SinonStub, SinonSpy, SinonSpyCallApi, restore } from 'sinon'
|
||||
import mockFs from 'mock-fs'
|
||||
import fsExtra from 'fs-extra'
|
||||
import { main } from './main'
|
||||
import sinonChai from 'sinon-chai'
|
||||
import childProcess from 'child_process'
|
||||
|
||||
use(sinonChai)
|
||||
|
||||
function someOfSpyCallsIncludes (spy: any, logPart: string) {
|
||||
return spy.getCalls().some(
|
||||
(spy: SinonSpyCallApi<unknown[]>) => {
|
||||
return spy.args.some((callArg) => typeof callArg === 'string' && callArg.includes(logPart))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
describe('create-cypress-tests', () => {
|
||||
let promptSpy: SinonStub<any> | null = null
|
||||
let logSpy: SinonSpy | null = null
|
||||
let errorSpy: SinonSpy | null = null
|
||||
let execStub: SinonStub | null = null
|
||||
let fsCopyStub: SinonStub | null = null
|
||||
let processExitStub: SinonStub | null = null
|
||||
|
||||
beforeEach(() => {
|
||||
logSpy = sinon.spy(global.console, 'log')
|
||||
errorSpy = sinon.spy(global.console, 'error')
|
||||
// @ts-ignore
|
||||
execStub = sinon.stub(childProcess, 'exec').callsFake((command, callback) => callback())
|
||||
// @ts-ignore
|
||||
fsCopyStub = sinon.stub(fsExtra, 'copy').returns(Promise.resolve())
|
||||
processExitStub = sinon.stub(process, 'exit').callsFake(() => {
|
||||
throw new Error('process.exit should not be called')
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore()
|
||||
logSpy?.restore()
|
||||
promptSpy?.restore()
|
||||
execStub?.restore()
|
||||
fsCopyStub?.restore()
|
||||
processExitStub?.restore()
|
||||
execStub?.restore()
|
||||
errorSpy?.restore()
|
||||
})
|
||||
|
||||
it('Install cypress if no config found', async () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({ }),
|
||||
})
|
||||
|
||||
await main({ useNpm: false, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
|
||||
expect(execStub).calledWith('yarn add cypress --dev')
|
||||
})
|
||||
|
||||
it('Uses npm if yarn is not available', async () => {
|
||||
execStub
|
||||
?.onFirstCall().callsFake((command, callback) => callback('yarn is not available'))
|
||||
?.onSecondCall().callsFake((command, callback) => callback())
|
||||
?.onThirdCall().callsFake((command, callback) => callback())
|
||||
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({ }),
|
||||
})
|
||||
|
||||
await main({ useNpm: false, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
expect(execStub).calledWith('npm install -D cypress')
|
||||
})
|
||||
|
||||
it('Uses npm if --use-npm was provided', async () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({ }),
|
||||
})
|
||||
|
||||
await main({ useNpm: true, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
|
||||
expect(execStub).calledWith('npm install -D cypress')
|
||||
})
|
||||
|
||||
it('Prints correct commands helper for npm', async () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({ }),
|
||||
})
|
||||
|
||||
await main({ useNpm: true, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
expect(someOfSpyCallsIncludes(logSpy, 'npx cypress open')).to.be.true
|
||||
})
|
||||
|
||||
it('Prints correct commands helper for yarn', async () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({ }),
|
||||
})
|
||||
|
||||
await main({ useNpm: false, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
expect(someOfSpyCallsIncludes(logSpy, 'yarn cypress open')).to.be.true
|
||||
})
|
||||
|
||||
it('Fails if git repository have untracked or uncommited files', async () => {
|
||||
mockFs({
|
||||
'/package.json': JSON.stringify({ }),
|
||||
})
|
||||
|
||||
execStub?.callsFake((_, callback) => callback(null, { stdout: 'test' }))
|
||||
processExitStub?.callsFake(() => {})
|
||||
|
||||
await main({ useNpm: true, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
|
||||
expect(
|
||||
someOfSpyCallsIncludes(errorSpy, 'This repository has untracked files or uncommmited changes.'),
|
||||
).to.equal(true)
|
||||
|
||||
expect(processExitStub).to.be.called
|
||||
})
|
||||
|
||||
context('e2e fs tests', () => {
|
||||
const e2eTestOutputPath = path.resolve(__dirname, 'test-output')
|
||||
|
||||
beforeEach(async () => {
|
||||
fsCopyStub?.restore()
|
||||
mockFs.restore()
|
||||
sinon.stub(process, 'cwd').returns(e2eTestOutputPath)
|
||||
|
||||
await fsExtra.remove(e2eTestOutputPath)
|
||||
await fsExtra.mkdir(e2eTestOutputPath)
|
||||
})
|
||||
|
||||
it('Copies plugins and support files', async () => {
|
||||
await fsExtra.outputFile(
|
||||
path.join(e2eTestOutputPath, 'package.json'),
|
||||
JSON.stringify({ name: 'test' }, null, 2),
|
||||
)
|
||||
|
||||
await main({ useNpm: true, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
|
||||
expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'plugins', 'index.js'))).to.equal(true)
|
||||
expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'index.js'))).to.equal(true)
|
||||
expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'support', 'commands.js'))).to.equal(true)
|
||||
expect(await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress.json'))).to.equal(true)
|
||||
})
|
||||
|
||||
it('Copies tsconfig if typescript is installed', async () => {
|
||||
await fsExtra.outputFile(
|
||||
path.join(e2eTestOutputPath, 'package.json'),
|
||||
JSON.stringify({
|
||||
name: 'test-typescript',
|
||||
dependencies: { typescript: '^4.0.0' },
|
||||
}, null, 2),
|
||||
)
|
||||
|
||||
await main({ useNpm: false, ignoreTs: false, ignoreExamples: false, setupComponentTesting: false })
|
||||
await fsExtra.pathExists(path.resolve(e2eTestOutputPath, 'cypress', 'tsconfig.json'))
|
||||
console.log(path.resolve(e2eTestOutputPath, 'cypress', 'tsconfig.json'))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,98 +0,0 @@
|
||||
import fs from 'fs'
|
||||
import findUp from 'find-up'
|
||||
import chalk from 'chalk'
|
||||
import util from 'util'
|
||||
import inquirer from 'inquirer'
|
||||
import { initComponentTesting } from './component-testing/init-component-testing'
|
||||
import { exec } from 'child_process'
|
||||
import { scanFSForAvailableDependency } from './findPackageJson'
|
||||
import { findInstalledOrInstallCypress } from './installCypress'
|
||||
|
||||
type MainArgv = {
|
||||
useNpm: boolean
|
||||
ignoreTs: boolean
|
||||
ignoreExamples: boolean
|
||||
setupComponentTesting: boolean
|
||||
}
|
||||
|
||||
async function getGitStatus () {
|
||||
const execAsync = util.promisify(exec)
|
||||
|
||||
try {
|
||||
let { stdout } = await execAsync(`git status --porcelain`)
|
||||
|
||||
console.log(stdout)
|
||||
|
||||
return stdout.trim()
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
async function shouldUseYarn () {
|
||||
const execAsync = util.promisify(exec)
|
||||
|
||||
return execAsync('yarn --version')
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
}
|
||||
|
||||
function shouldUseTypescript () {
|
||||
return scanFSForAvailableDependency(process.cwd(), ['typescript'])
|
||||
}
|
||||
|
||||
async function askForComponentTesting () {
|
||||
const { shouldSetupComponentTesting } = await inquirer.prompt({
|
||||
type: 'confirm',
|
||||
name: 'shouldSetupComponentTesting',
|
||||
message: `Do you want to setup ${chalk.cyan('component testing')}? ${chalk.grey('You can do this later by rerunning this command')}.`,
|
||||
})
|
||||
|
||||
return shouldSetupComponentTesting
|
||||
}
|
||||
|
||||
function printCypressCommandsHelper ({ useYarn }: { useYarn: boolean }) {
|
||||
const displayedCommand = useYarn ? 'yarn' : 'npx'
|
||||
|
||||
console.log('Inside this directory, you can run several commands:')
|
||||
console.log()
|
||||
console.log(chalk.cyan(` ${displayedCommand} cypress open`))
|
||||
console.log(' Opens cypress local development app.')
|
||||
console.log()
|
||||
console.log(chalk.cyan(` ${displayedCommand} cypress run`))
|
||||
console.log(' Runs tests in headless mode.')
|
||||
}
|
||||
|
||||
export async function main ({ useNpm, ignoreTs, setupComponentTesting, ignoreExamples }: MainArgv) {
|
||||
const rootPackageJsonPath = await findUp('package.json')
|
||||
const useYarn = useNpm === true ? false : await shouldUseYarn()
|
||||
const useTypescript = ignoreTs ? false : shouldUseTypescript()
|
||||
|
||||
if (!rootPackageJsonPath) {
|
||||
console.log(`${chalk.bold.red(`It looks like you are running cypress installation wizard outside of npm module.`)}\nIf you would like to setup a new project for cypress tests please run the ${chalk.inverse(useNpm ? ' npm init ' : ' yarn init ')} first.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const { name = 'unknown', version = '0.0.0' } = JSON.parse(fs.readFileSync(rootPackageJsonPath).toString())
|
||||
|
||||
console.log(`Running ${chalk.green('cypress 🌲')} installation wizard for ${chalk.cyan(`${name}@${version}`)}`)
|
||||
|
||||
const gitStatus = await getGitStatus()
|
||||
|
||||
if (gitStatus) {
|
||||
console.error(`\n${chalk.bold.red('This repository has untracked files or uncommmited changes.')}\nThis command will ${chalk.cyan('make changes in the codebase')}, so please remove untracked files, stash or commit any changes, and try again.`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const { config, cypressConfigPath } = await findInstalledOrInstallCypress({ useYarn, useTypescript, ignoreExamples })
|
||||
const shouldSetupComponentTesting = setupComponentTesting ?? await askForComponentTesting()
|
||||
|
||||
if (shouldSetupComponentTesting) {
|
||||
await initComponentTesting({ config, cypressConfigPath, useYarn })
|
||||
}
|
||||
|
||||
console.log(`\n👍 Success! Cypress is installed and ready to run tests.`)
|
||||
printCypressCommandsHelper({ useYarn })
|
||||
|
||||
console.log(`\nHappy testing with ${chalk.green('cypress.io')} 🌲\n`)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as babel from '@babel/core'
|
||||
import snapshot from 'snap-shot-it'
|
||||
import mockFs from 'mock-fs'
|
||||
import { SinonSpyCallApi } from 'sinon'
|
||||
import { createTransformPluginsFileBabelPlugin } from './component-testing/babel/babelTransform'
|
||||
import { Template } from './component-testing/templates/Template'
|
||||
|
||||
export function someOfSpyCallsIncludes (spy: any, logPart: string) {
|
||||
return spy.getCalls().some(
|
||||
(spy: SinonSpyCallApi<unknown[]>) => {
|
||||
return spy.args.some((callArg) => typeof callArg === 'string' && callArg.includes(logPart))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export function snapshotPluginsAstCode<T> (template: Template<T>, payload?: T) {
|
||||
mockFs.restore()
|
||||
const code = [
|
||||
'const something = require("something")',
|
||||
'module.exports = (on) => {',
|
||||
'};',
|
||||
].join('\n')
|
||||
|
||||
const babelPlugin = createTransformPluginsFileBabelPlugin(template.getPluginsCodeAst(payload ?? null, { cypressProjectRoot: '/' }))
|
||||
const output = babel.transformSync(code, {
|
||||
plugins: [babelPlugin],
|
||||
})
|
||||
|
||||
if (!output || !output.code) {
|
||||
throw new Error('Babel transform output is empty.')
|
||||
}
|
||||
|
||||
snapshot(output.code)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import semver from 'semver'
|
||||
import chalk from 'chalk'
|
||||
import ora from 'ora'
|
||||
import util from 'util'
|
||||
import { exec } from 'child_process'
|
||||
|
||||
/**
|
||||
* Compare available version range with the provided version from package.json
|
||||
* @param packageName Package name used to display a helper message to user.
|
||||
*/
|
||||
export function validateSemverVersion (
|
||||
version: string,
|
||||
allowedVersionRange: string,
|
||||
packageName?: string,
|
||||
) {
|
||||
let isValid: boolean
|
||||
|
||||
try {
|
||||
const minAvailableVersion = semver.minVersion(version)?.raw
|
||||
|
||||
isValid = Boolean(
|
||||
minAvailableVersion &&
|
||||
semver.satisfies(minAvailableVersion, allowedVersionRange),
|
||||
)
|
||||
} catch (e) {
|
||||
// handle not semver versions like "latest", "git:" or "file:"
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (!isValid && packageName) {
|
||||
const packageNameSymbol = chalk.green(packageName)
|
||||
|
||||
console.warn(
|
||||
`It seems like you are using ${packageNameSymbol} with version ${chalk.bold(
|
||||
version,
|
||||
)}, however we support only ${packageNameSymbol} projects with version ${chalk.bold(
|
||||
allowedVersionRange,
|
||||
)}. \n`,
|
||||
)
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
export async function installDependency (name: string, options: { useYarn: boolean}) {
|
||||
const commandToRun = options.useYarn ? `yarn add ${name} --dev` : `npm install -D ${name}`
|
||||
let cliSpinner = ora(`Installing ${name} ${chalk.gray(`(${commandToRun})`)}`).start()
|
||||
|
||||
try {
|
||||
// do this inside function for test stubbing
|
||||
const execAsync = util.promisify(exec)
|
||||
|
||||
await execAsync(commandToRun)
|
||||
} catch (e) {
|
||||
cliSpinner.fail(`Can not install ${name} using ${chalk.inverse(commandToRun)})}`)
|
||||
console.log(e)
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
cliSpinner.succeed()
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": ".",
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"declaration": true,
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"resolveJsonModule": true,
|
||||
"module": "CommonJS",
|
||||
"target": "ES2018",
|
||||
"types": [
|
||||
"node",
|
||||
],
|
||||
"lib": [
|
||||
"ES2018"
|
||||
],
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"exclude": [
|
||||
"./src/**/*.test.ts",
|
||||
"node_modules"
|
||||
],
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./initial-template/**/*.{js}"
|
||||
]
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"types": [
|
||||
"mocha"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.test.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
version: 2.1
|
||||
orbs:
|
||||
cypress: cypress-io/cypress@1.26.0
|
||||
|
||||
workflows:
|
||||
build:
|
||||
jobs:
|
||||
# install and cache dependencies in this job
|
||||
# AND build the library once
|
||||
# then the workspace will be passed to other jobs
|
||||
- cypress/install:
|
||||
name: Install
|
||||
executor: cypress/base-12
|
||||
build: npm run transpile
|
||||
post-steps:
|
||||
- run:
|
||||
name: Show info 📺
|
||||
command: npx cypress info
|
||||
- run:
|
||||
name: Linting code 🧹
|
||||
command: npm run lint
|
||||
- run:
|
||||
name: Stop exclusive tests 1️⃣
|
||||
command: npm run stop-only
|
||||
- run:
|
||||
name: Build folder 🏗
|
||||
command: npm run build
|
||||
- run:
|
||||
name: Run unit tests 👷
|
||||
command: npm run test:unit
|
||||
|
||||
- cypress/run:
|
||||
name: Example A11y
|
||||
requires:
|
||||
- Install
|
||||
executor: cypress/base-12
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/a11y
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Example Babel
|
||||
requires:
|
||||
- Install
|
||||
executor: cypress/base-12
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: false
|
||||
working_directory: examples/using-babel
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Example Babel + Typescript
|
||||
requires:
|
||||
- Install
|
||||
executor: cypress/base-12
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/using-babel-typescript
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Example React Scripts
|
||||
requires:
|
||||
- Install
|
||||
executor: cypress/base-12
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/react-scripts
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- run:
|
||||
name: Check coverage 📈
|
||||
command: |
|
||||
npm run check-coverage
|
||||
npm run only-covered
|
||||
working_directory: examples/react-scripts
|
||||
|
||||
- cypress/run:
|
||||
name: Example Next.js
|
||||
requires:
|
||||
- Install
|
||||
executor: cypress/base-12
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/nextjs
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- run:
|
||||
name: Check coverage 📈
|
||||
command: |
|
||||
npm run check-coverage
|
||||
npm run only-covered
|
||||
working_directory: examples/nextjs
|
||||
|
||||
- cypress/run:
|
||||
# react-scripts example with component tests not in "src" folder
|
||||
# but in "cypress/component" folder
|
||||
name: Example Component Folder
|
||||
executor: cypress/base-12
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/react-scripts-folder
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- run:
|
||||
name: Check coverage 📈
|
||||
command: |
|
||||
npm run check-coverage
|
||||
npm run only-covered
|
||||
working_directory: examples/react-scripts-folder
|
||||
|
||||
- cypress/run:
|
||||
name: Example Tailwind
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
executor: cypress/base-12
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/tailwind
|
||||
command: |
|
||||
DEBUG=cypress-react-unit-test,find-webpack npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- run:
|
||||
name: Check coverage 📈
|
||||
command: |
|
||||
ls -la
|
||||
npm run check-coverage
|
||||
npm run only-covered
|
||||
working_directory: examples/tailwind
|
||||
|
||||
- cypress/run:
|
||||
name: Example Webpack file
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
executor: cypress/base-12
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/webpack-file
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- run:
|
||||
name: Check coverage 📈
|
||||
command: |
|
||||
npm run check-coverage
|
||||
npm run only-covered
|
||||
working_directory: examples/webpack-file
|
||||
|
||||
- cypress/run:
|
||||
name: Example Rollup
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
executor: cypress/base-12
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/rollup
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Example Webpack options
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
executor: cypress/base-12
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/webpack-options
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- run:
|
||||
name: Check coverage 📈
|
||||
command: |
|
||||
npm run check-coverage
|
||||
npm run only-covered
|
||||
working_directory: examples/webpack-options
|
||||
|
||||
# - cypress/run:
|
||||
# name: Example Sass
|
||||
# requires:
|
||||
# - Install
|
||||
# # we need the same OS version as in install job
|
||||
# # because we will use native Sass dependency
|
||||
# executor: cypress/base-12
|
||||
# # each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
# install-command: npm install --no-bin-links
|
||||
# verify-command: echo 'Already verified'
|
||||
# no-workspace: true
|
||||
# working_directory: examples/sass-and-ts
|
||||
# command: npm test
|
||||
# store_artifacts: true
|
||||
# post-steps:
|
||||
# - run:
|
||||
# name: Check coverage 📈
|
||||
# command: |
|
||||
# npm run check-coverage
|
||||
# npm run only-covered
|
||||
# working_directory: examples/sass-and-ts
|
||||
|
||||
- cypress/run:
|
||||
name: Example Snapshots
|
||||
requires:
|
||||
- Install
|
||||
executor: cypress/base-12
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/snapshots
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Visual Sudoku
|
||||
executor: cypress/base-12
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/visual-sudoku
|
||||
command: npm test
|
||||
store_artifacts: true
|
||||
post-steps:
|
||||
- store_artifacts:
|
||||
path: examples/visual-sudoku/cypress/snapshots
|
||||
|
||||
- cypress/run:
|
||||
name: Visual with Applitools
|
||||
executor: cypress/base-12
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/visual-testing-with-applitools
|
||||
# to correctly run this job, we need Applitools token
|
||||
# external pull requests do not have environment variables set
|
||||
# thus the job will always fail. Let's skip this job if the
|
||||
# environment variable is missing
|
||||
command: |
|
||||
if [ -z "$APPLITOOLS_API_KEY" ]; then
|
||||
echo "Skipping Applitools test job, missing environment variable APPLITOOLS_API_KEY"
|
||||
else
|
||||
npm test
|
||||
fi
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Visual with Percy
|
||||
executor: cypress/base-12
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/visual-testing-with-percy
|
||||
# run Percy agent and then run Cypress component tests
|
||||
# https://docs.percy.io/docs/cypress
|
||||
command: npx percy exec -- npm test
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Visual with Happo
|
||||
executor: cypress/base-12
|
||||
requires:
|
||||
- Install
|
||||
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
|
||||
install-command: npm install --no-bin-links
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
working_directory: examples/visual-testing-with-happo
|
||||
command: npm run test:happo
|
||||
store_artifacts: true
|
||||
|
||||
- cypress/run:
|
||||
name: Component Tests
|
||||
executor: cypress/base-12
|
||||
parallelism: 4
|
||||
requires:
|
||||
- Install
|
||||
# notice a trick to avoid re-installing dependencies
|
||||
# in this job - a do-nothing "install-command" parameter
|
||||
install-command: echo 'Nothing to install in this job'
|
||||
# we are not going to use results from this job anywhere else
|
||||
no-workspace: true
|
||||
record: false
|
||||
store_artifacts: true
|
||||
# following examples from
|
||||
# https://circleci.com/docs/2.0/parallelism-faster-jobs/
|
||||
# TODO probably only run component tests and move integration sanity checks into own job
|
||||
command: |
|
||||
TESTFILES=$(circleci tests glob "cypress/{component,integration}/**/*spec.{js,jsx,ts,tsx}" | circleci tests split --total=4)
|
||||
echo "Test files for this machine are $TESTFILES"
|
||||
npx cypress run --spec $TESTFILES
|
||||
|
||||
# this job attaches the workspace left by the install job
|
||||
# so it is ready to run Cypress tests
|
||||
# only we will run semantic release script instead
|
||||
- cypress/run:
|
||||
name: NPM release
|
||||
# only run NPM release from specific branch(es)
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
# we need newer Node for semantic release
|
||||
executor: cypress/base-12
|
||||
requires:
|
||||
- Install
|
||||
- Component Tests
|
||||
- Example A11y
|
||||
- Example Babel
|
||||
- Example Component Folder
|
||||
- Example React Scripts
|
||||
# - Example Sass
|
||||
- Example Snapshots
|
||||
- Example Tailwind
|
||||
- Example Webpack file
|
||||
- Example Webpack options
|
||||
- Example Rollup
|
||||
- Visual Sudoku
|
||||
- Visual with Percy
|
||||
- Visual with Happo
|
||||
- Visual with Applitools
|
||||
install-command: echo 'Already installed'
|
||||
verify-command: echo 'Already verified'
|
||||
no-workspace: true
|
||||
# instead of "cypress run" do NPM release 😁
|
||||
# clear environment variables to trick semantic-release
|
||||
# into thinking this is NOT a pull request.
|
||||
# (under the hood the module env-ci is used to check if this is a PR)
|
||||
command: |
|
||||
npm run build
|
||||
CIRCLE_PR_NUMBER= \
|
||||
CIRCLE_PULL_REQUEST= \
|
||||
CI_PULL_REQUEST= \
|
||||
npm run semantic-release
|
||||
@@ -43,6 +43,9 @@
|
||||
"@percy/cypress": "2.3.2",
|
||||
"@testing-library/cypress": "7.0.1",
|
||||
"@types/chalk": "2.2.0",
|
||||
"@types/inquirer": "7.3.1",
|
||||
"@types/mock-fs": "4.10.0",
|
||||
"@types/node": "9.6.49",
|
||||
"@types/semver": "7.3.4",
|
||||
"arg": "4.1.3",
|
||||
"autoprefixer": "9.7.6",
|
||||
@@ -64,6 +67,8 @@
|
||||
"lodash": "4.17.15",
|
||||
"mobx": "6.0.0",
|
||||
"mobx-react-lite": "3.0.0",
|
||||
"mocha": "7.1.1",
|
||||
"mock-fs": "4.13.0",
|
||||
"next": "^9.5.3",
|
||||
"pretty": "2.0.0",
|
||||
"prop-types": "15.7.2",
|
||||
@@ -95,7 +100,7 @@
|
||||
"@types/react": "^16.9.16",
|
||||
"babel-loader": "^=8.x",
|
||||
"cypress": "*",
|
||||
"next": "^=9.x",
|
||||
"next": "^=8.x",
|
||||
"react": "^=16.x",
|
||||
"react-dom": "^=16.x",
|
||||
"webpack": "^=3.x"
|
||||
|
||||
@@ -60,6 +60,7 @@ function compileTemplate (options = {}) {
|
||||
|
||||
/**
|
||||
* Warning: modifies the input object
|
||||
<<<<<<< HEAD
|
||||
* @param {WebpackOptions} options
|
||||
*/
|
||||
|
||||
@@ -75,6 +76,8 @@ function removeForkTsCheckerWebpackPlugin (options) {
|
||||
|
||||
/**
|
||||
* Warning: modifies the input object
|
||||
=======
|
||||
>>>>>>> origin
|
||||
* @param {Cypress.ConfigOptions} config
|
||||
* @param {WebpackOptions} options
|
||||
*/
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
|
||||
## Scaffold config files
|
||||
|
||||
The `cypress/plugins/index.js`, `cypress/support/*` and `cypress/tsconfig.json` from this package are used for user scaffolding in `packages/server` and `npm/create-cypress-tests`. This configuration files are by default injected when user instals Cypress.
|
||||
|
||||
## Examples
|
||||
## Example
|
||||
|
||||
This repo contains the source code for pushing out [https://example.cypress.io](https://example.cypress.io).
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ shell.rm('-rf', 'app')
|
||||
shell.mkdir('app')
|
||||
|
||||
shell.cp('-r', join(resolvePkg('cypress-example-kitchensink'), 'app'), '.')
|
||||
shell.rm('-rf', 'cypress/integration')
|
||||
shell.rm('-rf', 'cypress')
|
||||
|
||||
shell.cp('-r', join(resolvePkg('cypress-example-kitchensink'), 'cypress', 'integration'), 'cypress/integration')
|
||||
shell.cp('-r', join(resolvePkg('cypress-example-kitchensink'), 'cypress'), '.')
|
||||
|
||||
shell.exec('node ./bin/convert.js')
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": ["cypress"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
export { default } from './lib/example'
|
||||
Vendored
-10
@@ -1,10 +0,0 @@
|
||||
declare const example: {
|
||||
getPathToExamples(): Promise<string[]>;
|
||||
getFolderName(): string;
|
||||
getPathToPlugins(): string;
|
||||
getPathToSupportFiles(): Promise<string[]>;
|
||||
getPathToTsConfig(): string;
|
||||
getPathToFixture(): string;
|
||||
}
|
||||
|
||||
export default example;
|
||||
@@ -16,33 +16,8 @@ module.exports = {
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
|
||||
getFolderName () {
|
||||
return 'examples'
|
||||
},
|
||||
|
||||
getPathToPlugins() {
|
||||
return path.resolve(__dirname, '..', 'cypress', 'plugins', 'index.js')
|
||||
},
|
||||
|
||||
getPathToSupportFiles() {
|
||||
return glob(
|
||||
path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'cypress',
|
||||
'support',
|
||||
'**',
|
||||
'*'
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
getPathToTsConfig() {
|
||||
return path.resolve(__dirname, '..', 'cypress', 'tsconfig.json')
|
||||
},
|
||||
|
||||
getPathToFixture() {
|
||||
return path.resolve(__dirname, '..', 'cypress', 'fixtures', 'example.json')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"postinstall": "echo '@packages/example needs: yarn build'",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
|
||||
@@ -342,11 +342,11 @@ exports['lib/scaffold .support creates supportFolder and commands.js and index.j
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: "element"}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: "optional"}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
|
||||
@@ -157,7 +157,7 @@ module.exports = {
|
||||
return this.verifyScaffolding(folder, () => {
|
||||
debug(`copying example.json into ${folder}`)
|
||||
|
||||
return this._copy(cypressEx.getPathToFixture(), folder, config)
|
||||
return this._copy('fixtures/example.json', folder, config)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -172,14 +172,10 @@ module.exports = {
|
||||
return this.verifyScaffolding(folder, () => {
|
||||
debug(`copying commands.js and index.js to ${folder}`)
|
||||
|
||||
return cypressEx.getPathToSupportFiles()
|
||||
.then((supportFiles) => {
|
||||
return Promise.all(
|
||||
supportFiles.map((supportFilePath) => {
|
||||
return this._copy(supportFilePath, folder, config)
|
||||
}),
|
||||
)
|
||||
})
|
||||
return Promise.join(
|
||||
this._copy('support/commands.js', folder, config),
|
||||
this._copy('support/index.js', folder, config),
|
||||
)
|
||||
})
|
||||
},
|
||||
|
||||
@@ -194,7 +190,7 @@ module.exports = {
|
||||
return this.verifyScaffolding(folder, () => {
|
||||
debug(`copying index.js into ${folder}`)
|
||||
|
||||
return this._copy(cypressEx.getPathToPlugins(), folder, config)
|
||||
return this._copy('plugins/index.js', folder, config)
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -14,11 +14,11 @@
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: "element"}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: "optional"}, (subject, options) => { ... })
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
@@ -342,7 +342,7 @@ describe('lib/scaffold', () => {
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
}\
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@ const isRightBranch = () => {
|
||||
process.env.APPVEYOR_REPO_COMMIT_MESSAGE || ''
|
||||
).includes('[build binary]')
|
||||
|
||||
const branchesToBuildBinary = ['develop', 'v6.0-release']
|
||||
const branchesToBuildBinary = ['develop', 'revert-create-cypress-tests']
|
||||
|
||||
return branchesToBuildBinary.includes(branch) || shouldForceBinaryBuild
|
||||
}
|
||||
|
||||
@@ -213,28 +213,6 @@
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/core@^7.5.4":
|
||||
version "7.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8"
|
||||
integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.10.4"
|
||||
"@babel/generator" "^7.12.1"
|
||||
"@babel/helper-module-transforms" "^7.12.1"
|
||||
"@babel/helpers" "^7.12.1"
|
||||
"@babel/parser" "^7.12.3"
|
||||
"@babel/template" "^7.10.4"
|
||||
"@babel/traverse" "^7.12.1"
|
||||
"@babel/types" "^7.12.1"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.1"
|
||||
json5 "^2.1.2"
|
||||
lodash "^4.17.19"
|
||||
resolve "^1.3.2"
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.11.5", "@babel/generator@^7.11.6", "@babel/generator@^7.4.0", "@babel/generator@^7.4.4", "@babel/generator@^7.6.0", "@babel/generator@^7.9.0", "@babel/generator@^7.9.3":
|
||||
version "7.11.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620"
|
||||
@@ -244,15 +222,6 @@
|
||||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.1.tgz#0d70be32bdaa03d7c51c8597dda76e0df1f15468"
|
||||
integrity sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.12.1"
|
||||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.12.5", "@babel/generator@^7.7.7":
|
||||
version "7.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.5.tgz#a2c50de5c8b6d708ab95be5e6053936c1884a4de"
|
||||
@@ -317,17 +286,6 @@
|
||||
"@babel/helper-replace-supers" "^7.10.4"
|
||||
"@babel/helper-split-export-declaration" "^7.10.4"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz#3c45998f431edd4a9214c5f1d3ad1448a6137f6e"
|
||||
integrity sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==
|
||||
dependencies:
|
||||
"@babel/helper-function-name" "^7.10.4"
|
||||
"@babel/helper-member-expression-to-functions" "^7.12.1"
|
||||
"@babel/helper-optimise-call-expression" "^7.10.4"
|
||||
"@babel/helper-replace-supers" "^7.12.1"
|
||||
"@babel/helper-split-export-declaration" "^7.10.4"
|
||||
|
||||
"@babel/helper-create-regexp-features-plugin@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8"
|
||||
@@ -384,13 +342,6 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.11.0"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz#fba0f2fcff3fba00e6ecb664bb5e6e26e2d6165c"
|
||||
integrity sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.12.1"
|
||||
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.8.3":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
|
||||
@@ -398,13 +349,6 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.10.4"
|
||||
|
||||
"@babel/helper-module-imports@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.1.tgz#1644c01591a15a2f084dd6d092d9430eb1d1216c"
|
||||
integrity sha512-ZeC1TlMSvikvJNy1v/wPIazCu3NdOwgYZLIkmIyAsGhqkNpiDoQQRmaCK8YP4Pq3GPTLPV9WXaPCJKvx06JxKA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.12.1"
|
||||
|
||||
"@babel/helper-module-transforms@^7.10.1", "@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.11.0", "@babel/helper-module-transforms@^7.9.0":
|
||||
version "7.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359"
|
||||
@@ -418,21 +362,6 @@
|
||||
"@babel/types" "^7.11.0"
|
||||
lodash "^4.17.19"
|
||||
|
||||
"@babel/helper-module-transforms@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c"
|
||||
integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.12.1"
|
||||
"@babel/helper-replace-supers" "^7.12.1"
|
||||
"@babel/helper-simple-access" "^7.12.1"
|
||||
"@babel/helper-split-export-declaration" "^7.11.0"
|
||||
"@babel/helper-validator-identifier" "^7.10.4"
|
||||
"@babel/template" "^7.10.4"
|
||||
"@babel/traverse" "^7.12.1"
|
||||
"@babel/types" "^7.12.1"
|
||||
lodash "^4.17.19"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
|
||||
@@ -473,16 +402,6 @@
|
||||
"@babel/traverse" "^7.10.4"
|
||||
"@babel/types" "^7.10.4"
|
||||
|
||||
"@babel/helper-replace-supers@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.1.tgz#f15c9cc897439281891e11d5ce12562ac0cf3fa9"
|
||||
integrity sha512-zJjTvtNJnCFsCXVi5rUInstLd/EIVNmIKA1Q9ynESmMBWPWd+7sdR+G4/wdu+Mppfep0XLyG2m7EBPvjCeFyrw==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.12.1"
|
||||
"@babel/helper-optimise-call-expression" "^7.10.4"
|
||||
"@babel/traverse" "^7.12.1"
|
||||
"@babel/types" "^7.12.1"
|
||||
|
||||
"@babel/helper-simple-access@^7.10.1", "@babel/helper-simple-access@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461"
|
||||
@@ -491,13 +410,6 @@
|
||||
"@babel/template" "^7.10.4"
|
||||
"@babel/types" "^7.10.4"
|
||||
|
||||
"@babel/helper-simple-access@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136"
|
||||
integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.12.1"
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.11.0":
|
||||
version "7.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729"
|
||||
@@ -536,15 +448,6 @@
|
||||
"@babel/traverse" "^7.10.4"
|
||||
"@babel/types" "^7.10.4"
|
||||
|
||||
"@babel/helpers@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.1.tgz#8a8261c1d438ec18cb890434df4ec768734c1e79"
|
||||
integrity sha512-9JoDSBGoWtmbay98efmT2+mySkwjzeFeAL9BuWNoVQpkPFQF8SIIFUfY5os9u8wVzglzoiPRSW7cuJmBDUt43g==
|
||||
dependencies:
|
||||
"@babel/template" "^7.10.4"
|
||||
"@babel/traverse" "^7.12.1"
|
||||
"@babel/types" "^7.12.1"
|
||||
|
||||
"@babel/helpers@^7.7.4":
|
||||
version "7.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e"
|
||||
@@ -568,11 +471,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037"
|
||||
integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==
|
||||
|
||||
"@babel/parser@^7.12.1", "@babel/parser@^7.12.3":
|
||||
version "7.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd"
|
||||
integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw==
|
||||
|
||||
"@babel/parser@^7.12.7", "@babel/parser@^7.7.7":
|
||||
version "7.12.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056"
|
||||
@@ -877,13 +775,6 @@
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.1.tgz#460ba9d77077653803c3dd2e673f76d66b4029e5"
|
||||
integrity sha512-UZNEcCY+4Dp9yYRCAHrHDU+9ZXLYaY9MgBXSRLkB9WjYFRR6quJBumfVrEkUxrePPBwFcpWfNKXqVRQQtm7mMA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
|
||||
"@babel/plugin-transform-arrow-functions@^7.10.4", "@babel/plugin-transform-arrow-functions@^7.2.0", "@babel/plugin-transform-arrow-functions@^7.8.3":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd"
|
||||
@@ -1250,15 +1141,6 @@
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
"@babel/plugin-syntax-typescript" "^7.10.4"
|
||||
|
||||
"@babel/plugin-transform-typescript@^7.2.0":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.12.1.tgz#d92cc0af504d510e26a754a7dbc2e5c8cd9c7ab4"
|
||||
integrity sha512-VrsBByqAIntM+EYMqSm59SiMEf7qkmI9dqMt6RbD/wlwueWmYcI0FFK5Fj47pP6DRZm+3teXjosKlwcZJ5lIMw==
|
||||
dependencies:
|
||||
"@babel/helper-create-class-features-plugin" "^7.12.1"
|
||||
"@babel/helper-plugin-utils" "^7.10.4"
|
||||
"@babel/plugin-syntax-typescript" "^7.12.1"
|
||||
|
||||
"@babel/plugin-transform-unicode-escapes@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007"
|
||||
@@ -1668,7 +1550,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.10.4", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.5.4", "@babel/template@^7.6.0", "@babel/template@^7.8.6":
|
||||
"@babel/template@^7.10.4", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0", "@babel/template@^7.8.6":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
|
||||
integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
|
||||
@@ -1701,25 +1583,10 @@
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.19"
|
||||
|
||||
"@babel/traverse@^7.12.1":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e"
|
||||
integrity sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.10.4"
|
||||
"@babel/generator" "^7.12.1"
|
||||
"@babel/helper-function-name" "^7.10.4"
|
||||
"@babel/helper-split-export-declaration" "^7.11.0"
|
||||
"@babel/parser" "^7.12.1"
|
||||
"@babel/types" "^7.12.1"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.19"
|
||||
|
||||
"@babel/traverse@^7.12.5", "@babel/traverse@^7.7.4":
|
||||
version "7.12.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.8.tgz#c1c2983bf9ba0f4f0eaa11dff7e77fa63307b2a4"
|
||||
integrity sha512-EIRQXPTwFEGRZyu6gXbjfpNORN1oZvwuzJbxcXjAgWV0iqXYDszN1Hx3FVm6YgZfu1ZQbCVAk3l+nIw95Xll9Q==
|
||||
version "7.12.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.7.tgz#572a722408681cef17d6b0bef69ef2e728ca69f1"
|
||||
integrity sha512-nMWaqsQEeSvMNypswUDzjqQ+0rR6pqCtoQpsqGJC4/Khm9cISwPTSpai57F6/jDaOoEGz8yE/WxcO3PV6tKSmQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.10.4"
|
||||
"@babel/generator" "^7.12.5"
|
||||
@@ -1749,15 +1616,6 @@
|
||||
lodash "^4.17.13"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.12.1", "@babel/types@^7.5.0":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.1.tgz#e109d9ab99a8de735be287ee3d6a9947a190c4ae"
|
||||
integrity sha512-BzSY3NJBKM4kyatSOWh3D/JJ2O3CVzBybHWxtgxnggaxEuaSTTDqeiSb/xk9lrkw2Tbqyivw5ZU4rT+EfznQsA==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.10.4"
|
||||
lodash "^4.17.19"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.7.4":
|
||||
version "7.12.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.7.tgz#6039ff1e242640a29452c9ae572162ec9a8f5d13"
|
||||
@@ -5148,17 +5006,6 @@
|
||||
"@types/babel__template" "*"
|
||||
"@types/babel__traverse" "*"
|
||||
|
||||
"@types/babel__core@^7.1.2":
|
||||
version "7.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.11.tgz#7fae4660a009a4031e293f25b213f142d823b3c4"
|
||||
integrity sha512-E5nSOzrjnvhURYnbOR2dClTqcyhPbPvtEwLHf7JJADKedPbcZsoJVfP+I2vBNfBjz4bnZIuhL/tNmRi5nJ7Jlw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.1.0"
|
||||
"@babel/types" "^7.0.0"
|
||||
"@types/babel__generator" "*"
|
||||
"@types/babel__template" "*"
|
||||
"@types/babel__traverse" "*"
|
||||
|
||||
"@types/babel__generator@*":
|
||||
version "7.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04"
|
||||
@@ -5627,13 +5474,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
|
||||
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
|
||||
|
||||
"@types/ora@^3.2.0":
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/ora/-/ora-3.2.0.tgz#b2f65d1283a8f36d8b0f9ee767e0732a2f429362"
|
||||
integrity sha512-jll99xUKpiFbIFZSQcxm4numfsLaOWBzWNaRk3PvTSE7BPqTzzOCFmS0mQ7m8qkTfmYhuYbehTGsxkvRLPC++w==
|
||||
dependencies:
|
||||
ora "*"
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
@@ -8871,7 +8711,7 @@ bindings@^1.5.0:
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bl@^4.0.3:
|
||||
bl@^4.0.1, bl@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489"
|
||||
integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==
|
||||
@@ -9951,9 +9791,9 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, can
|
||||
integrity sha512-EHfInJHoQTmlMdVZrEc5gmwPc0zyN/hVufmGHPbVNQwlk7tJfCmQ2ysRZMY2MeleBivALUTyyxXnQjK18XrVpA==
|
||||
|
||||
caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001113:
|
||||
version "1.0.30001161"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001161.tgz#64f7ffe79ee780b8c92843ff34feb36cea4651e0"
|
||||
integrity sha512-JharrCDxOqPLBULF9/SPa6yMcBRTjZARJ6sc3cuKrPfyIk64JN6kuMINWqA99Xc8uElMFcROliwtz0n9pYej+g==
|
||||
version "1.0.30001159"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001159.tgz#bebde28f893fa9594dadcaa7d6b8e2aa0299df20"
|
||||
integrity sha512-w9Ph56jOsS8RL20K9cLND3u/+5WASWdhC/PPrf+V3/HsM3uHOavWOR1Xzakbv4Puo/srmPHudkmCRWM7Aq+/UA==
|
||||
|
||||
capture-exit@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -10068,7 +9908,7 @@ chai@4.2.0:
|
||||
pathval "^1.1.0"
|
||||
type-detect "^4.0.5"
|
||||
|
||||
chalk@*, chalk@4.1.0, chalk@^4.0.0, chalk@^4.1.0:
|
||||
chalk@*, chalk@^4.0.0, chalk@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
|
||||
integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
|
||||
@@ -10538,23 +10378,6 @@ cli-cursor@^3.1.0:
|
||||
dependencies:
|
||||
restore-cursor "^3.1.0"
|
||||
|
||||
cli-highlight@2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.4.tgz#098cb642cf17f42adc1c1145e07f960ec4d7522b"
|
||||
integrity sha512-s7Zofobm20qriqDoU9sXptQx0t2R9PEgac92mENNm7xaEe1hn71IIMsXMK+6encA6WRCWWxIGQbipr3q998tlQ==
|
||||
dependencies:
|
||||
chalk "^3.0.0"
|
||||
highlight.js "^9.6.0"
|
||||
mz "^2.4.0"
|
||||
parse5 "^5.1.1"
|
||||
parse5-htmlparser2-tree-adapter "^5.1.1"
|
||||
yargs "^15.0.0"
|
||||
|
||||
cli-spinners@^2.4.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.5.0.tgz#12763e47251bf951cb75c201dfa58ff1bcb2d047"
|
||||
integrity sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==
|
||||
|
||||
cli-table3@0.5.1, cli-table3@^0.5.0, cli-table3@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202"
|
||||
@@ -11008,11 +10831,6 @@ commander@2.x.x, commander@^2.11.0, commander@^2.12.1, commander@^2.13.0, comman
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
commander@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc"
|
||||
integrity sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==
|
||||
|
||||
commander@^4.0.1, commander@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
||||
@@ -13580,9 +13398,9 @@ electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.378, electron-to-chromi
|
||||
integrity sha512-uSEI0XZ//5ic+0NdOqlxp0liCD44ck20OAGyLMSymIWTEAtHKVJi6JM18acOnRgUgX7Q65QqnI+sNncNvIy8ew==
|
||||
|
||||
electron-to-chromium@^1.3.488:
|
||||
version "1.3.606"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.606.tgz#6ef2655d9a7c1b447dfdd6344657d00461a65e26"
|
||||
integrity sha512-+/2yPHwtNf6NWKpaYt0KoqdSZ6Qddt6nDfH/pnhcrHq9hSb23e5LFy06Mlf0vF2ykXvj7avJ597psqcbKnG5YQ==
|
||||
version "1.3.603"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.603.tgz#1b71bec27fb940eccd79245f6824c63d5f7e8abf"
|
||||
integrity sha512-J8OHxOeJkoSLgBXfV9BHgKccgfLMHh+CoeRo6wJsi6m0k3otaxS/5vrHpMNSEYY4MISwewqanPOuhAtuE8riQQ==
|
||||
|
||||
electron@11.0.2:
|
||||
version "11.0.2"
|
||||
@@ -17343,11 +17161,6 @@ highlight.js@^8.5.0:
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-8.9.1.tgz#b8a9c5493212a9392f0222b649c9611497ebfb88"
|
||||
integrity sha1-uKnFSTISqTkvAiK2SclhFJfr+4g=
|
||||
|
||||
highlight.js@^9.6.0:
|
||||
version "9.18.5"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825"
|
||||
integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==
|
||||
|
||||
history@5.0.0-beta.4:
|
||||
version "5.0.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-5.0.0-beta.4.tgz#7fd3bb1f6c75d00d9b5112a816766bfc72d1a3cd"
|
||||
@@ -18162,25 +17975,6 @@ inquirer@7.0.4:
|
||||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@7.3.3, inquirer@^7.0.0:
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
|
||||
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-width "^3.0.0"
|
||||
external-editor "^3.0.3"
|
||||
figures "^3.0.0"
|
||||
lodash "^4.17.19"
|
||||
mute-stream "0.0.8"
|
||||
run-async "^2.4.0"
|
||||
rxjs "^6.6.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^6.2.0:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca"
|
||||
@@ -18200,6 +17994,25 @@ inquirer@^6.2.0:
|
||||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inquirer@^7.0.0:
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
|
||||
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
|
||||
dependencies:
|
||||
ansi-escapes "^4.2.1"
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-width "^3.0.0"
|
||||
external-editor "^3.0.3"
|
||||
figures "^3.0.0"
|
||||
lodash "^4.17.19"
|
||||
mute-stream "0.0.8"
|
||||
run-async "^2.4.0"
|
||||
rxjs "^6.6.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
insert-module-globals@^7.0.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.2.0.tgz#ec87e5b42728479e327bd5c5c71611ddfb4752ba"
|
||||
@@ -18604,11 +18417,6 @@ is-integer@^1.0.4:
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
is-interactive@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
|
||||
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||
|
||||
is-map@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1"
|
||||
@@ -24121,20 +23929,6 @@ optionator@^0.8.1, optionator@^0.8.2, optionator@^0.8.3:
|
||||
type-check "~0.3.2"
|
||||
word-wrap "~1.2.3"
|
||||
|
||||
ora@*, ora@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8"
|
||||
integrity sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-spinners "^2.4.0"
|
||||
is-interactive "^1.0.0"
|
||||
log-symbols "^4.0.0"
|
||||
mute-stream "0.0.8"
|
||||
strip-ansi "^6.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
ordered-read-streams@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
|
||||
@@ -24707,13 +24501,6 @@ parse5-html-rewriting-stream@5.1.1:
|
||||
parse5 "^5.1.1"
|
||||
parse5-sax-parser "^5.1.1"
|
||||
|
||||
parse5-htmlparser2-tree-adapter@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-5.1.1.tgz#e8c743d4e92194d5293ecde2b08be31e67461cbc"
|
||||
integrity sha512-CF+TKjXqoqyDwHqBhFQ+3l5t83xYi6fVT1tQNg+Ye0JRLnTxWvIroCjEp1A0k4lneHNBGnICUf0cfYVYGEazqw==
|
||||
dependencies:
|
||||
parse5 "^5.1.1"
|
||||
|
||||
parse5-sax-parser@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5-sax-parser/-/parse5-sax-parser-5.1.1.tgz#02834a9d08b23ea2d99584841c38be09d5247a15"
|
||||
@@ -30923,7 +30710,18 @@ tar-fs@^2.0.0:
|
||||
pump "^3.0.0"
|
||||
tar-stream "^2.0.0"
|
||||
|
||||
tar-stream@^2.0.0, tar-stream@^2.1.4:
|
||||
tar-stream@^2.0.0:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.3.tgz#1e2022559221b7866161660f118255e20fa79e41"
|
||||
integrity sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==
|
||||
dependencies:
|
||||
bl "^4.0.1"
|
||||
end-of-stream "^1.4.1"
|
||||
fs-constants "^1.0.0"
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
tar-stream@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa"
|
||||
integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==
|
||||
@@ -33144,7 +32942,7 @@ wbuf@^1.1.0, wbuf@^1.7.3:
|
||||
dependencies:
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
wcwidth@^1.0.0, wcwidth@^1.0.1:
|
||||
wcwidth@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
||||
integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
|
||||
@@ -34530,7 +34328,7 @@ yargs@^14.2.2, yargs@^14.2.3:
|
||||
y18n "^4.0.0"
|
||||
yargs-parser "^15.0.1"
|
||||
|
||||
yargs@^15.0.0, yargs@^15.0.1, yargs@^15.0.2, yargs@^15.3.1:
|
||||
yargs@^15.0.1, yargs@^15.0.2, yargs@^15.3.1:
|
||||
version "15.4.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
|
||||
integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
|
||||
|
||||
Reference in New Issue
Block a user