Skip to content

Commit 10c7f92

Browse files
feat: scaffold and register cy.mount command for CT (#20933)
* fix: small ui tweaks for switch testing type (#20901) * fix: add missing component-index.html (#20926) * move files from data-context to scaffold-config * dynamically modify support file based on selected framework * scaffold correct supportFile for CT based on framework * update scaffolded files Co-authored-by: Zachary Williams <ZachJW34@gmail.com>
1 parent cc5d32b commit 10c7f92

File tree

8 files changed

+363
-75
lines changed

8 files changed

+363
-75
lines changed

packages/data-context/src/actions/WizardActions.ts

Lines changed: 13 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CodeLanguageEnum, NexusGenEnums, NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen'
22
import { CODE_LANGUAGES } from '@packages/types'
3-
import { detect, WIZARD_FRAMEWORKS, WIZARD_BUNDLERS } from '@packages/scaffold-config'
3+
import { detect, WIZARD_FRAMEWORKS, WIZARD_BUNDLERS, commandsFileBody, supportFileComponent, supportFileE2E } from '@packages/scaffold-config'
44
import assert from 'assert'
55
import dedent from 'dedent'
66
import path from 'path'
@@ -206,7 +206,18 @@ export class WizardActions {
206206
// @ts-ignore
207207
await this.ctx.fs.mkdir(supportDir, { recursive: true })
208208

209-
const fileContent = fileName === 'commands' ? this.commandsFileBody(language) : this.supportFileBody(fileName, language)
209+
let fileContent: string | undefined
210+
211+
if (fileName === 'commands') {
212+
fileContent = commandsFileBody(language)
213+
} else if (fileName === 'e2e') {
214+
fileContent = supportFileE2E(language)
215+
} else if (fileName === 'component') {
216+
assert(this.ctx.coreData.wizard.chosenFramework)
217+
fileContent = supportFileComponent(language, this.ctx.coreData.wizard.chosenFramework)
218+
}
219+
220+
assert(fileContent)
210221

211222
await this.scaffoldFile(supportFile, fileContent, 'Scaffold default support file')
212223

@@ -388,79 +399,8 @@ export class WizardActions {
388399
private ensureDir (type: 'component' | 'e2e' | 'fixtures') {
389400
return this.ctx.fs.ensureDir(path.join(this.projectRoot, 'cypress', type))
390401
}
391-
392-
private supportFileBody (fileName: 'e2e' | 'component', language: CodeLanguageEnum) {
393-
return dedent`
394-
// ***********************************************************
395-
// This example support/${fileName}.${language} is processed and
396-
// loaded automatically before your test files.
397-
//
398-
// This is a great place to put global configuration and
399-
// behavior that modifies Cypress.
400-
//
401-
// You can change the location of this file or turn off
402-
// automatically serving support files with the
403-
// 'supportFile' configuration option.
404-
//
405-
// You can read more here:
406-
// https://on.cypress.io/configuration
407-
// ***********************************************************
408-
409-
// Import commands.js using ES2015 syntax:
410-
import './commands'
411-
412-
// Alternatively you can use CommonJS syntax:
413-
// require('./commands')
414-
`
415-
}
416-
417-
private commandsFileBody (language: CodeLanguageEnum) {
418-
return dedent`
419-
${language === 'ts' ? '/// <reference types="cypress" />' : ''}
420-
// ***********************************************
421-
// This example commands.${language} shows you how to
422-
// create various custom commands and overwrite
423-
// existing commands.
424-
//
425-
// For more comprehensive examples of custom
426-
// commands please read more here:
427-
// https://on.cypress.io/custom-commands
428-
// ***********************************************
429-
//
430-
//
431-
// -- This is a parent command --
432-
// Cypress.Commands.add('login', (email, password) => { ... })
433-
//
434-
//
435-
// -- This is a child command --
436-
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
437-
//
438-
//
439-
// -- This is a dual command --
440-
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
441-
//
442-
//
443-
// -- This will overwrite an existing command --
444-
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
445-
${language === 'ts' ? COMMAND_TYPES : ''}
446-
`
447-
}
448402
}
449403

450-
const COMMAND_TYPES = dedent`
451-
//
452-
// declare global {
453-
// namespace Cypress {
454-
// interface Chainable {
455-
// login(email: string, password: string): Chainable<void>
456-
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
457-
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
458-
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
459-
// }
460-
// }
461-
// }
462-
`
463-
464404
const E2E_SCAFFOLD_BODY = dedent`
465405
e2e: {
466406
setupNodeEvents(on, config) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { CodeLanguage } from '@packages/types'
2+
import dedent from 'dedent'
3+
4+
const COMMAND_TYPES = dedent`
5+
//
6+
// declare global {
7+
// namespace Cypress {
8+
// interface Chainable {
9+
// login(email: string, password: string): Chainable<void>
10+
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
11+
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
12+
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
13+
// }
14+
// }
15+
// }
16+
`
17+
18+
export function commandsFileBody (language: CodeLanguage['type']) {
19+
return dedent`
20+
${language === 'ts' ? '/// <reference types="cypress" />' : ''}
21+
// ***********************************************
22+
// This example commands.${language} shows you how to
23+
// create various custom commands and overwrite
24+
// existing commands.
25+
//
26+
// For more comprehensive examples of custom
27+
// commands please read more here:
28+
// https://on.cypress.io/custom-commands
29+
// ***********************************************
30+
//
31+
//
32+
// -- This is a parent command --
33+
// Cypress.Commands.add('login', (email, password) => { ... })
34+
//
35+
//
36+
// -- This is a child command --
37+
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
38+
//
39+
//
40+
// -- This is a dual command --
41+
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
42+
//
43+
//
44+
// -- This will overwrite an existing command --
45+
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
46+
${language === 'ts' ? COMMAND_TYPES : ''}
47+
`
48+
}

packages/scaffold-config/src/frameworks.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export const WIZARD_FRAMEWORKS = [
121121
createCypressConfig,
122122
codeGenFramework: 'react',
123123
glob: '*.{js,jsx,tsx}',
124+
mountModule: 'cypress/react',
124125
},
125126
{
126127
type: 'vueclivue2',
@@ -140,6 +141,7 @@ export const WIZARD_FRAMEWORKS = [
140141
createCypressConfig,
141142
codeGenFramework: 'vue',
142143
glob: '*.vue',
144+
mountModule: 'cypress/vue2',
143145
},
144146
{
145147
type: 'vueclivue3',
@@ -159,6 +161,7 @@ export const WIZARD_FRAMEWORKS = [
159161
createCypressConfig,
160162
codeGenFramework: 'vue',
161163
glob: '*.vue',
164+
mountModule: 'cypress/vue',
162165
},
163166
{
164167
type: 'nextjs',
@@ -177,6 +180,7 @@ export const WIZARD_FRAMEWORKS = [
177180
createCypressConfig,
178181
codeGenFramework: 'react',
179182
glob: '*.{js,jsx,tsx}',
183+
mountModule: 'cypress/react',
180184
},
181185
{
182186
type: 'nuxtjs',
@@ -195,6 +199,7 @@ export const WIZARD_FRAMEWORKS = [
195199
createCypressConfig,
196200
codeGenFramework: 'vue',
197201
glob: '*.vue',
202+
mountModule: 'cypress/vue2',
198203
},
199204
{
200205
type: 'vue2',
@@ -213,6 +218,7 @@ export const WIZARD_FRAMEWORKS = [
213218
createCypressConfig,
214219
codeGenFramework: 'vue',
215220
glob: '*.vue',
221+
mountModule: 'cypress/vue2',
216222
},
217223
{
218224
type: 'vue3',
@@ -231,6 +237,7 @@ export const WIZARD_FRAMEWORKS = [
231237
createCypressConfig,
232238
codeGenFramework: 'vue',
233239
glob: '*.vue',
240+
mountModule: 'cypress/vue',
234241
},
235242
{
236243
type: 'react',
@@ -249,5 +256,6 @@ export const WIZARD_FRAMEWORKS = [
249256
createCypressConfig,
250257
codeGenFramework: 'react',
251258
glob: '*.{js,jsx,tsx}',
259+
mountModule: 'cypress/react',
252260
},
253261
] as const
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* eslint-disable padding-line-between-statements */
22
// created by autobarrel, do not modify directly
33

4+
export * from './commandFile'
45
export * from './dependencies'
56
export * from './detect'
67
export * from './frameworks'
8+
export * from './supportFile'
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import type { CodeLanguage } from '@packages/types'
2+
import dedent from 'dedent'
3+
import type { WizardFrontendFramework } from '.'
4+
5+
export function supportFileE2E (language: CodeLanguage['type']) {
6+
return dedent`
7+
// ***********************************************************
8+
// This example support/e2e.${language} is processed and
9+
// loaded automatically before your test files.
10+
//
11+
// This is a great place to put global configuration and
12+
// behavior that modifies Cypress.
13+
//
14+
// You can change the location of this file or turn off
15+
// automatically serving support files with the
16+
// 'supportFile' configuration option.
17+
//
18+
// You can read more here:
19+
// https://on.cypress.io/configuration
20+
// ***********************************************************
21+
22+
// Import commands.js using ES2015 syntax:
23+
import './commands'
24+
25+
// Alternatively you can use CommonJS syntax:
26+
// require('./commands')
27+
`
28+
}
29+
30+
export function supportFileComponent (language: CodeLanguage['type'], framework: WizardFrontendFramework) {
31+
const supportFileTemplate = dedent`
32+
// ***********************************************************
33+
// This example support/component.${language} is processed and
34+
// loaded automatically before your test files.
35+
//
36+
// This is a great place to put global configuration and
37+
// behavior that modifies Cypress.
38+
//
39+
// You can change the location of this file or turn off
40+
// automatically serving support files with the
41+
// 'supportFile' configuration option.
42+
//
43+
// You can read more here:
44+
// https://on.cypress.io/configuration
45+
// ***********************************************************
46+
47+
// Import commands.js using ES2015 syntax:
48+
import './commands'
49+
50+
// Alternatively you can use CommonJS syntax:
51+
// require('./commands')
52+
`
53+
54+
const exampleUse = dedent`
55+
// Example use:
56+
// cy.mount(${framework.mountModule === 'cypress/react' ? '<MyComponent />' : 'MyComponent'})
57+
`
58+
59+
const NEWLINE = '\n\n'
60+
61+
if (language === 'ts') {
62+
const registerMount = dedent`
63+
import { mount } from '${framework.mountModule}'
64+
import type { MountReturn } from '${framework.mountModule}'
65+
66+
// Augment the Cypress namespace to include type definitions for
67+
// your custom command.
68+
// Alternatively, can be defined in cypress/support/component.d.ts
69+
// with a <reference path="./component" /> at the top of your spec.
70+
declare global {
71+
namespace Cypress {
72+
interface Chainable {
73+
mount: typeof mount
74+
}
75+
}
76+
}
77+
78+
Cypress.Commands.add('mount', mount)
79+
`
80+
81+
return [supportFileTemplate, registerMount, exampleUse].join(NEWLINE)
82+
}
83+
84+
const registerMount = dedent`
85+
import { mount } from '${framework.mountModule}'
86+
87+
Cypress.Commands.add('mount', mount)
88+
`
89+
90+
return [supportFileTemplate, registerMount, exampleUse].join(NEWLINE)
91+
}

0 commit comments

Comments
 (0)