Skip to content

Commit d37581e

Browse files
authored
feat: IATR-M1.0 Debug page Header Update (#25072)
Co-authored-by: Stokes Player <stokes.player@gmail.com> Co-authored-by: elevatebart <bart@cypress.io> Closes #24851
1 parent ee859f6 commit d37581e

File tree

11 files changed

+224
-110
lines changed

11 files changed

+224
-110
lines changed

packages/app/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"dependencies": {},
2222
"devDependencies": {
2323
"@cypress-design/vue-icon": "^0.12.1",
24+
"@cypress-design/vue-statusicon": "0.2.0",
2425
"@graphql-typed-document-node/core": "^3.1.0",
2526
"@headlessui/vue": "1.4.0",
2627
"@iconify/iconify": "2.1.2",

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

+57-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { DebugPageFragmentDoc } from '../generated/graphql-test'
1+
import { CloudRunStatus, DebugPageFragmentDoc } from '../generated/graphql-test'
22
import DebugPageHeader from './DebugPageHeader.vue'
3+
import { defaultMessages } from '@cy/i18n'
34

45
const defaults = [
56
{ attr: 'debug-header-branch', text: 'Branch Name: feature/DESIGN-183' },
@@ -16,6 +17,7 @@ describe('<DebugPageHeader />', {
1617
cy.mountFragment(DebugPageFragmentDoc, {
1718
onResult (result) {
1819
if (result) {
20+
result.status = 'FAILED'
1921
if (result.commitInfo) {
2022
result.commitInfo.summary = 'Adding a hover state to the button component'
2123
result.commitInfo.branch = 'feature/DESIGN-183'
@@ -32,27 +34,71 @@ describe('<DebugPageHeader />', {
3234
})
3335

3436
cy.findByTestId('debug-header').children().should('have.length', 2)
35-
cy.findByTestId('debug-test-summary')
36-
.should('have.text', 'Adding a hover state to the button component')
37+
cy.findByTestId('debug-test-summary').should('have.text', 'Adding a hover state to the button component')
3738

38-
cy.findByTestId('debug-runCommit-info').children().should('have.length', 3)
39-
cy.findByTestId('debug-runNumber')
40-
.should('have.text', ' Run #432')
41-
.should('have.css', 'color', 'rgb(90, 95, 122)')
42-
43-
cy.findByTestId('debug-commitsAhead')
44-
.should('have.text', 'You are 2 commits ahead')
45-
.should('have.css', 'color', 'rgb(189, 88, 0)')
39+
cy.findByTestId('debug-commitsAhead').should('have.text', 'You are 2 commits ahead')
4640

4741
cy.findByTestId('debug-results').should('be.visible')
4842

43+
cy.findByTestId('debug-runNumber-FAILED')
44+
.should('have.text', '#432')
45+
.children().should('have.length', 2)
46+
47+
cy.findByTestId('debug-flaky-badge')
48+
.should('not.exist')
49+
4950
defaults.forEach((obj) => {
5051
cy.findByTestId(obj.attr)
5152
.should('have.text', obj.text)
5253
.children().should('have.length', 2)
5354
})
5455
})
5556

57+
it('displays a flaky badge', () => {
58+
const flakyCount = 4
59+
60+
cy.mountFragment(DebugPageFragmentDoc, {
61+
onResult: (result) => {
62+
if (result) {
63+
result.totalFlakyTests = flakyCount
64+
}
65+
},
66+
render: (gqlVal) => {
67+
return (
68+
<DebugPageHeader gql={gqlVal} commitsAhead={0}/>
69+
)
70+
},
71+
})
72+
73+
cy.findByTestId('debug-flaky-badge')
74+
.contains(defaultMessages.specPage.flaky.badgeLabel)
75+
76+
cy.findByTestId('total-flaky-tests')
77+
.contains(flakyCount)
78+
})
79+
80+
it('displays each run status', () => {
81+
const statuses: CloudRunStatus[] = ['PASSED', 'FAILED', 'CANCELLED', 'RUNNING', 'ERRORED']
82+
83+
statuses.forEach((status) => {
84+
cy.mountFragment(DebugPageFragmentDoc, {
85+
onResult: (result) => {
86+
if (result) {
87+
result.status = status
88+
}
89+
},
90+
render: (gqlVal) => {
91+
return (
92+
<DebugPageHeader gql={gqlVal} commitsAhead={0}/>
93+
)
94+
},
95+
})
96+
97+
cy.findByTestId(`debug-runNumber-${status}`).should('be.visible')
98+
cy.percySnapshot()
99+
})
100+
})
101+
56102
it('renders singular commit message', () => {
57103
cy.mountFragment(DebugPageFragmentDoc, {
58104
render: (gqlVal) => {

packages/app/src/debug/DebugPageHeader.vue

+42-15
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
>
66
<div
77
data-cy="debug-header"
8-
class="flex w-full grid py-24px px-24px gap-y-2 overflow-hidden items-center"
8+
class="flex w-full grid py-24px px-24px gap-y-2 items-center overflow-hidden"
99
>
1010
<ul
1111
data-cy="header-top"
12-
class="flex flex-row gap-x-2 self-stretch items-center whitespace-nowrap"
12+
class="flex flex-row gap-x-2 items-center self-stretch whitespace-nowrap"
1313
>
1414
<li
1515
v-if="debug?.commitInfo?.summary"
@@ -18,25 +18,18 @@
1818
>
1919
{{ debug.commitInfo.summary }}
2020
</li>
21-
<div
21+
<li
22+
v-if="props.commitsAhead"
2223
class="border rounded flex border-gray-100 h-6 text-sm items-center"
23-
data-cy="debug-runCommit-info"
2424
>
25-
<span
26-
class="font-medium mx-px px-2 text-gray-700 items-center"
27-
data-cy="debug-runNumber"
28-
>
29-
Run #{{ debug.runNumber }}
30-
</span>
31-
<div class="bg-gray-100 h-3 my-6px w-px" />
3225
<span
3326
v-if="props.commitsAhead"
3427
class="font-normal mx-px px-2 text-orange-500 items-center"
3528
data-cy="debug-commitsAhead"
3629
>
3730
{{ t('debugPage.header.commitsAhead', props.commitsAhead) }}
3831
</span>
39-
</div>
32+
</li>
4033
<li class="-mt-8px text-lg text-gray-400">
4134
.
4235
</li>
@@ -55,10 +48,24 @@
5548
class="flex flex-wrap font-normal text-sm text-gray-700 gap-x-2 items-center whitespace-nowrap children:flex children:items-center"
5649
>
5750
<li
58-
:data-cy="'debug-results'"
51+
class="flex flex-row text-sm gap-x-2 items-center justify-center"
5952
>
53+
<div
54+
v-if="(debug.runNumber && debug.status)"
55+
class="border rounded flex flex-row font-semibold bg-gray-50 border-gray-200 h-6 px-2 gap-x-1 items-center justify-center"
56+
:data-cy="`debug-runNumber-${debug.status}`"
57+
>
58+
<SolidStatusIcon
59+
size="16"
60+
:status="ICON_MAP[debug.status].type"
61+
/>
62+
<span :class="runNumberColor">
63+
{{ `#${debug.runNumber}` }}
64+
</span>
65+
</div>
6066
<DebugResults
6167
:gql="props.gql"
68+
data-cy="debug-results"
6269
/>
6370
</li>
6471
<li
@@ -107,9 +114,10 @@
107114
import { computed } from 'vue'
108115
import DebugResults from './DebugResults.vue'
109116
import ExternalLink from '@cy/gql-components/ExternalLink.vue'
110-
import type { DebugPageFragment } from '../generated/graphql'
111-
import CommitIcon from '~icons/cy/commit_x14'
117+
import type { DebugPageFragment, CloudRunStatus } from '../generated/graphql'
112118
import { IconTimeStopwatch } from '@cypress-design/vue-icon'
119+
import { SolidStatusIcon, StatusType } from '@cypress-design/vue-statusicon'
120+
import CommitIcon from '~icons/cy/commit_x14'
113121
import { gql } from '@urql/core'
114122
import { dayjs } from '../runs/utils/day.js'
115123
import { useI18n } from 'vue-i18n'
@@ -144,6 +152,25 @@ const props = defineProps<{
144152
145153
const debug = computed(() => props.gql)
146154
155+
const ICON_MAP: Record<CloudRunStatus, { textColor: string, type: StatusType }> = {
156+
PASSED: { textColor: 'text-jade-400', type: 'passed' },
157+
FAILED: { textColor: 'text-red-400', type: 'failed' },
158+
CANCELLED: { textColor: 'text-gray-500', type: 'cancelled' },
159+
ERRORED: { textColor: 'text-orange-400', type: 'errored' },
160+
RUNNING: { textColor: 'text-indigo-500', type: 'running' },
161+
NOTESTS: { textColor: 'text-indigo-500', type: 'noTests' },
162+
OVERLIMIT: { textColor: 'text-indigo-500', type: 'overLimit' },
163+
TIMEDOUT: { textColor: 'text-indigo-500', type: 'timedOut' },
164+
} as const
165+
166+
const runNumberColor = computed(() => {
167+
if (props.gql.status) {
168+
return ICON_MAP[props.gql.status].textColor
169+
}
170+
171+
return ''
172+
})
173+
147174
const relativeCreatedAt = computed(() => dayjs(new Date(debug.value.createdAt!)).fromNow())
148175
149176
const totalDuration = useDurationFormat(debug.value.totalDuration ?? 0)

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

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import DebugResults from './DebugResults.vue'
2+
import { DebugResultsFragmentDoc } from '../generated/graphql-test'
23
import { defaultMessages } from '@cy/i18n'
34
import { CloudRunStubs } from '@packages/graphql/test/stubCloudTypes'
45

@@ -14,10 +15,39 @@ describe('<DebugResults />', () => {
1415
cy.get(`[title=${defaultMessages.runs.results.failed}]`).should('contain.text', cloudRun.totalFailed)
1516
cy.get(`[title=${defaultMessages.runs.results.skipped}]`).should('contain.text', cloudRun.totalSkipped)
1617
cy.get(`[title=${defaultMessages.runs.results.pending}]`).should('contain.text', cloudRun.totalPending)
17-
cy.findByTestId('icon-prefix').should('exist')
1818
})
1919
})
2020

2121
cy.percySnapshot()
2222
})
2323
})
24+
25+
describe('Flaky badge tests', () => {
26+
const mountingFragment = (flakyTests: number) => {
27+
return (
28+
cy.mountFragment(DebugResultsFragmentDoc, {
29+
onResult (result) {
30+
if (result) {
31+
result.totalFlakyTests = flakyTests
32+
}
33+
},
34+
render: (gqlVal) => {
35+
return (
36+
<DebugResults gql={gqlVal} />
37+
)
38+
},
39+
})
40+
)
41+
}
42+
43+
it('does not show flaky component when flakyTests are < 1', () => {
44+
mountingFragment(0)
45+
cy.contains('Flaky').should('not.exist')
46+
})
47+
48+
it('contains flaky badge', () => {
49+
mountingFragment(4)
50+
cy.findByTestId('debug-flaky-badge').contains(defaultMessages.specPage.flaky.badgeLabel)
51+
cy.findByTestId('total-flaky-tests').contains(4)
52+
})
53+
})

packages/app/src/debug/DebugResults.vue

+19-24
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,34 @@
99
:total-skipped="results.totalSkipped"
1010
:total-pending="results.totalPending"
1111
:order="['PASSED', 'FAILED', 'SKIPPED', 'PENDING']"
12+
/>
13+
<div
14+
v-if="results?.totalFlakyTests"
15+
data-cy="debug-flaky-badge"
16+
class="border rounded flex flex-row gap-8px items-center h-6 bg-orange-50 border-orange-200 text-sm text-orange-600 px-2 gap-x-1 border-1"
1217
>
13-
<template #prefix>
14-
<div
15-
class="text-red-400 font-semibold text-sm flex items-center px-2"
16-
>
17-
<component
18-
:is="icon[0]"
19-
class="h-16px w-16px pr-2"
20-
data-cy="icon-prefix"
21-
/>
22-
{{ icon[1] }}
23-
</div>
24-
<div class="w-px h-3 my-6px bg-gray-100" />
25-
</template>
26-
</ResultCounts>
18+
<span
19+
data-cy="total-flaky-tests"
20+
class="font-medium pr-1 opacity-70"
21+
>
22+
{{ results.totalFlakyTests }}
23+
</span>
24+
<div class="w-px my-6px h-6 border-orange-200 border" />
25+
<span class="font-semibold pl-1">
26+
{{ t('specPage.flaky.badgeLabel') }}
27+
</span>
28+
</div>
2729
</div>
2830
</template>
2931

3032
<script lang="ts" setup>
3133
import { computed } from 'vue'
3234
import type { DebugResultsFragment } from '../generated/graphql'
3335
import { gql } from '@urql/core'
34-
import FailedSolidIcon from '~icons/cy/status-failed-solid_x24.svg'
35-
import PassedIcon from '~icons/cy/passed-solid_x16.svg'
3636
import ResultCounts from '@packages/frontend-shared/src/components/ResultCounts.vue'
37+
import { useI18n } from '@cy/i18n'
38+
39+
const { t } = useI18n()
3740
3841
gql`
3942
fragment DebugResults on CloudRun {
@@ -50,13 +53,5 @@ const props = defineProps<{
5053
gql: DebugResultsFragment
5154
}>()
5255
53-
const ICON_MAP = {
54-
PASSED: [PassedIcon, 'Passed'],
55-
FAILED: [FailedSolidIcon, 'Failed'],
56-
} as const
57-
58-
const icon = computed(() => ICON_MAP['FAILED'])
59-
6056
const results = computed(() => props.gql)
61-
6257
</script>

packages/frontend-shared/src/components/ResultCounts.cy.tsx

-20
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,4 @@ describe('<ResultCounts />', () => {
6969
expect(status[3]).to.contain(5)
7070
})
7171
})
72-
73-
const slotContent = {
74-
prefix: () => <div class="h-full bg-emerald-100">Prefix</div>,
75-
}
76-
77-
it('tests if the prefix slot shows up in the Result counts', () => {
78-
cy.mount(() => (
79-
<ResultCounts
80-
data-cy='result-count'
81-
totalFailed={3}
82-
totalPassed={4}
83-
totalPending={5}
84-
totalSkipped={6}
85-
v-slots={slotContent}
86-
order={['SKIPPED', 'FAILED', 'PASSED', 'PENDING']}
87-
/>
88-
))
89-
90-
cy.findByText('Prefix').should('be.visible')
91-
})
9272
})

packages/frontend-shared/src/components/ResultCounts.vue

-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
<template>
22
<div class="border rounded flex border-gray-200 h-6 text-gray-700 text-size-14px leading-20px">
3-
<slot
4-
name="prefix"
5-
data-cy="prefix"
6-
/>
73
<div
84
v-for="(result, i) in results"
95
:key="i"

packages/graphql/schemas/cloud.graphql

+15-1
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ type CloudSpecRun implements Node {
846846
"""
847847
Most important status for the spec shared between all groups
848848
"""
849-
status: CloudRunGroupStatusEnum
849+
status: CloudSpecStatus
850850

851851
"""
852852
Aggregate information about how many tests failed in the groups
@@ -903,6 +903,20 @@ type CloudSpecRunEdge {
903903
node: CloudSpecRun!
904904
}
905905

906+
"""
907+
Possible check status of the spec within a run
908+
"""
909+
enum CloudSpecStatus {
910+
CANCELLED
911+
ERRORED
912+
FAILED
913+
NOTESTS
914+
PASSED
915+
RUNNING
916+
TIMEDOUT
917+
UNCLAIMED
918+
}
919+
906920
"""
907921
Details of a recording in Cypress Cloud for a single test within a run
908922
"""

0 commit comments

Comments
 (0)