Skip to content

Commit 216d4c5

Browse files
authored
feat: run failures enhancements (#25234)
1 parent 68a02fc commit 216d4c5

16 files changed

+493
-100
lines changed

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

+40-28
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DebugSpecsFragmentDoc } from '../generated/graphql-test'
1+
import { DebugSpecListGroupsFragment, DebugSpecListSpecFragment, DebugSpecListTestsFragment, DebugSpecsFragmentDoc } from '../generated/graphql-test'
22
import DebugContainer from './DebugContainer.vue'
33
import { defaultMessages } from '@cy/i18n'
44
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store'
@@ -83,69 +83,81 @@ describe('<DebugContainer />', () => {
8383
})
8484

8585
describe('testing util function: debugMapping', () => {
86-
const createSpecs = (idArr: string[]) => {
87-
const acc: {id: string}[] = []
88-
89-
idArr.forEach((val) => {
90-
acc.push({ id: val })
91-
})
92-
93-
return acc
94-
}
95-
9686
it('maps correctly for a single spec', () => {
97-
const spec = createSpecs(['a1c'])
87+
const specs = [
88+
{ id: 'a1c', groupIds: ['a'] },
89+
] as DebugSpecListSpecFragment[]
9890
const tests = [
9991
{ specId: 'a1c', id: 'random1' },
10092
{ specId: 'a1c', id: 'random2' },
101-
]
93+
] as DebugSpecListTestsFragment[]
94+
const groups = [
95+
{ id: 'a', testingType: 'e2e' },
96+
{ id: 'b', testingType: 'e2e' },
97+
] as DebugSpecListGroupsFragment[]
10298

103-
const debugMappingArray = specsList(spec, tests)
99+
const debugMappingArray = specsList({ specs, tests, groups, localSpecs: [], currentTestingType: 'e2e' })
104100

105101
expect(debugMappingArray).to.have.length(1)
106-
expect(debugMappingArray[0]).to.deep.equal({ spec: { id: 'a1c' }, tests: [{ specId: 'a1c', id: 'random1' }, { specId: 'a1c', id: 'random2' }] })
102+
expect(debugMappingArray[0]).to.deep.equal({ spec: { id: 'a1c', groupIds: ['a'] }, tests: [{ specId: 'a1c', id: 'random1' }, { specId: 'a1c', id: 'random2' }], groups: [{ id: 'a', testingType: 'e2e' }], foundLocally: false, testingType: 'e2e', matchesCurrentTestingType: true })
107103
})
108104

109105
it('maps correctly for multiple specs and test', () => {
110-
const specs = createSpecs(['123', '456', '789'])
106+
const specs = [
107+
{ id: '123', groupIds: ['a'] },
108+
{ id: '456', groupIds: ['b'] },
109+
{ id: '789', groupIds: ['a', 'b'] },
110+
] as DebugSpecListSpecFragment[]
111111
const tests = [
112112
{ specId: '123', id: 'random1' },
113113
{ specId: '456', id: 'random2' },
114114
{ specId: '456', id: 'random3' },
115115
{ specId: '789', id: 'random4' },
116116
{ specId: '123', id: 'random6' },
117-
]
117+
] as DebugSpecListTestsFragment[]
118+
const groups = [
119+
{ id: 'a', testingType: 'e2e' },
120+
{ id: 'b', testingType: 'e2e' },
121+
] as DebugSpecListGroupsFragment[]
118122

119-
const debugMappingArray = specsList(specs, tests)
123+
const debugMappingArray = specsList({ specs, tests, localSpecs: [], currentTestingType: 'e2e', groups })
120124

121125
const expected = [
122-
{ spec: { id: '123' }, tests: [{ specId: '123', id: 'random1' }, { specId: '123', id: 'random6' }] },
123-
{ spec: { id: '456' }, tests: [{ specId: '456', id: 'random2' }, { specId: '456', id: 'random3' }] },
124-
{ spec: { id: '789' }, tests: [{ specId: '789', id: 'random4' }] },
126+
{ spec: { id: '123', groupIds: ['a'] }, tests: [{ specId: '123', id: 'random1' }, { specId: '123', id: 'random6' }], groups: [{ id: 'a', testingType: 'e2e' }], foundLocally: false, testingType: 'e2e', matchesCurrentTestingType: true },
127+
{ spec: { id: '456', groupIds: ['b'] }, tests: [{ specId: '456', id: 'random2' }, { specId: '456', id: 'random3' }], groups: [{ id: 'b', testingType: 'e2e' }], foundLocally: false, testingType: 'e2e', matchesCurrentTestingType: true },
128+
{ spec: { id: '789', groupIds: ['a', 'b'] }, tests: [{ specId: '789', id: 'random4' }], groups: [{ id: 'a', testingType: 'e2e' }, { id: 'b', testingType: 'e2e' }], foundLocally: false, testingType: 'e2e', matchesCurrentTestingType: true },
125129
]
126130

127131
expect(debugMappingArray).to.deep.equal(expected)
128132
})
129133

