Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enable create from Vue component for projects with custom spec patterns #23298

Merged
merged 15 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
112 changes: 112 additions & 0 deletions packages/app/cypress/e2e/create-from-component.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'
import { getPathForPlatform } from '../../src/paths'

function validateCreateFromComponentCard (beforeEachFn: () => void, expectedSpecPath: string) {
beforeEach(beforeEachFn)

it('Shows create from component card for Vue projects with default spec patterns', () => {
cy.get('@ComponentCard')
.within(() => {
cy.findByRole('button', {
name: 'Create from component',
}).should('be.visible')
.and('not.be.disabled')
})
})

it('Can be closed with the x button', () => {
cy.get('@ComponentCard').click()

cy.findByRole('button', { name: 'Close' }).as('DialogCloseButton')

cy.get('@DialogCloseButton').click()
cy.findByRole('dialog', {
name: 'Choose a component',
}).should('not.exist')
})

it('Lists Vue components in the project', () => {
cy.get('@ComponentCard').click()

cy.findByText('2 Matches').should('be.visible')

cy.findByText('App').should('be.visible')
cy.findByText('HelloWorld').should('be.visible')
})

it('Allows for the user to search through their components', () => {
cy.get('@ComponentCard').click()

cy.findByText('*.vue').should('be.visible')
cy.findByText('2 Matches').should('be.visible')
cy.findByLabelText('file-name-input').type('HelloWorld')

cy.findByText('HelloWorld').should('be.visible')
cy.findByText('1 of 2 Matches').should('be.visible')
cy.findByText('App').should('not.exist')
})

it('shows success modal when component spec is created', () => {
cy.get('@ComponentCard').click()

cy.findByText('HelloWorld').should('be.visible').click()

cy.findByRole('dialog', {
name: defaultMessages.createSpec.successPage.header,
}).as('SuccessDialog').within(() => {
cy.contains(getPathForPlatform(expectedSpecPath)).should('be.visible')
cy.findByRole('button', { name: 'Close' }).should('be.visible')

cy.findByRole('link', { name: 'Okay, run the spec' })
.should('have.attr', 'href', `#/specs/runner?file=${expectedSpecPath}`)

cy.findByRole('button', { name: 'Create another spec' }).click()
})

// 'Create from component' card appears again when the user selects "create another spec"
cy.findByText('Create from component').should('be.visible')
})

it('runs generated spec', () => {
cy.get('@ComponentCard').click()

cy.findByText('HelloWorld').should('be.visible').click()

cy.findByRole('dialog', {
name: defaultMessages.createSpec.successPage.header,
}).as('SuccessDialog').within(() => {
cy.contains(getPathForPlatform(expectedSpecPath)).should('be.visible')
cy.findByRole('button', { name: 'Close' }).should('be.visible')

cy.findByRole('link', { name: 'Okay, run the spec' })
.should('have.attr', 'href', `#/specs/runner?file=${expectedSpecPath}`).click()
})

cy.findByText('<HelloWorld ... />').should('be.visible')
})
}

describe('Create from component card', () => {
context('project with default spec pattern', () => {
validateCreateFromComponentCard(() => {
cy.scaffoldProject('no-specs-vue-2')
cy.openProject('no-specs-vue-2')
cy.startAppServer('component')
cy.visitApp()

cy.findAllByTestId('card').eq(0).as('ComponentCard')
}, 'src/components/HelloWorld.cy.js')
})

context('project with custom spec pattern', () => {
astone123 marked this conversation as resolved.
Show resolved Hide resolved
validateCreateFromComponentCard(() => {
cy.scaffoldProject('no-specs-vue-2')
cy.openProject('no-specs-vue-2', ['--config-file', 'cypress-custom-spec-pattern.config.js'])
cy.startAppServer('component')
cy.visitApp()

cy.findByText('New Spec').click()
cy.findAllByTestId('card').eq(0).as('ComponentCard')
}, 'src/specs-folder/HelloWorld.cy.js')
})
})
92 changes: 0 additions & 92 deletions packages/app/cypress/e2e/specs.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,98 +639,6 @@ describe('App: Specs', () => {
})
})

