Skip to content

Commit

Permalink
feat(launchpad): update CT setup and config scaffolding (#20893)
Browse files Browse the repository at this point in the history
Co-authored-by: Zachary Williams <ZachJW34@gmail.com>
Co-authored-by: Tim Griesser <tgriesser10@gmail.com>
  • Loading branch information
3 people authored Apr 14, 2022
1 parent 5615f79 commit f8621da
Show file tree
Hide file tree
Showing 69 changed files with 46,489 additions and 1,757 deletions.
3 changes: 1 addition & 2 deletions autobarrel.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
"prefix": "/* eslint-disable padding-line-between-statements */",
"paths": [
"packages/graphql/src/**/*",
"packages/data-context/src/**/*",
"packages/scaffold-config/src/**"
"packages/data-context/src/**/*"
],
"ignore": [
"packages/data-context/src/gen",
Expand Down
7 changes: 7 additions & 0 deletions npm/vite-dev-server-fresh/.percy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
snapshot:
widths:
- 1280
min-height: 1024
discovery:
network-idle-timeout: 1000
4 changes: 2 additions & 2 deletions npm/vite-dev-server-fresh/cypress/e2e/react.cy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// <reference types="cypress" />
/// <reference path="../support/e2e.ts" />
import type { e2eProjectDirs } from '@packages/frontend-shared/cypress/e2e/support/e2eProjectDirs'
import type { fixtureDirs } from '@tooling/system-tests'

type ProjectDirs = typeof e2eProjectDirs
type ProjectDirs = typeof fixtureDirs

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

Expand Down
7 changes: 7 additions & 0 deletions npm/webpack-dev-server-fresh/.percy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
snapshot:
widths:
- 1280
min-height: 1024
discovery:
network-idle-timeout: 1000
1 change: 0 additions & 1 deletion packages/data-context/src/DataContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,6 @@ export class DataContext {
await this.initializeOpenMode()
if (this.coreData.currentProject && this.coreData.currentTestingType && await this.lifecycleManager.waitForInitializeSuccess()) {
this.lifecycleManager.setAndLoadCurrentTestingType(this.coreData.currentTestingType)
this.lifecycleManager.scaffoldFilesIfNecessary()
}
} else {
throw new Error(`Missing DataContext config "mode" setting, expected run | open`)
Expand Down
20 changes: 0 additions & 20 deletions packages/data-context/src/actions/MigrationActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,26 +334,6 @@ export class MigrationActions {
}
}

async assertSuccessfulConfigScaffold (configFile: `cypress.config.${'js'|'ts'}`) {
assert(this.ctx.currentProject)

// we assert the generated configuration file against one from a project that has
// been verified to run correctly.
// each project has an `unconfigured` and `configured` variant in `system-tests/projects`
// for example vueclivue2-configured and vueclivue2-unconfigured.
// after setting the project up with the launchpad, the two projects should contain the same files.

const configuredProject = this.ctx.project.projectTitle(this.ctx.currentProject).replace('unconfigured', 'configured')
const expectedProjectConfig = path.join(__dirname, '..', '..', '..', '..', 'system-tests', 'projects', configuredProject, configFile)

const actual = formatConfig(await this.ctx.file.readFileInProject(configFile))
const expected = formatConfig(await this.ctx.fs.readFile(expectedProjectConfig, 'utf8'))

if (actual !== expected) {
throw Error(`Expected ${actual} to equal ${expected}`)
}
}

resetFlags () {
this.ctx.update((coreData) => {
const defaultFlags = makeCoreData().migration.flags
Expand Down
190 changes: 68 additions & 122 deletions packages/data-context/src/actions/WizardActions.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import type { CodeLanguageEnum, NexusGenEnums, NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen'
import { CodeLanguage, CODE_LANGUAGES } from '@packages/types'
import { Bundler, FrontendFramework, FRONTEND_FRAMEWORKS, detect } from '@packages/scaffold-config'
import { CODE_LANGUAGES } from '@packages/types'
import { detect, WIZARD_FRAMEWORKS, WIZARD_BUNDLERS, commandsFileBody, supportFileComponent, supportFileE2E } from '@packages/scaffold-config'
import assert from 'assert'
import dedent from 'dedent'
import path from 'path'
import fs from 'fs-extra'
import Debug from 'debug'

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

import type { DataContext } from '..'

interface WizardGetCodeComponent {
chosenLanguage: CodeLanguage
chosenFramework: FrontendFramework
chosenLanguage: 'js' | 'ts'
chosenFramework: typeof WIZARD_FRAMEWORKS[number]
}

export class WizardActions {
Expand All @@ -29,13 +28,15 @@ export class WizardActions {
return this.ctx.wizardData
}

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

this.ctx.coreData.wizard.chosenFramework = framework
this.ctx.update((coreData) => {
coreData.wizard.chosenFramework = framework
})

if (next?.supportedBundlers?.length === 1) {
this.setBundler(next?.supportedBundlers?.[0].type)
this.setBundler(next?.supportedBundlers?.[0])

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

const prevFramework = this.ctx.coreData.wizard.chosenFramework || ''
const prevFramework = this.ctx.coreData.wizard.chosenFramework?.type ?? null

if (doesNotSupportChosenBundler || !['react', 'vue'].includes(prevFramework)) {
if (!prevFramework || doesNotSupportChosenBundler || !['react', 'vue'].includes(prevFramework)) {
this.setBundler(null)
}
}

setBundler (bundler: Bundler | null) {
this.ctx.coreData.wizard.chosenBundler = bundler
setBundler (bundler: typeof WIZARD_BUNDLERS[number] | null) {
this.ctx.update((coreData) => {
coreData.wizard.chosenBundler = bundler
})

return this.data
return this.ctx.coreData.wizard
}

setCodeLanguage (lang: NexusGenEnums['CodeLanguageEnum']) {
this.ctx.coreData.wizard.chosenLanguage = lang
this.ctx.update((coreData) => {
coreData.wizard.chosenLanguage = lang
})

return this.data
return this.ctx.coreData.wizard
}

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

/// reset wizard status, useful for when changing to a new project
resetWizard () {
this.data.chosenBundler = null
this.data.chosenFramework = null
this.data.chosenLanguage = 'js'
this.ctx.update((coreData) => {
coreData.wizard.chosenBundler = null
coreData.wizard.chosenFramework = null
coreData.wizard.chosenLanguage = 'js'
coreData.wizard.detectedBundler = null
coreData.wizard.detectedFramework = null
})

return this.data
return this.ctx.coreData.wizard
}

async initialize () {
if (!this.ctx.currentProject) {
return
}

this.ctx.update((coreData) => {
coreData.wizard.detectedFramework = null
coreData.wizard.detectedBundler = null
coreData.wizard.detectedLanguage = null
})
this.resetWizard()

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

try {
const detected = detect(await fs.readJson(path.join(this.ctx.currentProject, 'package.json')))
const detected = detect(this.ctx.currentProject)

debug('detected %o', detected)
debug('detected %o', detected)

if (detected) {
this.ctx.update((coreData) => {
coreData.wizard.detectedFramework = detected.framework?.type ?? null
coreData.wizard.chosenFramework = detected.framework?.type ?? null
if (detected) {
this.ctx.update((coreData) => {
coreData.wizard.detectedFramework = detected.framework ?? null
coreData.wizard.chosenFramework = detected.framework ?? null

if (!detected.framework?.supportedBundlers[0]) {
return
}
if (!detected.framework?.supportedBundlers[0]) {
return
}

coreData.wizard.detectedBundler = detected.bundler || detected.framework.supportedBundlers[0].type
coreData.wizard.chosenBundler = detected.bundler || detected.framework.supportedBundlers[0].type
})
}
} catch {
// Could not detect anything - no problem, no need to do anything.
coreData.wizard.detectedBundler = detected.bundler || detected.framework.supportedBundlers[0]
coreData.wizard.chosenBundler = detected.bundler || detected.framework.supportedBundlers[0]
})
}
}

Expand Down Expand Up @@ -160,7 +161,7 @@ export class WizardActions {
return
}
case 'component': {
const { chosenBundler, chosenFramework } = this.ctx.wizard
const { chosenBundler, chosenFramework } = this.ctx.coreData.wizard

if (!chosenBundler || !chosenFramework) {
return
Expand Down Expand Up @@ -190,15 +191,15 @@ export class WizardActions {

private async scaffoldComponent () {
debug('scaffoldComponent')
const { chosenBundler, chosenFramework, chosenLanguage } = this.ctx.wizard
const { chosenBundler, chosenFramework, chosenLanguage } = this.ctx.coreData.wizard

assert(chosenFramework && chosenLanguage && chosenBundler)

return await Promise.all([
this.scaffoldConfig('component'),
this.scaffoldFixtures(),
this.scaffoldSupport('component', chosenLanguage.type),
this.scaffoldSupport('commands', chosenLanguage.type),
this.scaffoldSupport('component', chosenLanguage),
this.scaffoldSupport('commands', chosenLanguage),
this.getComponentIndexHtml({
chosenFramework,
chosenLanguage,
Expand All @@ -213,7 +214,18 @@ export class WizardActions {
// @ts-ignore
await this.ctx.fs.mkdir(supportDir, { recursive: true })

const fileContent = fileName === 'commands' ? this.commandsFileBody(language) : this.supportFileBody(fileName, language)
let fileContent: string | undefined

if (fileName === 'commands') {
fileContent = commandsFileBody(language)
} else if (fileName === 'e2e') {
fileContent = supportFileE2E(language)
} else if (fileName === 'component') {
assert(this.ctx.coreData.wizard.chosenFramework)
fileContent = supportFileComponent(language, this.ctx.coreData.wizard.chosenFramework)
}

assert(fileContent)

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

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

const { chosenBundler, chosenFramework } = this.ctx.wizard
const { chosenBundler, chosenFramework } = this.ctx.coreData.wizard

assert(chosenFramework && chosenLanguage && chosenBundler)
assert(chosenFramework && chosenLanguage && chosenBundler && this.ctx.currentProject)

return chosenFramework.config[chosenLanguage.type](chosenBundler.type)
return chosenFramework.createCypressConfig({
language: chosenLanguage.type,
bundler: chosenBundler.type,
framework: chosenFramework.configFramework,
projectRoot: this.ctx.currentProject,
})
}

return this.wizardGetConfigCodeE2E(language)
Expand Down Expand Up @@ -390,79 +407,8 @@ export class WizardActions {
private ensureDir (type: 'component' | 'e2e' | 'fixtures') {
return this.ctx.fs.ensureDir(path.join(this.projectRoot, 'cypress', type))
}

private supportFileBody (fileName: 'e2e' | 'component', language: CodeLanguageEnum) {
return dedent`
// ***********************************************************
// This example support/${fileName}.${language} is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')
`
}

private commandsFileBody (language: CodeLanguageEnum) {
return dedent`
${language === 'ts' ? '/// <reference types="cypress" />' : ''}
// ***********************************************
// This example commands.${language} shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
${language === 'ts' ? COMMAND_TYPES : ''}
`
}
}

const COMMAND_TYPES = dedent`
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
`

const E2E_SCAFFOLD_BODY = dedent`
e2e: {
setupNodeEvents(on, config) {
Expand Down
Loading

2 comments on commit f8621da

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on f8621da Apr 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.0.0/linux-x64/10.0-release-f8621da49d33f16a6ef6b79559e975bef227710b/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on f8621da Apr 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.0.0/darwin-x64/10.0-release-f8621da49d33f16a6ef6b79559e975bef227710b/cypress.tgz

Please sign in to comment.