130134
it('maps does not show specs that do not have tests', () => {
131-
const specs = createSpecs(['123', '456', '789'])
132-
const tests = [{ specId: '123', id: 'random1' }]
135+
const specs = [
136+
{ id: '123', groupIds: ['a'] },
137+
{ id: '456', groupIds: ['a'] },
138+
{ id: '789', groupIds: ['a'] },
139+
] as DebugSpecListSpecFragment[]
140+
const tests = [{ specId: '123', id: 'random1' }] as DebugSpecListTestsFragment[]
141+
const groups = [{ id: 'a', testingType: 'e2e' }] as DebugSpecListGroupsFragment[]
133142

134-
const debugMappingArray = specsList(specs, tests)
143+
const debugMappingArray = specsList({ specs, tests, localSpecs: [], currentTestingType: 'e2e', groups })
135144

136145
expect(debugMappingArray).to.have.length(1)
137-
expect(debugMappingArray).to.deep.equal([{ spec: { id: '123' }, tests: [{ specId: '123', id: 'random1' }] }])
146+
expect(debugMappingArray).to.deep.equal([{ spec: { id: '123', groupIds: ['a'] }, tests: [{ specId: '123', id: 'random1' }], groups: [{ id: 'a', testingType: 'e2e' }], foundLocally: false, testingType: 'e2e', matchesCurrentTestingType: true }])
138147
})
139148