context('Create from component card', () => {
beforeEach(() => {
cy.scaffoldProject('no-specs-vue-2')
cy.openProject('no-specs-vue-2')
cy.startAppServer('component')
cy.visitApp()

cy.findAllByTestId('card').eq(0).as('ComponentCard')
})

it('Shows create from component card for Vue projects with default spec patterns', () => {
cy.get('@ComponentCard')
.within(() => {
cy.findByRole('button', {
name: 'Create from component',
}).should('be.visible')
.and('not.be.disabled')
})
})

it('Can be closed with the x button', () => {
cy.get('@ComponentCard').click()

cy.findByRole('button', { name: 'Close' }).as('DialogCloseButton')

cy.get('@DialogCloseButton').click()
cy.findByRole('dialog', {
name: 'Choose a component',
}).should('not.exist')
})

it('Lists Vue components in the project', () => {
cy.get('@ComponentCard').click()

cy.findByText('2 Matches').should('be.visible')

cy.findByText('App').should('be.visible')
cy.findByText('HelloWorld').should('be.visible')
})

it('Allows for the user to search through their components', () => {
cy.get('@ComponentCard').click()

cy.findByText('*.vue').should('be.visible')
cy.findByText('2 Matches').should('be.visible')
cy.findByLabelText('file-name-input').type('HelloWorld')

cy.findByText('HelloWorld').should('be.visible')
cy.findByText('1 of 2 Matches').should('be.visible')
cy.findByText('App').should('not.exist')
})

it('shows success modal when component spec is created', () => {
cy.get('@ComponentCard').click()

cy.findByText('HelloWorld').should('be.visible').click()

cy.findByRole('dialog', {
name: defaultMessages.createSpec.successPage.header,
}).as('SuccessDialog').within(() => {
cy.contains(getPathForPlatform('src/components/HelloWorld.cy.js')).should('be.visible')
cy.findByRole('button', { name: 'Close' }).should('be.visible')

cy.findByRole('link', { name: 'Okay, run the spec' })
.should('have.attr', 'href', `#/specs/runner?file=src/components/HelloWorld.cy.js`)

cy.findByRole('button', { name: 'Create another spec' }).click()
})

// 'Create from component' card appears again when the user selects "create another spec"
cy.findByText('Create from component').should('be.visible')
})

it('runs generated spec', () => {
cy.get('@ComponentCard').click()

cy.findByText('HelloWorld').should('be.visible').click()

cy.findByRole('dialog', {
name: defaultMessages.createSpec.successPage.header,
}).as('SuccessDialog').within(() => {
cy.contains(getPathForPlatform('src/components/HelloWorld.cy.js')).should('be.visible')
cy.findByRole('button', { name: 'Close' }).should('be.visible')

cy.findByRole('link', { name: 'Okay, run the spec' })
.should('have.attr', 'href', `#/specs/runner?file=src/components/HelloWorld.cy.js`).click()
})

cy.findByText('<HelloWorld ... />').should('be.visible')
})
})

context('project with custom spec pattern', () => {
beforeEach(() => {
cy.scaffoldProject('no-specs-custom-pattern')
Expand Down
4 changes: 0 additions & 4 deletions packages/app/src/specs/CreateSpecModal.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ describe('<CreateSpecModal />', () => {
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
},
}],
isDefaultSpecPattern: true,
specs: [],
fileExtensionToUse: 'js',
defaultSpecFileName: 'cypress/e2e/ComponentName.cy.js',
Expand Down Expand Up @@ -130,7 +129,6 @@ describe('Modal Text Input', () => {
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
},
}],
isDefaultSpecPattern: true,
specs: [],
fileExtensionToUse: 'js',
defaultSpecFileName: 'cypress/e2e/ComponentName.cy.js',
Expand Down Expand Up @@ -179,7 +177,6 @@ describe('Modal Text Input', () => {
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
},
}],
isDefaultSpecPattern: true,
specs: [],
fileExtensionToUse: 'js',
defaultSpecFileName: 'this/path/does/not/produce/regex/match-',
Expand Down Expand Up @@ -232,7 +229,6 @@ describe('playground', () => {
specPattern: '**/*.cy.{js,jsx,ts,tsx}',
},
}],
isDefaultSpecPattern: true,
specs: [],
fileExtensionToUse: 'js',
defaultSpecFileName: 'cypress/e2e/ComponentName.cy.js',
Expand Down
3 changes: 1 addition & 2 deletions packages/app/src/specs/CreateSpecModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ fragment CreateSpecModal on Query {
id
fileExtensionToUse
defaultSpecFileName
isDefaultSpecPattern
...ComponentGeneratorStepOne_codeGenGlob
...EmptyGenerator
}
Expand Down Expand Up @@ -107,7 +106,7 @@ const specFileName = computed(() => {
return getPathForPlatform(props.gql.currentProject?.defaultSpecFileName || '')
})

const filteredGenerators = getFilteredGeneratorList(props.gql.currentProject, props.gql.currentProject?.isDefaultSpecPattern)
const filteredGenerators = getFilteredGeneratorList(props.gql.currentProject)

const singleGenerator = computed(() => filteredGenerators.value.length === 1 ? filteredGenerators.value[0] : null)

Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/specs/DefaultSpecPatternNoContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const props = defineProps<{
gql: CreateSpecContentFragment
}>()

const filteredGenerators = getFilteredGeneratorList(props.gql.currentProject, true)
const filteredGenerators = getFilteredGeneratorList(props.gql.currentProject)

