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: add spec pattern modal #19801

Merged
merged 16 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
15 changes: 15 additions & 0 deletions packages/app/cypress/e2e/spec_list.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ describe('App: Spec List', () => {
cy.visitApp()
})

it('opens spec pattern modal', () => {
cy.get('[data-cy="open-spec-pattern-modal"]').click()

cy.get('[data-cy="spec-pattern-modal"]').should('be.visible')
cy.get('[data-cy="spec-pattern"]').contains('cypress/component-tests/**/*')

cy.contains('button', 'Update Spec Pattern').click()
cy.get('[data-cy="choose-editor-modal"]').should('be.visible').within(() => {
cy.get('[aria-label="Close"]').click()
})

cy.contains('button', 'Dismiss').click()
cy.get('[data-cy="spec-pattern-modal"]').should('not.exist')
})

it('highlights the currently running spec', () => {
cy.contains('fails').click()

Expand Down
2 changes: 1 addition & 1 deletion packages/app/cypress/e2e/top-nav.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ describe('App Top Nav Workflows', () => {
cy.findByTestId('cypress-update-popover').findByRole('button', { name: 'Update to 10.1.0' }).click()

cy.findByRole('dialog', { name: 'Upgrade to Cypress 10.1.0' }).as('upgradeModal').within(() => {
cy.validateExternalLink({ name: 'Need help?', href: 'https://on.cypress.io' })
cy.validateExternalLink({ name: 'Need help', href: 'https://on.cypress.io' })
cy.contains('You are currently running Version 10.0.0 of Cypress').should('be.visible')
cy.contains('npm install --save-dev cypress@10.1.0').should('be.visible')
cy.findByRole('button', { name: 'Close' }).click()
Expand Down
39 changes: 39 additions & 0 deletions packages/app/src/components/SpecPatternModal.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { SpecPatternModalFragmentDoc } from '../generated/graphql-test'
import SpecPatternModal from './SpecPatternModal.vue'
import { defaultMessages } from '@cy/i18n'

describe('<SpecPatternModal />', () => {
it('should not render if closed', () => {
cy.mountFragment(SpecPatternModalFragmentDoc, {
render (gql) {
return (<SpecPatternModal gql={gql} show={false} />)
},
})

cy.get('[data-cy="spec-pattern-modal"]').should('not.exist')
})

it('should render and close', () => {
const closeSpy = cy.stub().as('closeSpy')

cy.mountFragment(SpecPatternModalFragmentDoc, {
render (gql) {
return (<SpecPatternModal gql={gql} show={true} onClose={closeSpy} />)
},
})

cy.get('[data-cy="spec-pattern-modal"]').should('be.visible')
cy.contains('h2', defaultMessages.components.specPatternModal.title)
cy.get('[data-cy="external"]').should('have.attr', 'href').and('eq', 'https://on.cypress.io')
cy.get('[data-cy="spec-pattern"]').should('be.visible')

cy.percySnapshot()

cy.get('[data-cy="open-config-file"').should('be.visible')
cy.contains('button', defaultMessages.createSpec.updateSpecPattern)

cy.contains('button', defaultMessages.components.modal.dismiss).click()

cy.get('@closeSpy').should('have.been.called')
})
})
68 changes: 68 additions & 0 deletions packages/app/src/components/SpecPatternModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<StandardModal
class="transition-all transition duration-200"
variant="bare"
:title="t('components.specPatternModal.title')"
:model-value="show"
data-cy="spec-pattern-modal"
help-link="https://on.cypress.io"
@update:model-value="emits('close')"
>
<div
class="w-full p-24px sm:min-w-640px"
>
<SpecPatterns
:gql="props.gql"
class="border-gray-100 rounded border-px"
/>
</div>
<StandardModalFooter
class="flex items-center h-72px gap-16px"
>
<OpenConfigFileInIDE>
<Button size="lg">
<template #prefix>
<i-cy-code-editor_x16 class="icon-dark-white" />
</template>
{{ t('createSpec.updateSpecPattern') }}
</Button>
</OpenConfigFileInIDE>
<Button
variant="outline"
size="lg"
@click="emits('close')"
>
{{ t('components.modal.dismiss') }}
</Button>
</StandardModalFooter>
</StandardModal>
</template>

<script lang="ts" setup>
import StandardModal from '@cy/components/StandardModal.vue'
import SpecPatterns from '../components/SpecPatterns.vue'
import { useI18n } from '@cy/i18n'
import type { SpecPatternModalFragment } from '../generated/graphql'
import { gql } from '@urql/core'
import StandardModalFooter from '@cy/components/StandardModalFooter.vue'
import Button from '../../../frontend-shared/src/components/Button.vue'
import OpenConfigFileInIDE from '../../../frontend-shared/src/gql-components/OpenConfigFileInIDE.vue'

gql`
fragment SpecPatternModal on CurrentProject {
id
...SpecPatterns
}
`

const props = defineProps<{
gql: SpecPatternModalFragment
show: boolean
}>()

const { t } = useI18n()

const emits = defineEmits<{
(eventName: 'close'): void
}>()
</script>
10 changes: 5 additions & 5 deletions packages/app/src/components/SpecPatterns.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="rounded border-gray-100 border-1px w-full">
<div class="flex p-16px justify-between items-center">
<div class="w-full border-gray-100 rounded border-1px">
<div class="flex items-center justify-between p-16px">
<FileMatchIndicator>
<i18n-t
scope="global"
Expand All @@ -11,9 +11,9 @@
</FileMatchIndicator>
<OpenConfigFileInIDE>
<button
class="flex outline-transparent text-indigo-500 gap-8px items-center group"
class="flex items-center text-indigo-500 outline-transparent gap-8px group"
>
<i-cy-document-text_x16 class="icon-light-gray-100 icon-dark-gray-500" />
<i-cy-document-text_x16 class="icon-light-gray-50 icon-dark-gray-300" />
<span class="group-hocus:underline">cypress.config.js</span>
</button>
</OpenConfigFileInIDE>
Expand All @@ -23,7 +23,7 @@
<code
v-for="pattern in specPatterns"
:key="pattern"
class="flex py-8px text-gray-600 text-size-14px leading-24px block"
class="flex block text-gray-600 py-8px text-size-14px leading-24px"
data-cy="spec-pattern"
>
{{ pattern }}
Expand Down
19 changes: 15 additions & 4 deletions packages/app/src/specs/SpecsList.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="p-24px spec-container">
<CreateSpecModal
v-if="props.gql.currentProject?.currentTestingType"
v-if="props.gql.currentProject?.currentTestingType && showModal"
:show="showModal"
:gql="props.gql"
@close="showModal = false"
Expand All @@ -11,6 +11,13 @@
class="pb-32px"
:result-count="specs.length"
@newSpec="showModal = true"
@spec-pattern="bindingsOpen = true"
/>
<SpecPatternModal
v-if="props.gql.currentProject && bindingsOpen"
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we combine the v-if and :show? It looks like they do same thing (conditionally hide/show?)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think they have different purposes here. It might be better to make the v-if depend just on props.gql.currentProject so that the SpecPatternModal component renders only once, when there is a currentProject, and keep bindingsOpen to only manage the open/closed state. With the current v-if we add/remove the component from the DOM, at the same time as we are opening and closing the modal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@marktnoonan I'll implement what you've stated above, and also rename some variables as bindingsOpen was a copy and paste and it should be named more contextually.

:show="bindingsOpen"
:gql="props.gql.currentProject"
@close="bindingsOpen = false"
/>

<template
Expand All @@ -20,13 +27,13 @@
class="grid grid-cols-2 children:font-medium children:text-gray-800"
>
<div
class="flex justify-between items-center"
class="flex items-center justify-between"
data-cy="specs-testing-type-header"
>
{{ props.gql.currentProject?.currentTestingType === 'component' ?
t('specPage.componentSpecsHeader') : t('specPage.e2eSpecsHeader') }}
</div>
<div class="flex justify-between items-center">
<div class="flex items-center justify-between">
<div>{{ t('specPage.gitStatusHeader') }}</div>
</div>
</div>
Expand Down Expand Up @@ -102,6 +109,7 @@ import RowDirectory from './RowDirectory.vue'
import SpecItem from './SpecItem.vue'
import { useVirtualList } from '@packages/frontend-shared/src/composables/useVirtualList'
import NoResults from '@cy/components/NoResults.vue'
import SpecPatternModal from '../components/SpecPatternModal.vue'

const { t } = useI18n()

Expand All @@ -126,7 +134,6 @@ fragment SpecNode_SpecsList on SpecEdge {

gql`
fragment Specs_SpecsList on Query {
...CreateSpecModal
currentProject {
id
projectRoot
Expand All @@ -136,7 +143,10 @@ fragment Specs_SpecsList on Query {
...SpecNode_SpecsList
}
}
config
...SpecPatternModal
}
...CreateSpecModal
}
`

Expand All @@ -145,6 +155,7 @@ const props = defineProps<{
}>()

const showModal = ref(false)
const bindingsOpen = ref(false)
const search = ref('')

function handleClear () {
Expand Down
15 changes: 15 additions & 0 deletions packages/app/src/specs/SpecsListHeader.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ describe('<SpecsListHeader />', { keystrokeDelay: 0 }, () => {
.should('have.been.called')
})

it('emits a spec pattern event', () => {
const onSpecPattern = cy.stub().as('spec-pattern')
const search = ref('')

cy.mount(() => (<div class="max-w-800px p-12 resize overflow-auto"><SpecsListHeader
modelValue={search.value}
onSpecPattern={onSpecPattern}
resultCount={0}
/></div>))
.get('[data-cy="open-spec-pattern-modal"]')
.click()
.get('@spec-pattern')
.should('have.been.called')
})

it('shows the result count correctly', () => {
const mountWithResultCount = (count = 0) => {
cy.mount(() => (<div class="max-w-800px p-12 resize overflow-auto"><SpecsListHeader
Expand Down
17 changes: 12 additions & 5 deletions packages/app/src/specs/SpecsListHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="flex w-full gap-16px relative">
<div class="relative flex w-full gap-16px">
<Input
type="search"
class="flex-grow h-full min-w-200px"
Expand All @@ -10,12 +10,18 @@
@input="onInput"
>
<template #suffix>
<div
class="text-gray-500 border-l border-l-gray-100 pl-16px"
<button
class="mr-[-0.75rem] h-40px outline-none hover:(bg-indigo-50 text-indigo-500) transition-all rounded-r-md group"
data-cy="open-spec-pattern-modal"
aria-live="polite"
@click="emit('specPattern')"
>
{{ resultCount }} {{ resultCount === 1 ? t('specPage.matchSingular') : t('specPage.matchPlural') }}
</div>
<span
class="block border-l h-24px px-16px border-l-gray-100 group-hover:border-none"
>
{{ resultCount }} {{ resultCount === 1 ? t('specPage.matchSingular') : t('specPage.matchPlural') }}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
{{ resultCount }} {{ resultCount === 1 ? t('specPage.matchSingular') : t('specPage.matchPlural') }}
{{ resultCount }} {{ resultCount === 1 ? t('specPage.matchSingular') : t('specPage.matchPlural') }}
<span class="sr-only">{{ t(`createSpec.viewSpecPatternButton`) }} </span>

If we add an sr-only span here, it will give the button a useful label for screen readers, and we can replace .get('[data-cy="open-spec-pattern-modal"]') with something like cy.contains('button', 'View spec pattern') in tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated! I noticed alignment issues as well but they disappeared and I can't reproduce them. Could have been a new class that wasn't picked up if yarn dev was still running?

Copy link
Contributor

Choose a reason for hiding this comment

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

that sounds right!

</span>
</button>
</template>
</Input>

Expand Down Expand Up @@ -53,6 +59,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void,
(e: 'newSpec'): void
(e: 'specPattern'): void
}>()

const onInput = (e: Event) => {
Expand Down
10 changes: 5 additions & 5 deletions packages/frontend-shared/src/components/StandardModal.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<template>
<Dialog
:open="modelValue"
class="inset-0 z-10 fixed overflow-y-auto"
class="fixed inset-0 z-10 overflow-y-auto"
@close="clickOutside && closeModal()"
>
<div class="flex min-h-screen items-center justify-center">
<div class="flex items-center justify-center min-h-screen">
<slot
name="overlay"
:classes="'fixed inset-0'"
>
<DialogOverlay class="bg-gray-800 opacity-90 inset-0 fixed" />
<DialogOverlay class="fixed inset-0 bg-gray-800 opacity-90" />
</slot>
<div
class="bg-white rounded mx-auto ring-[#9095AD40] ring-4 relative"
Expand All @@ -27,7 +27,7 @@

<DialogDescription
v-if="$slots.description"
class="font-normal p-24px text-gray-700"
class="font-normal text-gray-700 p-24px"
>
<slot name="description" />
</DialogDescription>
Expand Down Expand Up @@ -72,7 +72,7 @@ const props = withDefaults(defineProps<{
}>(), {
clickOutside: true,
modelValue: false,
helpText: 'Need help?',
helpText: 'Need help',
helpLink: 'https://on.cypress.io',
class: undefined,
variant: undefined,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<template v-if="query?.data?.value">
<button
data-testid="open-config-file"
data-cy="open-config-file"
class="hocus-link-default underline-purple-500"
@click="showCypressConfigInIDE()"
>
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend-shared/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
},
"specPattern": {
"matches": "{0} Matches"
},
"specPatternModal": {
"title": "Spec pattern settings"
}
},
"clipboard": {
Expand Down