140149
it('throws an error when a test does not map to a spec', () => {
141-
const specs = createSpecs(['123'])
150+
const specs = [
151+
{ id: '123', groupIds: ['a'] },
152+
] as DebugSpecListSpecFragment[]
142153
const tests = [
143154
{ specId: '123', id: 'random1' },
144155
{ specId: '456', id: 'random2' },
145-
]
156+
] as DebugSpecListTestsFragment[]
157+
const groups = [{ id: 'a' }] as DebugSpecListGroupsFragment[]
146158

147159
const specsListWrapper = () => {
148-
return specsList(specs, tests)
160+
return specsList({ specs, tests, groups, localSpecs: [], currentTestingType: 'e2e' })
149161
}
150162

151163
expect(specsListWrapper).to.throw('Could not find spec for id 456')

packages/app/src/debug/DebugContainer.vue

+31-5
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<script setup lang="ts">
3838
import { gql } from '@urql/vue'
3939
import { computed } from '@vue/reactivity'
40-
import type { DebugSpecsFragment } from '../generated/graphql'
40+
import type { DebugSpecsFragment, TestingTypeEnum } from '../generated/graphql'
4141
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store'
4242
import DebugPageHeader from './DebugPageHeader.vue'
4343
import DebugSpecList from './DebugSpecList.vue'
@@ -46,6 +46,14 @@ import { specsList } from './utils/DebugMapping'
4646
4747
const { t } = useI18n()
4848
49+
gql`
50+
fragment DebugLocalSpecs on Spec {
51+
id
52+
absolute
53+
relative
54+
}
55+
`
56+
4957
gql`
5058
fragment DebugSpecs on Query {
5159
currentProject {
@@ -54,7 +62,7 @@ fragment DebugSpecs on Query {
5462
__typename
5563
... on CloudProject {
5664
id
57-
runByNumber(runNumber: 6) {
65+
runByNumber(runNumber: 11) {
5866
...DebugPage
5967
id
6068
runNumber
@@ -69,9 +77,18 @@ fragment DebugSpecs on Query {
6977
id
7078
...DebugSpecListSpec
7179
}
80+
groups {
81+
id,
82+
...DebugSpecListGroups
83+
}
7284
}
7385
}
7486
}
87+
specs {
88+
id
89+
...DebugLocalSpecs
90+
}
91+
currentTestingType
7592
}
7693
}
7794
`
@@ -87,14 +104,23 @@ const run = computed(() => {
87104
})
88105
89106
const debugSpecsArray = computed(() => {
90-
if (run.value) {
107+
if (run.value && props.gql.currentProject) {
91108
const specs = run.value.specs || []
92109
const tests = run.value.testsForReview || []
110+
const groups = run.value.groups || []
111+
// Will be defined so ignore the possibility of null for testingType
112+
const currentTestingType = props.gql.currentProject.currentTestingType as TestingTypeEnum
113+
const localSpecs = props.gql.currentProject.specs
93114
94-
return specsList(specs, tests)
115+
return specsList({
116+
specs,
117+
tests,
118+
groups,
119+
localSpecs,
120+
currentTestingType,
121+
})
95122
}
96123
97124
return []
98125
})
99-
100126
</script>

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

+76-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import type { Spec, TestResults } from './DebugSpec.vue'
2-
import DebugSpec from './DebugSpec.vue'
1+
import DebugSpec, { Spec, TestResults } from './DebugSpec.vue'
32
import { defaultMessages } from '@cy/i18n'
43

54
describe('<DebugSpec/> with multiple test results', () => {
@@ -8,6 +7,7 @@ describe('<DebugSpec/> with multiple test results', () => {
87
path: 'cypress/tests/',
98
fileName: 'auth',
109
fileExtension: '.spec.ts',
10+
fullPath: 'cypress/tests/auth.spec.ts',
1111
}
1212

1313
const testResults: TestResults[] = [
@@ -23,31 +23,20 @@ describe('<DebugSpec/> with multiple test results', () => {
2323

2424
it('mounts correctly', () => {
2525
cy.mount(() => (
26-
<DebugSpec spec={spec} testResults={testResults} />
26+
<DebugSpec spec={spec} testResults={testResults} foundLocally={true} testingType={'e2e'} matchesCurrentTestingType={true} />
2727
))
2828

2929
cy.findByTestId('debug-spec-item').children().should('have.length', 3)
3030
cy.findByTestId('spec-contents').children().should('have.length', 2)
3131
cy.findByTestId('spec-path').should('have.text', 'cypress/tests/auth.spec.ts')
3232
cy.contains('auth').should('be.visible')
3333
cy.findByTestId('run-failures').should('not.be.disabled')
34-
.contains(defaultMessages.debugPage.runFailures)
34+
.contains(defaultMessages.debugPage.runFailures.btn)
3535

3636
cy.findAllByTestId('test-group').should('have.length', 2)
3737

3838
cy.percySnapshot()
3939
})
40-
41-
it('renders correctly with disabled run-failures button', () => {
42-
cy.mount(() => (
43-
<DebugSpec spec={spec} testResults={testResults} isDisabled={true} />
44-
))
45-
46-
cy.findByTestId('run-failures').should('have.attr', 'aria-disabled', 'disabled')
47-
.should('not.have.attr', 'href')
48-
49-
cy.percySnapshot()
50-
})
5140
})
5241

5342
describe('<DebugSpec/> responsive UI', () => {
@@ -68,10 +57,11 @@ describe('<DebugSpec/> responsive UI', () => {
6857
path: 'cypress/tests/',
6958
fileName: 'AlertBar',
7059
fileExtension: '.spec.ts',
60+
fullPath: 'cypress/tests/AlertBar.spec.ts',
7161
}
7262

7363
cy.mount(() => (
74-
<DebugSpec spec={spec} testResults={testResults} />
64+
<DebugSpec spec={spec} testResults={testResults} foundLocally={true} testingType={'e2e'} matchesCurrentTestingType={true} />
7565
))
7666

7767
cy.findByTestId('spec-contents').children().should('have.length', 2)
@@ -88,10 +78,11 @@ describe('<DebugSpec/> responsive UI', () => {
8878
path: 'src/shared/frontend/cow/packages/foo/cypress/tests/e2e/components',
8979
fileName: 'AlertBar',
9080
fileExtension: '.spec.ts',
81+
fullPath: 'src/shared/frontend/cow/packages/foo/cypress/tests/e2e/components/AlertBar.spec.ts',
9182
}
9283

9384
cy.mount(() => (
94-
<DebugSpec spec={spec} testResults={testResults} />
85+
<DebugSpec spec={spec} testResults={testResults} foundLocally={true} testingType={'e2e'} matchesCurrentTestingType={true} />
9586
))
9687

9788
cy.findByTestId('spec-path').should('have.css', 'text-overflow', 'ellipsis')
@@ -100,3 +91,71 @@ describe('<DebugSpec/> responsive UI', () => {
10091
cy.percySnapshot()
10192
})
10293
})
94+
95+
describe('Run Failures button', () => {
96+
const spec: Spec = {
97+
id: '1',
98+
path: 'cypress/tests/',
99+
fileName: 'auth',
100+
fileExtension: '.spec.ts',
101+
fullPath: 'cypress/tests/auth.spec.ts',
102+
}
103+
104+
const testResults: TestResults[] = [
105+
{
106+
id: '2',
107+
titleParts: ['Login', 'Should redirect unauthenticated user to signin page'],
108+
},
109+
{
110+
id: '3',
111+
titleParts: ['Login', 'redirects to stored path after login'],
112+
},
113+
]
114+
115+
it('is disabled if spec is not found locally', () => {
116+
cy.mount(() => <DebugSpec spec={spec} testResults={testResults} foundLocally={false} testingType={'e2e'} matchesCurrentTestingType={true}/>)
117+
118+
cy.findByTestId('run-failures')
119+
.should('have.attr', 'aria-disabled', 'disabled')
120+
.should('not.have.attr', 'href')
121+
122+
cy.findByTestId('run-failures').realHover()
123+
124+
cy.findByTestId('run-all-failures-tooltip').should('be.visible').contains('Spec was not found locally')
125+
126+
cy.percySnapshot()
127+
})
128+
129+
it('is disabled if run testing-type differs from the current testing-type', () => {
130+
cy.mount(() => (
131+
<DebugSpec
132+
spec={spec}
133+
testResults={testResults}
134+
foundLocally={true}
135+
testingType='e2e'
136+
matchesCurrentTestingType={false}
137+
onSwitchTestingType={cy.spy().as('switchTestingType')}/>
138+
))
139+
140+
cy.findByTestId('run-failures')
141+
.should('have.attr', 'aria-disabled', 'disabled')
142+
.should('not.have.attr', 'href')
143+
144+
cy.findByTestId('run-failures').realHover()
145+
146+
cy.findByTestId('run-all-failures-tooltip').should('be.visible').within(() => {
147+
cy.contains('span', 'There are 2 e2e tests failing in this spec. To run them locally switch to e2e testing.')
148+
cy.contains('button', 'Switch to e2e testing').click()
149+
150+
cy.get('@switchTestingType').should('have.been.calledWith', 'e2e')
151+
})
152+
})
153+
154+
it('is enabled if found locally and same testing type', () => {
155+
cy.mount(() => <DebugSpec spec={spec} testResults={testResults} foundLocally={true} testingType={'e2e'} matchesCurrentTestingType={true}/>)
156+
157+
cy.findByTestId('run-failures')
158+
.should('have.attr', 'href', '#/specs/runner?file=cypress/tests/auth.spec.ts')
159+
.and('not.have.attr', 'aria-disabled')
160+
})
161+
})

0 commit comments

Comments
 (0)