Skip to content

Commit f8621da

Browse files
lmiller1990ZachJW34tgriesser
authored
feat(launchpad): update CT setup and config scaffolding (#20893)
Co-authored-by: Zachary Williams <ZachJW34@gmail.com> Co-authored-by: Tim Griesser <tgriesser10@gmail.com>
1 parent 5615f79 commit f8621da

File tree

69 files changed

+46489
-1757
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+46489
-1757
lines changed

autobarrel.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
"prefix": "/* eslint-disable padding-line-between-statements */",
33
"paths": [
44
"packages/graphql/src/**/*",
5-
"packages/data-context/src/**/*",
6-
"packages/scaffold-config/src/**"
5+
"packages/data-context/src/**/*"
76
],
87
"ignore": [
98
"packages/data-context/src/gen",

npm/vite-dev-server-fresh/.percy.yml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: 2
2+
snapshot:
3+
widths:
4+
- 1280
5+
min-height: 1024
6+
discovery:
7+
network-idle-timeout: 1000

npm/vite-dev-server-fresh/cypress/e2e/react.cy.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/// <reference types="cypress" />
22
/// <reference path="../support/e2e.ts" />
3-
import type { e2eProjectDirs } from '@packages/frontend-shared/cypress/e2e/support/e2eProjectDirs'
3+
import type { fixtureDirs } from '@tooling/system-tests'
44

5-
type ProjectDirs = typeof e2eProjectDirs
5+
type ProjectDirs = typeof fixtureDirs
66

77
const VITE_REACT: ProjectDirs[number][] = ['vite2.8.6-react', 'vite2.9.1-react']
88

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: 2
2+
snapshot:
3+
widths:
4+
- 1280
5+
min-height: 1024
6+
discovery:
7+
network-idle-timeout: 1000

packages/data-context/src/DataContext.ts

-1
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,6 @@ export class DataContext {
408408
await this.initializeOpenMode()
409409
if (this.coreData.currentProject && this.coreData.currentTestingType && await this.lifecycleManager.waitForInitializeSuccess()) {
410410
this.lifecycleManager.setAndLoadCurrentTestingType(this.coreData.currentTestingType)
411-
this.lifecycleManager.scaffoldFilesIfNecessary()
412411
}
413412
} else {
414413
throw new Error(`Missing DataContext config "mode" setting, expected run | open`)

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

-20
Original file line numberDiff line numberDiff line change
@@ -334,26 +334,6 @@ export class MigrationActions {
334334
}
335335
}
336336

337-
async assertSuccessfulConfigScaffold (configFile: `cypress.config.${'js'|'ts'}`) {
338-
assert(this.ctx.currentProject)
339-
340-
// we assert the generated configuration file against one from a project that has
341-
// been verified to run correctly.
342-
// each project has an `unconfigured` and `configured` variant in `system-tests/projects`
343-
// for example vueclivue2-configured and vueclivue2-unconfigured.
344-
// after setting the project up with the launchpad, the two projects should contain the same files.
345-
346-
const configuredProject = this.ctx.project.projectTitle(this.ctx.currentProject).replace('unconfigured', 'configured')
347-
const expectedProjectConfig = path.join(__dirname, '..', '..', '..', '..', 'system-tests', 'projects', configuredProject, configFile)
348-
349-
const actual = formatConfig(await this.ctx.file.readFileInProject(configFile))
350-
const expected = formatConfig(await this.ctx.fs.readFile(expectedProjectConfig, 'utf8'))
351-
352-
if (actual !== expected) {
353-
throw Error(`Expected ${actual} to equal ${expected}`)
354-
}
355-
}
356-
357337
resetFlags () {
358338
this.ctx.update((coreData) => {
359339
const defaultFlags = makeCoreData().migration.flags

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

+68-122
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import type { CodeLanguageEnum, NexusGenEnums, NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen'
2-
import { CodeLanguage, CODE_LANGUAGES } from '@packages/types'
3-
import { Bundler, FrontendFramework, FRONTEND_FRAMEWORKS, detect } from '@packages/scaffold-config'
2+
import { CODE_LANGUAGES } from '@packages/types'
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'
7-
import fs from 'fs-extra'
87
import Debug from 'debug'
98

109
const debug = Debug('cypress:data-context:wizard-actions')
1110

1211
import type { DataContext } from '..'
1312

1413
interface WizardGetCodeComponent {
15-
chosenLanguage: CodeLanguage
16-
chosenFramework: FrontendFramework
14+
chosenLanguage: 'js' | 'ts'
15+
chosenFramework: typeof WIZARD_FRAMEWORKS[number]
1716
}
1817

1918
export class WizardActions {
@@ -29,13 +28,15 @@ export class WizardActions {
2928
return this.ctx.wizardData
3029
}
3130

32-
setFramework (framework: typeof FRONTEND_FRAMEWORKS[number]['type'] | null): void {
33-
const next = FRONTEND_FRAMEWORKS.find((x) => x.type === framework)
31+
setFramework (framework: typeof WIZARD_FRAMEWORKS[number] | null): void {
32+
const next = WIZARD_FRAMEWORKS.find((x) => x.type === framework?.type)
3433

35-
this.ctx.coreData.wizard.chosenFramework = framework
34+
this.ctx.update((coreData) => {
35+
coreData.wizard.chosenFramework = framework
36+
})
3637

3738
if (next?.supportedBundlers?.length === 1) {
38-
this.setBundler(next?.supportedBundlers?.[0].type)
39+
this.setBundler(next?.supportedBundlers?.[0])
3940

4041
return
4142
}
@@ -45,26 +46,30 @@ export class WizardActions {
4546
// if the previous bundler was incompatible with the
4647
// new framework that was selected, we need to reset it
4748
const doesNotSupportChosenBundler = (chosenBundler && !new Set(
48-
this.ctx.wizard.chosenFramework?.supportedBundlers.map((x) => x.type) || [],
49-
).has(chosenBundler)) ?? false
49+
this.ctx.coreData.wizard.chosenFramework?.supportedBundlers.map((x) => x.type) || [],
50+
).has(chosenBundler.type)) ?? false
5051

51-
const prevFramework = this.ctx.coreData.wizard.chosenFramework || ''
52+
const prevFramework = this.ctx.coreData.wizard.chosenFramework?.type ?? null
5253

53-
if (doesNotSupportChosenBundler || !['react', 'vue'].includes(prevFramework)) {
54+
if (!prevFramework || doesNotSupportChosenBundler || !['react', 'vue'].includes(prevFramework)) {
5455
this.setBundler(null)
5556
}
5657
}
5758

58-
setBundler (bundler: Bundler | null) {
59-
this.ctx.coreData.wizard.chosenBundler = bundler
59+
setBundler (bundler: typeof WIZARD_BUNDLERS[number] | null) {
60+
this.ctx.update((coreData) => {
61+
coreData.wizard.chosenBundler = bundler
62+
})
6063

61-
return this.data
64+
return this.ctx.coreData.wizard
6265
}
6366

6467
setCodeLanguage (lang: NexusGenEnums['CodeLanguageEnum']) {
65-
this.ctx.coreData.wizard.chosenLanguage = lang
68+
this.ctx.update((coreData) => {
69+
coreData.wizard.chosenLanguage = lang
70+
})
6671

67-
return this.data
72+
return this.ctx.coreData.wizard
6873
}
6974

7075
async completeSetup () {
@@ -83,48 +88,44 @@ export class WizardActions {
8388

8489
/// reset wizard status, useful for when changing to a new project
8590
resetWizard () {
86-
this.data.chosenBundler = null
87-
this.data.chosenFramework = null
88-
this.data.chosenLanguage = 'js'
91+
this.ctx.update((coreData) => {
92+
coreData.wizard.chosenBundler = null
93+
coreData.wizard.chosenFramework = null
94+
coreData.wizard.chosenLanguage = 'js'
95+
coreData.wizard.detectedBundler = null
96+
coreData.wizard.detectedFramework = null
97+
})
8998

90-
return this.data
99+
return this.ctx.coreData.wizard
91100
}
92101

93102
async initialize () {
94103
if (!this.ctx.currentProject) {
95104
return
96105
}
97106

98-
this.ctx.update((coreData) => {
99-
coreData.wizard.detectedFramework = null
100-
coreData.wizard.detectedBundler = null
101-
coreData.wizard.detectedLanguage = null
102-
})
107+
this.resetWizard()
103108

104109
await this.detectLanguage()
105110
debug('detectedLanguage %s', this.data.detectedLanguage)
106111
this.data.chosenLanguage = this.data.detectedLanguage || 'js'
107112

108-
try {
109-
const detected = detect(await fs.readJson(path.join(this.ctx.currentProject, 'package.json')))
113+
const detected = detect(this.ctx.currentProject)
110114

111-
debug('detected %o', detected)
115+
debug('detected %o', detected)
112116

113-
if (detected) {
114-
this.ctx.update((coreData) => {
115-
coreData.wizard.detectedFramework = detected.framework?.type ?? null
116-
coreData.wizard.chosenFramework = detected.framework?.type ?? null
117+
if (detected) {
118+
this.ctx.update((coreData) => {
119+
coreData.wizard.detectedFramework = detected.framework ?? null
120+
coreData.wizard.chosenFramework = detected.framework ?? null
117121

118-
if (!detected.framework?.supportedBundlers[0]) {
119-
return
120-
}
122+
if (!detected.framework?.supportedBundlers[0]) {
123+
return
124+
}
121125

122-
coreData.wizard.detectedBundler = detected.bundler || detected.framework.supportedBundlers[0].type
123-
coreData.wizard.chosenBundler = detected.bundler || detected.framework.supportedBundlers[0].type
124-
})
125-
}
126-
} catch {
127-
// Could not detect anything - no problem, no need to do anything.
126+
coreData.wizard.detectedBundler = detected.bundler || detected.framework.supportedBundlers[0]
127+
coreData.wizard.chosenBundler = detected.bundler || detected.framework.supportedBundlers[0]
128+
})
128129
}
129130
}
130131

@@ -160,7 +161,7 @@ export class WizardActions {
160161
return
161162
}
162163
case 'component': {
163-
const { chosenBundler, chosenFramework } = this.ctx.wizard
164+
const { chosenBundler, chosenFramework } = this.ctx.coreData.wizard
164165

165166
if (!chosenBundler || !chosenFramework) {
166167
return
@@ -190,15 +191,15 @@ export class WizardActions {
190191

191192
private async scaffoldComponent () {
192193
debug('scaffoldComponent')
193-
const { chosenBundler, chosenFramework, chosenLanguage } = this.ctx.wizard
194+
const { chosenBundler, chosenFramework, chosenLanguage } = this.ctx.coreData.wizard
194195

195196
assert(chosenFramework && chosenLanguage && chosenBundler)
196197

197198
return await Promise.all([
198199
this.scaffoldConfig('component'),
199200
this.scaffoldFixtures(),
200-
this.scaffoldSupport('component', chosenLanguage.type),
201-
this.scaffoldSupport('commands', chosenLanguage.type),
201+
this.scaffoldSupport('component', chosenLanguage),
202+
this.scaffoldSupport('commands', chosenLanguage),
202203
this.getComponentIndexHtml({
203204
chosenFramework,
204205
chosenLanguage,
@@ -213,7 +214,18 @@ export class WizardActions {
213214
// @ts-ignore
214215
await this.ctx.fs.mkdir(supportDir, { recursive: true })
215216

216-
const fileContent = fileName === 'commands' ? this.commandsFileBody(language) : this.supportFileBody(fileName, language)
217+
let fileContent: string | undefined
218+
219+
if (fileName === 'commands') {
220+
fileContent = commandsFileBody(language)
221+
} else if (fileName === 'e2e') {
222+
fileContent = supportFileE2E(language)
223+
} else if (fileName === 'component') {
224+
assert(this.ctx.coreData.wizard.chosenFramework)
225+
fileContent = supportFileComponent(language, this.ctx.coreData.wizard.chosenFramework)
226+
}
227+
228+
assert(fileContent)
217229

218230
await this.scaffoldFile(supportFile, fileContent, 'Scaffold default support file')
219231

@@ -230,11 +242,16 @@ export class WizardActions {
230242
if (testingType === 'component') {
231243
const chosenLanguage = CODE_LANGUAGES.find((f) => f.type === language)
232244

233-
const { chosenBundler, chosenFramework } = this.ctx.wizard
245+
const { chosenBundler, chosenFramework } = this.ctx.coreData.wizard
234246

235-
assert(chosenFramework && chosenLanguage && chosenBundler)
247+
assert(chosenFramework && chosenLanguage && chosenBundler && this.ctx.currentProject)
236248

237-
return chosenFramework.config[chosenLanguage.type](chosenBundler.type)
249+
return chosenFramework.createCypressConfig({
250+
language: chosenLanguage.type,
251+
bundler: chosenBundler.type,
252+
framework: chosenFramework.configFramework,
253+
projectRoot: this.ctx.currentProject,
254+
})
238255
}
239256

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

452-
const COMMAND_TYPES = dedent`
453-
//
454-
// declare global {
455-
// namespace Cypress {
456-
// interface Chainable {
457-
// login(email: string, password: string): Chainable<void>
458-
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
459-
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
460-
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
461-
// }
462-
// }
463-
// }
464-
`
465-
466412
const E2E_SCAFFOLD_BODY = dedent`
467413
e2e: {
468414
setupNodeEvents(on, config) {

0 commit comments

Comments
 (0)