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: create from React component UI #24982

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 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
6468430
feat: WIP create from React UI
astone123 Nov 30, 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 react-docgen@6.0.0-alpha.3
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
cb381e9
Merge branch 'astone123/create-from-react-server' of github.com:cypre…
astone123 Dec 2, 2022
cd65233
feat: add more test cases
astone123 Dec 2, 2022
205e185
Merge branch 'astone123/create-from-react-server' of github.com:cypre…
astone123 Dec 2, 2022
9449d66
feat: create CodegenActions; other minor refactors
astone123 Dec 5, 2022
2b03c33
Merge branch 'astone123/create-from-react-server' of github.com:cypre…
astone123 Dec 5, 2022
f979f48
feat: continue UI work
astone123 Dec 5, 2022
da5bfda
Merge branch 'feature/create-from-react-component' of github.com:cypr…
astone123 Dec 5, 2022
16df37a
feat: ignore config and Cypress-related files
astone123 Dec 6, 2022
19fac18
feat: PR feedback
astone123 Dec 6, 2022
ab6f8c0
Merge branch 'feature/create-from-react-component' of github.com:cypr…
astone123 Dec 7, 2022
c4749b9
update Vue component link
astone123 Dec 7, 2022
544a651
merge in default export work
astone123 Dec 7, 2022
dbea144
consolidate graphql queries
astone123 Dec 7, 2022
50a9c15
other misc feedback
astone123 Dec 7, 2022
367eaa7
use network-only policy to fetch files; include cypress/ dir for code…
astone123 Dec 7, 2022
5debd39
add basic e2e test
astone123 Dec 7, 2022
b469af7
fix app integration tests
astone123 Dec 7, 2022
18d2545
refactor and fix app component and webpack dev server tests
astone123 Dec 8, 2022
1d745e9
add error state; fix unit tests [skip ci]
astone123 Dec 8, 2022
84fb446
simplify generator show logic [skip ci]
astone123 Dec 8, 2022
27ae647
more testing
astone123 Dec 8, 2022
f10b034
fix types
astone123 Dec 8, 2022
2d30c0f
style updates [skip ci]
astone123 Dec 8, 2022
101f964
fix error state [skip ci]
astone123 Dec 9, 2022
595fe0d
fix list padding [skip ci]
astone123 Dec 9, 2022
156c800
use slots (#25079)
lmiller1990 Dec 9, 2022
d504825
add more tests; fix unit tests
astone123 Dec 9, 2022
a44ed45
fix types
astone123 Dec 9, 2022
43d73f0
fix test describe
astone123 Dec 9, 2022
165fbfe
add percy snapshots for new list
astone123 Dec 9, 2022
f1c7a07
update trouble rendering banner link [skip ci]
astone123 Dec 9, 2022
7bf5c7e
use collapsible component
astone123 Dec 9, 2022
766419d
use button for component list items
astone123 Dec 9, 2022
b55c4fa
fix tests
astone123 Dec 9, 2022
48081eb
Merge branch 'feature/create-from-react-component' of github.com:cypr…
astone123 Dec 9, 2022
49c7ed7
build binaries
astone123 Dec 9, 2022
a582866
revert changes to circle config
astone123 Dec 12, 2022
1670c94
remove eslintignore and extra loading div [skip ci] because we know i…
astone123 Dec 13, 2022
d243608
revert changes to framework glob patterns [skip ci]
astone123 Dec 13, 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: 2 additions & 0 deletions npm/webpack-dev-server/cypress/e2e/react.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ for (const project of WEBPACK_REACT) {

// 4. recreate spec, with same name as removed spec
cy.findByTestId('new-spec-button').click()
cy.findByRole('button', { name: 'Create new empty spec' }).should('be.visible').click()

cy.findByRole('dialog').within(() => {
cy.get('input').clear().type('src/App.cy.jsx')
cy.contains('button', 'Create spec').click()
Expand Down
192 changes: 168 additions & 24 deletions packages/app/cypress/e2e/create-from-component.cy.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'
import { getPathForPlatform } from '../../src/paths'

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

it('Shows create from component card for Vue projects with default spec patterns', () => {
it('Shows create from component card for Vue projects', () => {
cy.get('@ComponentCard')
.within(() => {
cy.findByRole('button', {
Expand Down Expand Up @@ -82,31 +82,175 @@ function validateCreateFromComponentCard (beforeEachFn: () => void, expectedSpec
.should('have.attr', 'href', `#/specs/runner?file=${expectedSpecPath}`).click()
})

cy.findByText('<HelloWorld ... />', { timeout: 10000 }).should('be.visible')
cy.waitForSpecToFinish({ passCount: 1 })
})
}

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

it('Shows create from component card for React projects', () => {
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 files in the project', () => {
cy.get('@ComponentCard').click()

cy.findByText('5 matches').should('be.visible')

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

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

cy.findByText('*.{js,jsx,ts,tsx}').should('be.visible')
cy.findByText('5 matches').should('be.visible')
cy.findByLabelText('file-name-input').type('App')

cy.findByText('App').should('be.visible')
cy.findByText('1 of 5 matches').should('be.visible')
cy.findByText('index').should('not.exist')
cy.findByText('component').should('not.exist')
})

it('shows \'No components found\' if there are no exported components', () => {
cy.get('@ComponentCard').click()

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

cy.findByTestId('react-component-row').should('not.exist')
cy.contains('No components found').should('be.visible')
})

it('shows \'Unable to parse file\' if there was an error parsing the file', () => {
cy.get('@ComponentCard').click()

// This component has a syntax error so we will fail to parse it
cy.findByText('Invalid').should('be.visible').click()

cy.findByTestId('react-component-row').should('not.exist')
cy.contains('Unable to parse file').should('be.visible')
})

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

// Expand the row
cy.findByText('App').should('be.visible').click()

// Click on 'app' component
cy.findByTestId('react-component-row').should('contain', 'App').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()

// Expand the row
cy.findByText('App').should('be.visible').click()

// Click on 'app' component
cy.findByTestId('react-component-row').should('contain', 'App').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')

// There appears to be a race condition here where sometimes we try to run the spec
// before the file has been written to. Waiting here for 1 second resolves the issue.
cy.wait(1000)

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

cy.waitForSpecToFinish({ passCount: 1 })
})
}

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', () => {
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')
context('Vue', () => {
context('project with default spec pattern', () => {
validateCreateFromVueComponentCard(() => {
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', () => {
validateCreateFromVueComponentCard(() => {
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')
})
})

context('React', () => {
context('project with default spec pattern', () => {
validateCreateFromReactComponentCard(() => {
cy.scaffoldProject('no-specs')
cy.openProject('no-specs')
cy.startAppServer('component')
cy.visitApp()

cy.findAllByTestId('card').eq(0).as('ComponentCard')
}, 'src/App.cy.jsx')
})

context('project with custom spec pattern', () => {
validateCreateFromReactComponentCard(() => {
cy.scaffoldProject('no-specs')
cy.openProject('no-specs', ['--config-file', 'cypress-custom-spec-pattern.config.ts'])
cy.startAppServer('component')
cy.visitApp()

cy.findByText('New spec').click()
cy.findAllByTestId('card').eq(0).as('ComponentCard')
}, 'src/specs-folder/App.cy.jsx')
})
})
})
22 changes: 18 additions & 4 deletions packages/app/cypress/e2e/specs.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,12 @@ describe('App: Specs', () => {
})
})

function selectEmptySpecCard () {
cy.findAllByTestId('card').should('have.length', 2)
cy.findByRole('button', { name: 'Create from component' }).should('be.visible')
cy.findByRole('button', { name: 'Create new empty spec' }).should('be.visible').click()
}

describe('Testing Type: Component', {
viewportHeight: 768,
viewportWidth: 1024,
Expand All @@ -535,7 +541,7 @@ describe('App: Specs', () => {
cy.startAppServer('component')
cy.visitApp()

cy.findAllByTestId('card').eq(0).as('EmptyCard')
cy.findAllByTestId('card').eq(1).as('EmptyCard')
})

it('shows create new empty spec card', () => {
Expand Down Expand Up @@ -589,7 +595,9 @@ describe('App: Specs', () => {

// 'Create a new spec' dialog presents with options when user indicates they want to create
// another spec.
cy.findByRole('dialog', { name: 'Enter the path for your new spec' }).should('be.visible')
cy.findAllByTestId('card').should('have.length', 2)
cy.findByRole('button', { name: 'Create new empty spec' }).should('be.visible')
cy.findByRole('button', { name: 'Create from component' }).should('be.visible')
})

it('navigates to spec runner when selected', () => {
Expand Down Expand Up @@ -628,7 +636,7 @@ describe('App: Specs', () => {
})

cy.contains('Review the docs')
.should('have.attr', 'href', 'https://on.cypress.io/mount')
.should('have.attr', 'href', 'https://on.cypress.io/styling-components')

cy.log('should not contain the link if you navigate away and back')
cy.get('body').type('f')
Expand Down Expand Up @@ -709,13 +717,17 @@ describe('App: Specs', () => {
it('shows new spec button to start creation workflow', () => {
cy.findByRole('button', { name: 'New spec', exact: false }).click()

selectEmptySpecCard()

cy.findByRole('dialog', { name: 'Enter the path for your new spec' }).should('be.visible')
})

it('shows create first spec page with create empty option and goes back if it is cancel', () => {
cy.findByRole('button', { name: 'New spec', exact: false }).click()

cy.contains('Cancel').click()
selectEmptySpecCard()

cy.contains('Back').click()

cy.findByRole('dialog', { name: 'Enter the path for your new spec' }).should('not.exist')
})
Expand All @@ -738,6 +750,8 @@ describe('App: Specs', () => {

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

selectEmptySpecCard()

cy.findByRole('dialog', {
name: 'Enter the path for your new spec',
}).within(() => {
Expand Down
4 changes: 4 additions & 0 deletions packages/app/src/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ export function getPathForPlatform (posixPath?: string) {

return posixPath
}

export function posixify (path: string): string {
return path.replace(/\\/g, '/')
}
4 changes: 2 additions & 2 deletions packages/app/src/runner/SpecRunnerHeaderOpenMode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@
dismissible
>
<template #title>
<ExternalLink href="https://on.cypress.io/mount">
<i-cy-book_x16 class="inline-block icon-dark-indigo-500 icon-light-indigo-200" />
<i-cy-book_x16 class="pr-2px inline-block icon-dark-indigo-500 icon-light-indigo-200" />
<ExternalLink href="https://on.cypress.io/styling-components">
{{ t('runner.header.reviewDocs') }}
</ExternalLink>
{{ t('runner.header.troubleRendering') }}
Expand Down
Loading