Skip to content

Commit 552fe87

Browse files
authored
feat: IATR empty states (#25219) [run ci]
1 parent 216d4c5 commit 552fe87

19 files changed

+407
-52
lines changed

packages/app/cypress/e2e/runs.cy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
279279
name: 'Test User A',
280280
} })
281281

282-
cy.contains('button', 'Log in to Cypress Cloud').click()
282+
cy.contains('button', 'Connect to Cypress Cloud').click()
283283

284284
cy.findByRole('dialog', { name: 'Log in to Cypress' }).as('logInModal').within(() => {
285285
cy.findByRole('button', { name: 'Log in' }).click()

packages/app/cypress/e2e/settings.cy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ describe('App: Settings without cloud', () => {
402402
o.sinon.stub(ctx._apis.authApi, 'logIn')
403403
})
404404

405-
cy.contains('button', 'Log in to Cypress Cloud').click()
405+
cy.contains('button', 'Connect to Cypress Cloud').click()
406406
cy.findByRole('dialog', { name: 'Log in to Cypress' }).within(() => {
407407
cy.contains('button', 'Log in').click()
408408
})

packages/app/src/debug/DebugContainer.cy.tsx

+26-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { CloudRunStubs } from '@packages/graphql/test/stubCloudTypes'
77

88
describe('<DebugContainer />', () => {
99
context('empty states', () => {
10-
const validateEmptyState = (expectedMessage: string) => {
10+
const validateEmptyState = (expectedMessages: string[]) => {
1111
cy.mountFragment(DebugSpecsFragmentDoc, {
1212
render: (gqlVal) => {
1313
return (
@@ -18,19 +18,24 @@ describe('<DebugContainer />', () => {
1818
},
1919
})
2020

21-
cy.findByTestId('debug-empty').contains(expectedMessage)
21+
expectedMessages.forEach((message) => {
22+
cy.findByTestId('debug-empty').contains(message)
23+
})
2224
}
2325

2426
it('shows not logged in', () => {
25-
validateEmptyState(defaultMessages.debugPage.notLoggedIn)
27+
validateEmptyState([defaultMessages.debugPage.emptyStates.connectToCypressCloud, defaultMessages.debugPage.emptyStates.debugDirectlyInCypress, defaultMessages.debugPage.emptyStates.notLoggedInTestMessage])
28+
cy.findByRole('button', { name: 'Connect to Cypress Cloud' }).should('be.visible')
2629
})
2730

28-
it('is logged in', () => {
31+
it('is logged in with no project', () => {
2932
const loginConnectStore = useLoginConnectStore()
3033

3134
loginConnectStore.setUserFlag('isLoggedIn', true)
35+
loginConnectStore.setProjectFlag('isProjectConnected', false)
3236

33-
validateEmptyState(defaultMessages.debugPage.notConnected)
37+
validateEmptyState([defaultMessages.debugPage.emptyStates.debugDirectlyInCypress, defaultMessages.debugPage.emptyStates.reviewRerunAndDebug, defaultMessages.debugPage.emptyStates.noProjectTestMessage])
38+
cy.findByRole('button', { name: 'Connect a Cypress Cloud project' }).should('be.visible')
3439
})
3540

3641
it('has no runs', () => {
@@ -39,16 +44,24 @@ describe('<DebugContainer />', () => {
3944
loginConnectStore.setUserFlag('isLoggedIn', true)
4045
loginConnectStore.setProjectFlag('isProjectConnected', true)
4146
cy.mountFragment(DebugSpecsFragmentDoc, {
42-
render: (gqlVal) => {
43-
return (
44-
<DebugContainer
45-
gql={gqlVal}
46-
/>
47-
)
48-
},
47+
render: (gqlVal) => <DebugContainer gql={gqlVal} />,
48+
})
49+
50+
validateEmptyState([defaultMessages.debugPage.emptyStates.recordYourFirstRun, defaultMessages.debugPage.emptyStates.almostThere, defaultMessages.debugPage.emptyStates.noRunsTestMessage])
51+
cy.findByDisplayValue('npx cypress run --record --key 2aaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa').should('be.visible')
52+
})
53+
54+
it('errors', () => {
55+
const loginConnectStore = useLoginConnectStore()
56+
57+
loginConnectStore.setUserFlag('isLoggedIn', true)
58+
loginConnectStore.setProjectFlag('isProjectConnected', true)
59+
cy.mountFragment(DebugSpecsFragmentDoc, {
60+
render: (gqlVal) => <DebugContainer gql={gqlVal} showError={true} />,
4961
})
5062

51-
cy.findByTestId('debug-empty').contains(defaultMessages.debugPage.noRuns)
63+
cy.findByTestId('debug-empty').should('not.exist')
64+
cy.findByTestId('debug-alert').should('be.visible')
5265
})
5366
})
5467

packages/app/src/debug/DebugContainer.vue

+16-22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<template>
22
<div>
3+
<DebugError
4+
v-if="showError"
5+
/>
36
<div
4-
v-if="loginConnectStore.user.isLoggedIn && loginConnectStore.project.isProjectConnected && run"
7+
v-else-if="loginConnectStore.user.isLoggedIn && loginConnectStore.project.isProjectConnected && run"
58
>
69
<DebugPageHeader
710
:gql="run"
@@ -15,21 +18,9 @@
1518
v-else
1619
data-cy="debug-empty"
1720
>
18-
<div
19-
v-if="!loginConnectStore.user.isLoggedIn"
20-
>
21-
{{ t('debugPage.notLoggedIn') }}
22-
</div>
23-
<div
24-
v-else-if="!loginConnectStore.project.isProjectConnected"
25-
>
26-
{{ t('debugPage.notConnected' ) }}
27-
</div>
28-
<div
29-
v-else-if="!run"
30-
>
31-
{{ t('debugPage.noRuns') }}
32-
</div>
21+
<DebugNotLoggedIn v-if="!loginConnectStore.user.isLoggedIn" />
22+
<DebugNoProject v-else-if="!loginConnectStore.project.isProjectConnected" />
23+
<DebugNoRuns v-else-if="!run" />
3324
</div>
3425
</div>
3526
</template>
@@ -41,11 +32,12 @@ import type { DebugSpecsFragment, TestingTypeEnum } from '../generated/graphql'
4132
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store'
4233
import DebugPageHeader from './DebugPageHeader.vue'
4334
import DebugSpecList from './DebugSpecList.vue'
44-
import { useI18n } from 'vue-i18n'
35+
import DebugNotLoggedIn from './empty/DebugNotLoggedIn.vue'
36+
import DebugNoProject from './empty/DebugNoProject.vue'
37+
import DebugNoRuns from './empty/DebugNoRuns.vue'
38+
import DebugError from './empty/DebugError.vue'
4539
import { specsList } from './utils/DebugMapping'
4640
47-
const { t } = useI18n()
48-
4941
gql`
5042
fragment DebugLocalSpecs on Spec {
5143
id
@@ -94,17 +86,19 @@ fragment DebugSpecs on Query {
9486
`
9587
9688
const props = defineProps<{
97-
gql: DebugSpecsFragment
89+
gql?: DebugSpecsFragment
90+
// This prop is just to stub the error state for now
91+
showError?: boolean
9892
}>()
9993
10094
const loginConnectStore = useLoginConnectStore()
10195
10296
const run = computed(() => {
103-
return props.gql.currentProject?.cloudProject?.__typename === 'CloudProject' ? props.gql.currentProject.cloudProject.runByNumber : null
97+
return props.gql?.currentProject?.cloudProject?.__typename === 'CloudProject' ? props.gql.currentProject.cloudProject.runByNumber : null
10498
})
10599
106100
const debugSpecsArray = computed(() => {
107-
if (run.value && props.gql.currentProject) {
101+
if (run.value && props.gql?.currentProject) {
108102
const specs = run.value.specs || []
109103
const tests = run.value.testsForReview || []
110104
const groups = run.value.groups || []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import DebugNotLoggedIn from './DebugNotLoggedIn.vue'
2+
import DebugNoProject from './DebugNoProject.vue'
3+
import DebugNoRuns from './DebugNoRuns.vue'
4+
import DebugLoading from './DebugLoading.vue'
5+
import DebugError from './DebugError.vue'
6+
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store'
7+
8+
describe('Debug page empty states', () => {
9+
context('not logged in', () => {
10+
it('renders', () => {
11+
const loginConnectStore = useLoginConnectStore()
12+
13+
// We need to set isLoggedIn so that CloudConnectButton shows the correct state
14+
loginConnectStore.setUserFlag('isLoggedIn', false)
15+
16+
cy.mount(<DebugNotLoggedIn />)
17+
18+
cy.percySnapshot()
19+
})
20+
})
21+
22+
context('no project', () => {
23+
it('renders', () => {
24+
const loginConnectStore = useLoginConnectStore()
25+
26+
// We need to set isLoggedIn so that CloudConnectButton shows the correct state
27+
loginConnectStore.setUserFlag('isLoggedIn', true)
28+
29+
cy.mount(<DebugNoProject />)
30+
31+
cy.percySnapshot()
32+
})
33+
})
34+
35+
context('no runs', () => {
36+
it('renders', () => {
37+
cy.mount(<DebugNoRuns />)
38+
39+
cy.percySnapshot()
40+
})
41+
})
42+
43+
context('loading', () => {
44+
it('renders', () => {
45+
cy.mount(<DebugLoading />)
46+
47+
cy.percySnapshot()
48+
})
49+
})
50+
51+
context('error', () => {
52+
it('renders', () => {
53+
cy.mount(<DebugError />)
54+
55+
cy.percySnapshot()
56+
})
57+
})
58+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
<div class="flex flex-col my-45px items-center">
3+
<div class="flex flex-col items-center justify-evenly">
4+
<div><i-cy-box-open_x48 class="icon-dark-gray-500 icon-light-indigo-100" /></div>
5+
<div class="flex flex-col mx-[20%] mt-25px mb-20px items-center">
6+
<div class="font-medium my-5px text-center text-gray-900 text-18px">
7+
{{ title }}
8+
</div>
9+
<div class="font-normal my-5px text-center leading-relaxed text-16px text-gray-600">
10+
{{ description }}
11+
</div>
12+
</div>
13+
<slot name="cta" />
14+
</div>
15+
<div class="flex flex-col my-40px w-full items-center">
16+
<DebugTestLoadingContainer
17+
width-class="w-[75%]"
18+
dot-class="icon-light-gray-200"
19+
:rows="loadingRows"
20+
>
21+
<template #header>
22+
<div class="bg-white border rounded-md flex border-gray-100 w-max p-5px text-14px text-gray-700">
23+
<div><i-cy-status-failed_x12 /></div>
24+
<div class="bg-gray-700 h-1px mx-5px mt-7px w-5px" />
25+
<div
26+
v-if="exampleTestName"
27+
class="bg-gray-100 h-13px mx-1 pb-1px w-1px"
28+
/>
29+
<div
30+
v-if="exampleTestName"
31+
class="mx-1 text-14px text-gray-700"
32+
>
33+
{{ exampleTestName }}
34+
</div>
35+
</div>
36+
</template>
37+
</DebugTestLoadingContainer>
38+
</div>
39+
</div>
40+
</template>
41+
42+
<script lang="ts" setup>
43+
import DebugTestLoadingContainer from './DebugTestLoadingContainer.vue'
44+
45+
defineProps<{
46+
title: string
47+
description?: string
48+
exampleTestName?: string
49+
}>()
50+
51+
const loadingRows = [
52+
['w-40px', 'w-[40%]'],
53+
['w-40px', 'w-[50%]'],
54+
['w-40px', 'w-[65%]'],
55+
]
56+
57+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<div class="m-25px">
3+
<Alert
4+
data-cy="debug-alert"
5+
status="warning"
6+
:title="t('debugPage.emptyStates.gitRepositoryNotDetected')"
7+
:icon="WarningIcon"
8+
dismissible
9+
>
10+
<p>{{ t('debugPage.emptyStates.ensureGitSetupCorrectly') }}</p>
11+
</Alert>
12+
</div>
13+
<DebugEmptyView
14+
:title="t('debugPage.emptyStates.debugDirectlyInCypress')"
15+
:description="t('debugPage.emptyStates.reviewRerunAndDebug')"
16+
/>
17+
</template>
18+
19+
<script lang="ts" setup>
20+
import DebugEmptyView from './DebugEmptyView.vue'
21+
import Alert from '@packages/frontend-shared/src/components/Alert.vue'
22+
import WarningIcon from '~icons/cy/warning_x16.svg'
23+
import { useI18n } from '@cy/i18n'
24+
25+
const { t } = useI18n()
26+
27+
</script>

0 commit comments

Comments
 (0)