const emit = defineEmits<{
(e: 'showCreateSpecModal', id: string): void
Expand Down
7 changes: 3 additions & 4 deletions packages/app/src/specs/generators/EmptyGenerator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ const props = defineProps<{
gql: EmptyGeneratorFragment
type: 'e2e' | 'component' | 'componentEmpty'
specFileName: string
erroredCodegenCandidate?: string
/** is there any other generator available when clicking "Back" */
otherGenerators: boolean
}>()
Expand All @@ -168,8 +167,8 @@ mutation EmptyGenerator_MatchSpecFile($specFile: String!) {
`

gql`
mutation EmptyGenerator_generateSpec($codeGenCandidate: String!, $type: CodeGenType!, $erroredCodegenCandidate: String) {
generateSpecFromSource(codeGenCandidate: $codeGenCandidate, type: $type, erroredCodegenCandidate: $erroredCodegenCandidate) {
mutation EmptyGenerator_generateSpec($codeGenCandidate: String!, $type: CodeGenType!) {
generateSpecFromSource(codeGenCandidate: $codeGenCandidate, type: $type) {
...GeneratorSuccess
}
}`
Expand Down Expand Up @@ -230,7 +229,7 @@ const createSpec = async () => {
return
}

const { data } = await writeFile.executeMutation({ codeGenCandidate: specFile.value, type: props.type, erroredCodegenCandidate: props.erroredCodegenCandidate ?? null })
const { data } = await writeFile.executeMutation({ codeGenCandidate: specFile.value, type: props.type })

result.value = data?.generateSpecFromSource?.generatedSpecResult?.__typename === 'ScaffoldedFile' ? data?.generateSpecFromSource?.generatedSpecResult : null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import ComponentGeneratorCard from './ComponentGeneratorCard.vue'
export const ComponentGenerator: SpecGenerator = {
card: ComponentGeneratorCard,
entry: ComponentGeneratorStepOne,
show: (currentProject, isDefaultSpecPattern) => {
if (!isDefaultSpecPattern) {
return false
}

show: (currentProject) => {
return currentProject?.codeGenGlobs?.component === '*.vue'
},
matches: filters.matchesCT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
type="component"
:other-generators="false"
:spec-file-name="generatedSpecError.fileName"
:errored-codegen-candidate="generatedSpecError.erroredCodegenCandidate"
@restart="cancelSpecNameCreation"
@updateTitle="(value) => emits('update:title', value)"
/>
Expand Down Expand Up @@ -143,7 +142,6 @@ mutation ComponentGeneratorStepOne_generateSpec($codeGenCandidate: String!, $typ
generatedSpecResult {
... on GeneratedSpecError {
fileName
erroredCodegenCandidate
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/specs/generators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export const generatorList: SpecGenerator[] = [
EmptyGenerator,
]

export const getFilteredGeneratorList = (currentProject, isDefaultSpecPattern) => {
return computed(() => generatorList.filter((g) => g.matches(currentProject.currentTestingType) && (g.show === undefined ? true : g.show(currentProject, isDefaultSpecPattern))))
export const getFilteredGeneratorList = (currentProject) => {
return computed(() => generatorList.filter((g) => g.matches(currentProject.currentTestingType) && (g.show === undefined ? true : g.show(currentProject))))
}

export const generators = keyBy(generatorList, 'id') as Record<GeneratorId, SpecGenerator>
2 changes: 1 addition & 1 deletion packages/app/src/specs/generators/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export interface SpecGenerator {
card: Component
entry: Component
matches: (testingType?: TestingType | null) => boolean
show: (currentProject?: CurrentProject, isDefaultSpecPattern?: boolean) => boolean
show: (currentProject?: CurrentProject) => boolean
id: GeneratorId
}
16 changes: 9 additions & 7 deletions packages/data-context/src/actions/ProjectActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,15 +336,13 @@ export class ProjectActions {
this.api.insertProjectPreferencesToCache(this.ctx.lifecycleManager.projectTitle, args)
}

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

if (!project) {
throw Error(`Cannot create spec without currentProject.`)
}
assert(project, 'Cannot create spec without currentProject.')

const getCodeGenPath = () => {
return codeGenType === 'e2e' || erroredCodegenCandidate
return codeGenType === 'e2e'
? this.ctx.path.join(
project,
codeGenCandidate,
Expand All @@ -354,18 +352,22 @@ export class ProjectActions {

const codeGenPath = getCodeGenPath()

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

const newSpecCodeGenOptions = new SpecOptions({
codeGenPath,
codeGenType,
erroredCodegenCandidate,
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: path.parse(codeGenPath).dir },
{ templateDir: templates[codeGenOptions.templateKey], target: codeGenOptions.overrideCodeGenDir || path.parse(codeGenPath).dir },
codeGenOptions,
)

Expand Down
Loading