mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-16 04:02:50 -06:00
fix: various minor migration bugs (#21195)
* correct indentation * update formatting * add comments * update tsconfig.json * Update packages/data-context/src/sources/migration/codegen.ts Co-authored-by: Blue F <blue@cypress.io> * Update packages/data-context/src/sources/migration/codegen.ts Co-authored-by: Blue F <blue@cypress.io> Co-authored-by: Blue F <blue@cypress.io>
This commit is contained in:
@@ -180,3 +180,16 @@ export default defineConfig({
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
exports['cypress.config.js generation generates correct config for component testing migration with custom testFiles glob 1'] = `
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({
|
||||
component: {
|
||||
setupNodeEvents(on, config) {},
|
||||
componentFolder: '.',
|
||||
specPattern: './**/*.spec.cy.{js,ts,jsx,tsx}',
|
||||
},
|
||||
})
|
||||
|
||||
`
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.8.3",
|
||||
"@babel/generator": "7.17.9",
|
||||
"@babel/parser": "7.13.0",
|
||||
"@urql/core": "2.3.1",
|
||||
"@urql/exchange-execute": "1.1.0",
|
||||
|
||||
@@ -184,9 +184,12 @@ export class MigrationActions {
|
||||
const hasCustomComponentFolder = componentFolder !== 'cypress/component'
|
||||
const hasCustomComponentTestFiles = !isDefaultTestFiles(legacyConfigForMigration, 'component')
|
||||
|
||||
const hasComponentTesting = componentFolder
|
||||
? await hasSpecFile(this.ctx.currentProject, componentFolder, componentTestFiles)
|
||||
: false
|
||||
// A user is considered to "have" component testing if either
|
||||
// 1. they have a default component folder (cypress/component) with at least 1 spec file
|
||||
// OR
|
||||
// 2. they have configured a non-default componentFolder (even if it doesn't have any specs.)
|
||||
const hasSpecInDefaultComponentFolder = await hasSpecFile(this.ctx.currentProject, componentFolder, componentTestFiles)
|
||||
const hasComponentTesting = (hasCustomComponentFolder || hasSpecInDefaultComponentFolder) ?? false
|
||||
|
||||
this.ctx.update((coreData) => {
|
||||
coreData.migration.flags = {
|
||||
|
||||
@@ -12,6 +12,8 @@ import Debug from 'debug'
|
||||
import dedent from 'dedent'
|
||||
import { hasDefaultExport } from './parserUtils'
|
||||
import type { LegacyCypressConfigJson } from '..'
|
||||
import { parse } from '@babel/parser'
|
||||
import generate from '@babel/generator'
|
||||
|
||||
const debug = Debug('cypress:data-context:sources:migration:codegen')
|
||||
|
||||
@@ -168,18 +170,24 @@ function createCypressConfig (config: ConfigOptions, pluginPath: string | undefi
|
||||
|
||||
if (defineConfigAvailable(options.projectRoot)) {
|
||||
if (options.hasTypescript) {
|
||||
return formatConfig(
|
||||
`import { defineConfig } from 'cypress'
|
||||
return formatConfig(dedent`
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({${globalString}${e2eString}${componentString}})`,
|
||||
)
|
||||
export default defineConfig({
|
||||
${globalString}
|
||||
${e2eString}
|
||||
${componentString}
|
||||
})`)
|
||||
}
|
||||
|
||||
return formatConfig(
|
||||
`const { defineConfig } = require('cypress')
|
||||
return formatConfig(dedent`
|
||||
const { defineConfig } = require('cypress')
|
||||
|
||||
module.exports = defineConfig({${globalString}${e2eString}${componentString}})`,
|
||||
)
|
||||
module.exports = defineConfig({
|
||||
${globalString}
|
||||
${e2eString}
|
||||
${componentString}
|
||||
})`)
|
||||
}
|
||||
|
||||
if (options.hasTypescript) {
|
||||
@@ -245,7 +253,11 @@ export interface RelativeSpec {
|
||||
*
|
||||
* NOTE: this is what we use to see if CT/E2E is set up
|
||||
*/
|
||||
export async function hasSpecFile (projectRoot: string, folder: string, glob: string | string[]): Promise<boolean> {
|
||||
export async function hasSpecFile (projectRoot: string, folder: string | false, glob: string | string[]): Promise<boolean> {
|
||||
if (!folder) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (await globby(glob, {
|
||||
cwd: path.join(projectRoot, folder),
|
||||
onlyFiles: true,
|
||||
@@ -447,6 +459,65 @@ export function getSpecPattern (cfg: LegacyCypressConfigJson, testType: TestingT
|
||||
return specPattern
|
||||
}
|
||||
|
||||
function formatWithBundledBabel (config: string) {
|
||||
const ast = parse(config)
|
||||
|
||||
let { code } = generate(ast, {}, config)
|
||||
// By default babel generates imports like this:
|
||||
// const {
|
||||
// defineConfig
|
||||
// } = require('cypress');
|
||||
// So we replace them with a one-liner, since we know this will never
|
||||
// be more than one import.
|
||||
//
|
||||
// Babel also adds empty lines, for example:
|
||||
//
|
||||
// export default defineConfig({
|
||||
// component: {
|
||||
// },
|
||||
// <===== empty line
|
||||
// e2e: {
|
||||
//
|
||||
// }
|
||||
// })
|
||||
// Which we don't want, so we change those to single carriage returns.
|
||||
const replacers = [
|
||||
{
|
||||
from: dedent`
|
||||
const {
|
||||
defineConfig
|
||||
} = require('cypress');
|
||||
`,
|
||||
to: dedent`
|
||||
const { defineConfig } = require('cypress');
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
||||
from: dedent`
|
||||
import {
|
||||
defineConfig
|
||||
} from 'cypress';
|
||||
`,
|
||||
to: dedent`
|
||||
import { defineConfig } from 'cypress';
|
||||
`,
|
||||
},
|
||||
{
|
||||
from: `,\n\n`,
|
||||
to: `,\n`,
|
||||
},
|
||||
]
|
||||
|
||||
for (const rep of replacers) {
|
||||
if (code.includes(rep.from)) {
|
||||
code = code.replaceAll(rep.from, rep.to)
|
||||
}
|
||||
}
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
export function formatConfig (config: string): string {
|
||||
try {
|
||||
const prettier = require('prettier') as typeof import('prettier')
|
||||
@@ -458,6 +529,11 @@ export function formatConfig (config: string): string {
|
||||
parser: 'babel',
|
||||
})
|
||||
} catch (e) {
|
||||
return config
|
||||
// If they do not have prettier
|
||||
// We do a basic format using babel, which we
|
||||
// bundle as part of the binary.
|
||||
// We don't ship a fully fledged formatter like
|
||||
// prettier, since it's massively bloats the bundle.
|
||||
return formatWithBundledBabel(config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export function getIntegrationFolder (config: LegacyCypressConfigJson) {
|
||||
return config.e2e?.integrationFolder ?? config.integrationFolder ?? 'cypress/integration'
|
||||
}
|
||||
|
||||
export function getComponentFolder (config: LegacyCypressConfigJson) {
|
||||
export function getComponentFolder (config: LegacyCypressConfigJson): false | string {
|
||||
if (config.component?.componentFolder === false || config.componentFolder === false) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -17,6 +17,25 @@ import { scaffoldMigrationProject, getSystemTestProject } from '../../helper'
|
||||
const projectRoot = getSystemTestProject('migration-e2e-defaults')
|
||||
|
||||
describe('cypress.config.js generation', () => {
|
||||
it('generates correct config for component testing migration with custom testFiles glob', async () => {
|
||||
const config = {
|
||||
component: {
|
||||
testFiles: '**/*.spec.cy.{js,ts,jsx,tsx}',
|
||||
componentFolder: '.',
|
||||
},
|
||||
}
|
||||
|
||||
const generatedConfig = await createConfigString(config, {
|
||||
hasE2ESpec: false,
|
||||
hasComponentTesting: true,
|
||||
hasPluginsFile: false,
|
||||
projectRoot,
|
||||
hasTypescript: false,
|
||||
})
|
||||
|
||||
snapshot(generatedConfig)
|
||||
})
|
||||
|
||||
it('should create a string when passed only a global option', async () => {
|
||||
const config: Partial<Cypress.Config> = {
|
||||
viewportWidth: 300,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"./../ts/index.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["es2020"],
|
||||
"lib": ["esnext"],
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"noImplicitAny": true,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"script"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["es2020"],
|
||||
"lib": ["esnext"],
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"noImplicitAny": true,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"./../ts/index.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["es2020"],
|
||||
"lib": ["esnext"],
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"noImplicitAny": true,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"./../ts/index.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["es2020"],
|
||||
"lib": ["esnext"],
|
||||
"types": [
|
||||
"mocha",
|
||||
"node"
|
||||
|
||||
@@ -1302,7 +1302,7 @@
|
||||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.12.10", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.15.4", "@babel/generator@^7.15.8", "@babel/generator@^7.17.9", "@babel/generator@^7.4.0", "@babel/generator@^7.4.4", "@babel/generator@^7.5.0", "@babel/generator@^7.6.0", "@babel/generator@^7.8.3", "@babel/generator@^7.9.0":
|
||||
"@babel/generator@7.17.9", "@babel/generator@^7.12.10", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.15.4", "@babel/generator@^7.15.8", "@babel/generator@^7.17.9", "@babel/generator@^7.4.0", "@babel/generator@^7.4.4", "@babel/generator@^7.5.0", "@babel/generator@^7.6.0", "@babel/generator@^7.8.3", "@babel/generator@^7.9.0":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.9.tgz#f4af9fd38fa8de143c29fce3f71852406fc1e2fc"
|
||||
integrity sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==
|
||||
|
||||
Reference in New Issue
Block a user