Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6c24bfa
feat: WIP server logic for create from React component
astone123 Nov 29, 2022
2948dd7
feat: add more tests; error handling
astone123 Nov 29, 2022
73cb71f
feat: PR feedback [run CI]
astone123 Dec 1, 2022
0dbd568
Resolve conflicts
astone123 Dec 1, 2022
0f4e836
feat: try committing snapshot cache changes [run ci]
astone123 Dec 1, 2022
d763e1f
feat: try re-generating snapshot [run ci]
astone123 Dec 1, 2022
a2626df
fix build
ryanthemanuel Dec 1, 2022
6eabeb3
regenerate cache on darwin
ryanthemanuel Dec 1, 2022
6ba1695
update caches
ryanthemanuel Dec 1, 2022
9389037
Revert "feat: try re-generating snapshot [run ci]"
astone123 Dec 1, 2022
d4e4c7d
Merge branch 'feature/create-from-react-component' into astone123/cre…
lmiller1990 Dec 2, 2022
a48491d
fix typing error
lmiller1990 Dec 2, 2022
00e7819
types
lmiller1990 Dec 2, 2022
df027ff
fix test
lmiller1990 Dec 2, 2022
b32560f
chore: try using [email protected]
lmiller1990 Dec 2, 2022
89b823a
update test
lmiller1990 Dec 2, 2022
2f3ffcb
regen linux snapshot
lmiller1990 Dec 2, 2022
a631284
update snapshots for darwin
lmiller1990 Dec 2, 2022
dbb5b3e
re-gen linux snapshot
lmiller1990 Dec 2, 2022
4ad474c
Merge branch 'astone123/create-from-react-server' of https://github.c…
lmiller1990 Dec 2, 2022
c0382fa
yarn install
lmiller1990 Dec 2, 2022
7456bb7
update snapshots
lmiller1990 Dec 2, 2022
fadb8d9
update snapshot metadata
lmiller1990 Dec 2, 2022
6d502b1
update snapshots due to babel deps changing slightly
lmiller1990 Dec 2, 2022
f60ac0a
make react docgen a dep
lmiller1990 Dec 2, 2022
bd398ed
update tests
lmiller1990 Dec 2, 2022
9510a85
revert
lmiller1990 Dec 2, 2022
77a4942
snapshots again??
lmiller1990 Dec 2, 2022
f9e8af7
revert
lmiller1990 Dec 2, 2022
68d5c87
update
lmiller1990 Dec 2, 2022
281da0a
update
lmiller1990 Dec 2, 2022
e4410b1
try change snapshot
lmiller1990 Dec 2, 2022
f12efca
change snap
lmiller1990 Dec 2, 2022
e857b8f
update snap
lmiller1990 Dec 2, 2022
c070f96
feat: remove unnecessary ts-ignore
astone123 Dec 2, 2022
cd65233
feat: add more test cases
astone123 Dec 2, 2022
9449d66
feat: create CodegenActions; other minor refactors
astone123 Dec 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion npm/webpack-preprocessor/__snapshots__/compilation.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
exports['webpack preprocessor - e2e correctly preprocesses the file 1'] = `
it("is a test",(function(){expect(1).to.equal(1),expect(2).to.equal(2),expect(Math.min.apply(Math,[3,4])).to.equal(3)}));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9zcGVjX291dHB1dC5qcyIsIm1hcHBpbmdzIjoiQUFBQUEsR0FBRyxhQUFhLFdBR2RDLE9BRmdCLEdBRU5DLEdBQUdDLE1BQU0sR0FDbkJGLE9BSG1CLEdBR1RDLEdBQUdDLE1BQU0sR0FDbkJGLE9BQU9HLEtBQUtDLElBQUwsTUFBQUQsS0FBWSxDQUFDLEVBQUcsS0FBS0YsR0FBR0MsTUFBTSIsInNvdXJjZXMiOlsid2VicGFjazovL0BjeXByZXNzL3dlYnBhY2stcHJlcHJvY2Vzc29yLy4vdGVzdC9fdGVzdC1vdXRwdXQvZXhhbXBsZV9zcGVjLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIml0KCdpcyBhIHRlc3QnLCAoKSA9PiB7XG4gIGNvbnN0IFthLCBiXSA9IFsxLCAyXVxuXG4gIGV4cGVjdChhKS50by5lcXVhbCgxKVxuICBleHBlY3QoYikudG8uZXF1YWwoMilcbiAgZXhwZWN0KE1hdGgubWluKC4uLlszLCA0XSkpLnRvLmVxdWFsKDMpXG59KVxuIl0sIm5hbWVzIjpbIml0IiwiZXhwZWN0IiwidG8iLCJlcXVhbCIsIk1hdGgiLCJtaW4iXSwic291cmNlUm9vdCI6IiJ9
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9zcGVjX291dHB1dC5qcyIsIm1hcHBpbmdzIjoiQUFBQUEsR0FBRyxhQUFhLFdBR2RDLE9BRmdCLEdBRU5DLEdBQUdDLE1BQU0sR0FDbkJGLE9BSG1CLEdBR1RDLEdBQUdDLE1BQU0sR0FDbkJGLE9BQU9HLEtBQUtDLElBQUcsTUFBUkQsS0FBWSxDQUFDLEVBQUcsS0FBS0YsR0FBR0MsTUFBTSIsInNvdXJjZXMiOlsid2VicGFjazovL0BjeXByZXNzL3dlYnBhY2stcHJlcHJvY2Vzc29yLy4vdGVzdC9fdGVzdC1vdXRwdXQvZXhhbXBsZV9zcGVjLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIml0KCdpcyBhIHRlc3QnLCAoKSA9PiB7XG4gIGNvbnN0IFthLCBiXSA9IFsxLCAyXVxuXG4gIGV4cGVjdChhKS50by5lcXVhbCgxKVxuICBleHBlY3QoYikudG8uZXF1YWwoMilcbiAgZXhwZWN0KE1hdGgubWluKC4uLlszLCA0XSkpLnRvLmVxdWFsKDMpXG59KVxuIl0sIm5hbWVzIjpbIml0IiwiZXhwZWN0IiwidG8iLCJlcXVhbCIsIk1hdGgiLCJtaW4iXSwic291cmNlUm9vdCI6IiJ9
`

exports['webpack preprocessor - e2e has less verbose syntax error 1'] = `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ describe('./lib/cross-origin-callback-loader', () => {
expectAddFileSource(store).to.equal(stripIndent`
__cypressCrossOriginCallback = () => {
const utils = require('../support/utils');

utils.foo();
}`)
})
Expand All @@ -230,9 +229,7 @@ describe('./lib/cross-origin-callback-loader', () => {
`it('test', () => {
cy.origin('http://www.foobar.com:3500', () => {
require('../support/commands')

const utils = require('../support/utils')

const _ = require('lodash')
})
})`,
Expand All @@ -241,9 +238,7 @@ describe('./lib/cross-origin-callback-loader', () => {
expectAddFileSource(store).to.equal(stripIndent`
__cypressCrossOriginCallback = () => {
require('../support/commands');

const utils = require('../support/utils');

const _ = require('lodash');
}`)
})
Expand All @@ -270,9 +265,7 @@ describe('./lib/cross-origin-callback-loader', () => {
`it('test', () => {
cy.origin('http://www.foobar.com:3500', () => {
const someVar = 'someValue'

const result = require('./fn')(someVar)

expect(result).to.equal('mutated someVar')
})
})`,
Expand All @@ -281,9 +274,7 @@ describe('./lib/cross-origin-callback-loader', () => {
expectAddFileSource(store).to.equal(stripIndent`
__cypressCrossOriginCallback = () => {
const someVar = 'someValue';

const result = require('./fn')(someVar);

expect(result).to.equal('mutated someVar');
}`)
})
Expand All @@ -293,7 +284,6 @@ describe('./lib/cross-origin-callback-loader', () => {
`it('test', () => {
cy.origin('http://www.foobar.com:3500', { args: { foo: 'foo'}}, ({ foo }) => {
const result = require('./fn')(foo)

expect(result).to.equal('mutated someVar')
})
})`,
Expand All @@ -304,7 +294,6 @@ describe('./lib/cross-origin-callback-loader', () => {
foo
}) => {
const result = require('./fn')(foo);

expect(result).to.equal('mutated someVar');
}`)
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const { defineConfig: cypressDefineConfig } = require("cypress");

export default cypressDefineConfig({
component: {
devServer: {
Expand Down
1 change: 1 addition & 0 deletions packages/data-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"prettier": "2.5.1",
"randexp": "0.5.3",
"randomstring": "1.1.5",
"react-docgen": "6.0.0-alpha.3",
"semver": "7.3.2",
"simple-git": "3.4.0",
"stringify-object": "^3.0.0",
Expand Down
6 changes: 6 additions & 0 deletions packages/data-context/src/DataActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
DevActions,
AuthActions,
CohortsActions,
CodegenActions,
} from './actions'
import { ErrorActions } from './actions/ErrorActions'
import { EventCollectorActions } from './actions/EventCollectorActions'
Expand Down Expand Up @@ -89,4 +90,9 @@ export class DataActions {
get cohorts () {
return new CohortsActions(this.ctx)
}

@cached
get codegen () {
return new CodegenActions(this.ctx)
}
}
141 changes: 141 additions & 0 deletions packages/data-context/src/actions/CodegenActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import type { NexusGenObjects, NexusGenUnions } from '@packages/graphql/src/gen/nxs.gen'
import assert from 'assert'
import path from 'path'
import type { DataContext } from '..'
import { SpecOptions, codeGenerator } from '../codegen'
import templates from '../codegen/templates'
import type { CodeGenType } from '../gen/graphcache-config.gen'
import { WizardFrontendFramework, WIZARD_FRAMEWORKS } from '@packages/scaffold-config'
import { parse as parseReactComponent, resolver as reactDocgenResolvers } from 'react-docgen'

interface ReactComponentDescriptor {
displayName: string
}

export class CodegenActions {
constructor (private ctx: DataContext) {}

async getReactComponentsFromFile (filePath: string): Promise<ReactComponentDescriptor[]> {
try {
const src = await this.ctx.fs.readFile(filePath, 'utf8')

const result = parseReactComponent(src, reactDocgenResolvers.findAllExportedComponentDefinitions)
// types appear to be incorrect in [email protected]
// TODO: update when 6.0.0 stable is out for fixed types.
const defs = (Array.isArray(result) ? result : [result]) as ReactComponentDescriptor[]

return defs
} catch (err) {
this.ctx.debug(err)

return []
}
}

async codeGenSpec (codeGenCandidate: string, codeGenType: CodeGenType, componentName?: string): Promise<NexusGenUnions['GeneratedSpecResult']> {
const project = this.ctx.currentProject

assert(project, 'Cannot create spec without currentProject.')

const getCodeGenPath = () => {
return codeGenType === 'e2e'
? this.ctx.path.join(
project,
codeGenCandidate,
)
: codeGenCandidate
}

const codeGenPath = getCodeGenPath()

const { specPattern = [] } = await this.ctx.project.specPatterns()

const newSpecCodeGenOptions = new SpecOptions({
codeGenPath,
codeGenType,
framework: this.getWizardFrameworkFromConfig(),
isDefaultSpecPattern: await this.ctx.project.getIsDefaultSpecPattern(),
specPattern,
currentProject: this.ctx.currentProject,
specs: this.ctx.project.specs,
componentName,
})

let codeGenOptions = await newSpecCodeGenOptions.getCodeGenOptions()

const codeGenResults = await codeGenerator(
{ templateDir: templates[codeGenOptions.templateKey], target: codeGenOptions.overrideCodeGenDir || path.parse(codeGenPath).dir },
codeGenOptions,
)

if (!codeGenResults.files[0] || codeGenResults.failed[0]) {
throw (codeGenResults.failed[0] || 'Unable to generate spec')
}

const [newSpec] = codeGenResults.files

const cfg = await this.ctx.project.getConfig()

if (cfg && this.ctx.currentProject) {
const testingType = (codeGenType === 'component') ? 'component' : 'e2e'

await this.ctx.actions.project.setSpecsFoundBySpecPattern({
projectRoot: this.ctx.currentProject,
testingType,
specPattern: cfg.specPattern ?? [],
configSpecPattern: cfg.specPattern ?? [],
excludeSpecPattern: cfg.excludeSpecPattern,
additionalIgnorePattern: cfg.additionalIgnorePattern,
})
}

return {
status: 'valid',
file: { absolute: newSpec.file, contents: newSpec.content },
description: 'Generated spec',
}
}

get defaultE2EPath () {
const projectRoot = this.ctx.currentProject

assert(projectRoot, `Cannot create e2e directory without currentProject.`)

return path.join(projectRoot, 'cypress', 'e2e')
}

async scaffoldIntegration (): Promise<NexusGenObjects['ScaffoldedFile'][]> {
const projectRoot = this.ctx.currentProject

assert(projectRoot, `Cannot create spec without currentProject.`)

const results = await codeGenerator(
{ templateDir: templates['scaffoldIntegration'], target: this.defaultE2EPath },
{},
)

if (results.failed.length) {
throw new Error(`Failed generating files: ${results.failed.map((e) => `${e}`)}`)
}

return results.files.map(({ status, file, content }) => {
return {
status: (status === 'add' || status === 'overwrite') ? 'valid' : 'skipped',
file: { absolute: file, contents: content },
description: 'Generated spec',
}
})
}

getWizardFrameworkFromConfig (): WizardFrontendFramework | undefined {
const config = this.ctx.lifecycleManager.loadedConfigFile

// If devServer is a function, they are using a custom dev server.
if (!config?.component?.devServer || typeof config?.component?.devServer === 'function') {
return undefined
}

// @ts-ignore - because of the conditional above, we know that devServer isn't a function
return WIZARD_FRAMEWORKS.find((framework) => framework.configFramework === config?.component?.devServer.framework)
}
}
112 changes: 2 additions & 110 deletions packages/data-context/src/actions/ProjectActions.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import type { CodeGenType, MutationSetProjectPreferencesInGlobalCacheArgs, NexusGenObjects, NexusGenUnions } from '@packages/graphql/src/gen/nxs.gen'
import type { MutationSetProjectPreferencesInGlobalCacheArgs, NexusGenObjects, NexusGenUnions } from '@packages/graphql/src/gen/nxs.gen'
import { InitializeProjectOptions, FoundBrowser, OpenProjectLaunchOptions, Preferences, TestingType, ReceivedCypressOptions, AddProject, FullConfig, AllowedState, SpecWithRelativeRoot, OpenProjectLaunchOpts, RUN_ALL_SPECS, RUN_ALL_SPECS_KEY } from '@packages/types'
import type { EventEmitter } from 'events'
import execa from 'execa'
import path from 'path'
import assert from 'assert'

import type { ProjectShape } from '../data/coreDataShape'

import type { DataContext } from '..'
import { codeGenerator, SpecOptions, hasNonExampleSpec } from '../codegen'
import { hasNonExampleSpec } from '../codegen'
import templates from '../codegen/templates'
import { insertValuesInConfigFile } from '../util'
import { getError } from '@packages/errors'
import { resetIssuedWarnings } from '@packages/config'
import { WizardFrontendFramework, WIZARD_FRAMEWORKS } from '@packages/scaffold-config'

export interface ProjectApiShape {
/**
Expand Down Expand Up @@ -345,69 +343,6 @@ export class ProjectActions {
this.api.insertProjectPreferencesToCache(this.ctx.lifecycleManager.projectTitle, args)
}

async codeGenSpec (codeGenCandidate: string, codeGenType: CodeGenType): Promise<NexusGenUnions['GeneratedSpecResult']> {
const project = this.ctx.currentProject

assert(project, 'Cannot create spec without currentProject.')

const getCodeGenPath = () => {
return codeGenType === 'e2e'
? this.ctx.path.join(
project,
codeGenCandidate,
)
: codeGenCandidate
}

const codeGenPath = getCodeGenPath()

const { specPattern = [] } = await this.ctx.project.specPatterns()

const newSpecCodeGenOptions = new SpecOptions({
codeGenPath,
codeGenType,
framework: this.getWizardFrameworkFromConfig(),
isDefaultSpecPattern: await this.ctx.project.getIsDefaultSpecPattern(),
specPattern,
currentProject: this.ctx.currentProject,
specs: this.ctx.project.specs,
})

let codeGenOptions = await newSpecCodeGenOptions.getCodeGenOptions()

const codeGenResults = await codeGenerator(
{ templateDir: templates[codeGenOptions.templateKey], target: codeGenOptions.overrideCodeGenDir || path.parse(codeGenPath).dir },
codeGenOptions,
)

if (!codeGenResults.files[0] || codeGenResults.failed[0]) {
throw (codeGenResults.failed[0] || 'Unable to generate spec')
}

const [newSpec] = codeGenResults.files

const cfg = await this.ctx.project.getConfig()

if (cfg && this.ctx.currentProject) {
const testingType = (codeGenType === 'component') ? 'component' : 'e2e'

await this.setSpecsFoundBySpecPattern({
projectRoot: this.ctx.currentProject,
testingType,
specPattern: cfg.specPattern ?? [],
configSpecPattern: cfg.specPattern ?? [],
excludeSpecPattern: cfg.excludeSpecPattern,
additionalIgnorePattern: cfg.additionalIgnorePattern,
})
}

return {
status: 'valid',
file: { absolute: newSpec.file, contents: newSpec.content },
description: 'Generated spec',
}
}

async setSpecsFoundBySpecPattern ({ projectRoot, testingType, specPattern, configSpecPattern, excludeSpecPattern, additionalIgnorePattern }: FindSpecs<string | string[] | undefined>) {
const toArray = (val?: string | string[]) => val ? typeof val === 'string' ? [val] : val : []

Expand Down Expand Up @@ -467,37 +402,6 @@ export class ProjectActions {
this.ctx.actions.electron.showBrowserWindow()
}

get defaultE2EPath () {
const projectRoot = this.ctx.currentProject

assert(projectRoot, `Cannot create e2e directory without currentProject.`)

return path.join(projectRoot, 'cypress', 'e2e')
}

async scaffoldIntegration (): Promise<NexusGenObjects['ScaffoldedFile'][]> {
const projectRoot = this.ctx.currentProject

assert(projectRoot, `Cannot create spec without currentProject.`)

const results = await codeGenerator(
{ templateDir: templates['scaffoldIntegration'], target: this.defaultE2EPath },
{},
)

if (results.failed.length) {
throw new Error(`Failed generating files: ${results.failed.map((e) => `${e}`)}`)
}

return results.files.map(({ status, file, content }) => {
return {
status: (status === 'add' || status === 'overwrite') ? 'valid' : 'skipped',
file: { absolute: file, contents: content },
description: 'Generated spec',
}
})
}

async hasNonExampleSpec () {
const specs = this.ctx.project.specs?.map((spec) => spec.relativeToCommonRoot)

Expand Down Expand Up @@ -545,16 +449,4 @@ export class ProjectActions {
await this.ctx.actions.wizard.scaffoldTestingType()
}
}

getWizardFrameworkFromConfig (): WizardFrontendFramework | undefined {
const config = this.ctx.lifecycleManager.loadedConfigFile

// If devServer is a function, they are using a custom dev server.
if (!config?.component?.devServer || typeof config?.component?.devServer === 'function') {
return undefined
}

// @ts-ignore - because of the conditional above, we know that devServer isn't a function
return WIZARD_FRAMEWORKS.find((framework) => framework.configFramework === config?.component?.devServer.framework)
}
}
Loading