Skip to content

Commit 660ff67

Browse files
warrensplayerZachJW34amehta265elevatebartrockindahizzy
authored
feat: Debug page [IATR] (#25488)
Co-authored-by: Zachary Williams <ZachJW34@gmail.com> Co-authored-by: Ankit <ankit@cypress.io> Co-authored-by: Stokes Player <stokes.player@gmail.com> Co-authored-by: elevatebart <bart@cypress.io> Co-authored-by: Rocky <25568640+rockindahizzy@users.noreply.github.com> Co-authored-by: Stokes Player <stokes@cypress.io> Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com> Co-authored-by: Mark Noonan <mark@cypress.io> Co-authored-by: Mike Plummer <mikep@cypress.io> Co-authored-by: amehta265 <65267668+amehta265@users.noreply.github.com> Co-authored-by: Adam Stone-Lord <adams@cypress.io> Co-authored-by: Mike Plummer <mike-plummer@users.noreply.github.com> Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
1 parent ee97b94 commit 660ff67

File tree

173 files changed

+14412
-571
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

173 files changed

+14412
-571
lines changed

cli/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
_Released 01/31/2023 (PENDING)_
55

6+
**Features:**
7+
8+
- Easily debug failed CI test runs right from your local Cypress app with the new Debug page, powered by Cypress Cloud. For more details, see the [Debug documentation](https://on.cypress.io/debug-page). Addressed in [#25488](https://github.com/cypress-io/cypress/pull/25488).
9+
610
**Bugfixes:**
711

812
- Fixed an issue where alternative Microsoft Edge Beta, Canary, and Dev binary versions were not being discovered by Cypress.

packages/app/cypress/e2e/cypress-in-cypress-run-mode.cy.ts

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1+
import { CY_IN_CY_SIMULATE_RUN_MODE } from '@packages/types/src/constants'
2+
13
describe('Cypress In Cypress - run mode', { viewportWidth: 1200 }, () => {
24
it('e2e run mode spec runner header is correct', () => {
35
cy.scaffoldProject('cypress-in-cypress')
46
cy.findBrowsers()
57
cy.openProject('cypress-in-cypress')
68
cy.startAppServer()
7-
cy.visitApp()
8-
9-
simulateRunModeInUI()
9+
cy.visitApp(`/specs/runner?file=cypress/e2e/dom-content.spec.js&${CY_IN_CY_SIMULATE_RUN_MODE}`)
1010

11-
cy.contains('dom-content.spec').click()
1211
cy.waitForSpecToFinish()
1312

1413
cy.findByTestId('aut-url').should('be.visible')
@@ -33,17 +32,14 @@ describe('Cypress In Cypress - run mode', { viewportWidth: 1200 }, () => {
3332
// cy.percySnapshot() // TODO: restore when Percy CSS is fixed. See https://github.com/cypress-io/cypress/issues/23435
3433
})
3534

36-
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23306
37-
it('component testing run mode spec runner header is correct', { retries: 15 }, () => {
35+
it('component testing run mode spec runner header is correct', () => {
3836
cy.scaffoldProject('cypress-in-cypress')
3937
cy.findBrowsers()
4038
cy.openProject('cypress-in-cypress')
4139
cy.startAppServer('component')
42-
cy.visitApp()
43-
simulateRunModeInUI()
44-
cy.contains('TestComponent.spec').click()
45-
cy.waitForSpecToFinish()
40+
cy.visitApp(`/specs/runner?file=src/TestComponent.spec.jsx&${CY_IN_CY_SIMULATE_RUN_MODE}`)
4641

42+
cy.waitForSpecToFinish()
4743
cy.findByTestId('aut-url').should('not.exist')
4844
cy.findByTestId('playground-activator').should('not.exist')
4945

@@ -81,9 +77,7 @@ describe('Cypress In Cypress - run mode', { viewportWidth: 1200 }, () => {
8177
})
8278
})
8379

84-
cy.visitApp()
85-
simulateRunModeInUI()
86-
cy.contains('dom-content.spec').click()
80+
cy.visitApp(`/specs/runner?file=cypress/e2e/dom-content.spec.js&${CY_IN_CY_SIMULATE_RUN_MODE}`)
8781

8882
cy.contains('http://localhost:4455/cypress/e2e/dom-content.html').should('be.visible')
8983
cy.findByLabelText('Stats').should('not.exist')
@@ -92,13 +86,3 @@ describe('Cypress In Cypress - run mode', { viewportWidth: 1200 }, () => {
9286
cy.findByTestId('sidebar').should('not.exist')
9387
})
9488
})
95-
96-
function simulateRunModeInUI () {
97-
// this simulates run mode enough for this test
98-
cy.window().then((win) => {
99-
win.__CYPRESS_MODE__ = 'run'
100-
cy.get('body').then(($el) => {
101-
$el.find('[data-cy="sidebar"]')?.remove()
102-
})
103-
})
104-
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import RelevantRunsDataSource_RunsByCommitShas from '../fixtures/gql-RelevantRunsDataSource_RunsByCommitShas.json'
2+
3+
Cypress.on('window:before:load', (win) => {
4+
win.__CYPRESS_GQL_NO_SOCKET__ = 'true'
5+
})
6+
7+
// These mocks all the responses so we can get deterministic
8+
// results to test the debug page.
9+
// The JSON fixtures were generated by using a real app and capturing
10+
// the responses.
11+
describe('App - Debug Page', () => {
12+
beforeEach(() => {
13+
cy.scaffoldProject('cypress-in-cypress')
14+
cy.openProject('cypress-in-cypress')
15+
cy.startAppServer('component')
16+
17+
cy.loginUser()
18+
cy.withCtx((ctx) => {
19+
ctx.git?.__setGitHashesForTesting(['commit1', 'commit2'])
20+
})
21+
22+
cy.remoteGraphQLIntercept((obj, _testState, options) => {
23+
if (obj.operationName === 'RelevantRunsDataSource_RunsByCommitShas') {
24+
obj.result.data = options.RelevantRunsDataSource_RunsByCommitShas.data
25+
}
26+
27+
return obj.result
28+
}, { RelevantRunsDataSource_RunsByCommitShas })
29+
})
30+
31+
it('all tests passed', () => {
32+
// This mocks all the responses so we can get deterministic
33+
// results to test the debug page.
34+
cy.intercept('POST', '/__cypress/graphql/query-Debug', {
35+
fixture: 'debug-Passing/gql-Debug.json',
36+
})
37+
38+
cy.intercept('POST', '/__cypress/graphql/query-CloudViewerAndProject_RequiredData', {
39+
fixture: 'debug-Passing/gql-CloudViewerAndProject_RequiredData.json',
40+
})
41+
42+
cy.intercept('POST', '/__cypress/graphql/query-MainAppQuery', {
43+
fixture: 'debug-Passing/gql-MainAppQuery.json',
44+
})
45+
46+
cy.intercept('POST', '/__cypress/graphql/query-SideBarNavigationContainer', {
47+
fixture: 'debug-Passing/gql-SideBarNavigationContainer',
48+
})
49+
50+
cy.intercept('POST', '/__cypress/graphql/query-HeaderBar_HeaderBarQuery', {
51+
fixture: 'debug-Passing/gql-HeaderBar_HeaderBarQuery',
52+
})
53+
54+
cy.intercept('POST', '/__cypress/graphql/query-SpecsPageContainer', {
55+
fixture: 'debug-Passing/gql-SpecsPageContainer',
56+
})
57+
58+
cy.visitApp()
59+
60+
cy.findByTestId('sidebar-link-debug-page').click()
61+
cy.findByTestId('debug-container').should('be.visible')
62+
63+
cy.findByTestId('header-top').contains('update projectId')
64+
cy.findByTestId('debug-header-dashboard-link')
65+
.contains('View in Cypress Cloud')
66+
.should('have.attr', 'href', 'https://cloud.cypress.io/projects/7p5uce/runs/2')
67+
68+
cy.findByTestId('debug-runNumber-PASSED').contains('#2')
69+
cy.findByTestId('debug-commitsAhead').contains('You are 1 commit ahead')
70+
71+
cy.findByTestId('metadata').within(() => {
72+
cy.get('[title="passed"]').contains('2')
73+
cy.get('[title="failed"]').contains('0')
74+
cy.get('[title="skipped"]').contains('0')
75+
cy.get('[title="pending"]').contains('2')
76+
cy.findByTestId('debug-header-branch').contains('main')
77+
cy.findByTestId('debug-header-commitHash').contains('e9d176f')
78+
cy.findByTestId('debug-header-author').contains('Lachlan Miller')
79+
cy.findByTestId('debug-header-createdAt').contains('01:18')
80+
})
81+
82+
cy.findByTestId('debug-passed').contains('Well Done!')
83+
cy.findByTestId('debug-passed').contains('All your tests passed.')
84+
cy.findByLabelText('Relevant run passed').should('be.visible').contains('0')
85+
cy.findByTestId('run-failures').should('not.exist')
86+
})
87+
88+
it('shows information about a failed spec', () => {
89+
cy.intercept('POST', '/__cypress/graphql/query-Debug', {
90+
fixture: 'debug-Failing/gql-Debug.json',
91+
})
92+
93+
cy.intercept('POST', '/__cypress/graphql/query-CloudViewerAndProject_RequiredData', {
94+
fixture: 'debug-Failing/gql-CloudViewerAndProject_RequiredData.json',
95+
})
96+
97+
cy.intercept('POST', '/__cypress/graphql/query-MainAppQuery', {
98+
fixture: 'debug-Failing/gql-MainAppQuery.json',
99+
})
100+
101+
cy.intercept('POST', '/__cypress/graphql/query-SideBarNavigationContainer', {
102+
fixture: 'debug-Failing/gql-SideBarNavigationContainer',
103+
})
104+
105+
cy.intercept('POST', '/__cypress/graphql/query-HeaderBar_HeaderBarQuery', {
106+
fixture: 'debug-Failing/gql-HeaderBar_HeaderBarQuery',
107+
})
108+
109+
cy.intercept('POST', '/__cypress/graphql/query-SpecsPageContainer', {
110+
fixture: 'debug-Failing/gql-SpecsPageContainer',
111+
})
112+
113+
cy.visitApp()
114+
115+
cy.findByTestId('sidebar-link-debug-page').click()
116+
cy.findByTestId('debug-container').should('be.visible')
117+
118+
cy.findByTestId('header-top').contains('chore: testing cypress')
119+
cy.findByTestId('debug-header-dashboard-link')
120+
.contains('View in Cypress Cloud')
121+
.should('have.attr', 'href', 'https://cloud.cypress.io/projects/vgqrwp/runs/136')
122+
123+
cy.findByLabelText('Relevant run had 1 test failure').should('be.visible').contains('1')
124+
125+
cy.findByTestId('debug-runNumber-FAILED').contains('#136')
126+
cy.findByTestId('debug-commitsAhead').contains('You are 1 commit ahead')
127+
128+
cy.findByTestId('metadata').within(() => {
129+
cy.get('[title="passed"]').contains('1')
130+
cy.get('[title="failed"]').contains('1')
131+
cy.get('[title="skipped"]').contains('0')
132+
cy.get('[title="pending"]').contains('0')
133+
cy.findByTestId('debug-header-branch').contains('main')
134+
cy.findByTestId('debug-header-commitHash').contains('commit1')
135+
cy.findByTestId('debug-header-author').contains('Lachlan Miller')
136+
cy.findByTestId('debug-header-createdAt').contains('00:19')
137+
})
138+
139+
cy.findByTestId('spec-contents').within(() => {
140+
cy.contains('src/components/InfoPanel/InfoPanel.cy.ts')
141+
cy.findByTestId('metaData-Results-spec-duration').contains('00:04')
142+
cy.findByTestId('metaData-Results-operating-system').contains('Linux Ubuntu')
143+
cy.findByTestId('metaData-Results-browser').contains('Electron 106')
144+
cy.findByTestId('metaData-Results-testing-type').contains('Component')
145+
})
146+
147+
cy.findByTestId('test-row').contains('InfoPanel')
148+
cy.findByTestId('test-row').contains('renders')
149+
cy.findByTestId('run-failures').should('exist').should('have.attr', 'href', '#/specs/runner?file=src/components/InfoPanel/InfoPanel.cy.ts&mode=debug')
150+
})
151+
})
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
describe('cloud debug test filtering', () => {
2+
beforeEach(() => {
3+
cy.scaffoldProject('cloud-debug-filter')
4+
cy.openProject('cloud-debug-filter')
5+
cy.startAppServer('e2e')
6+
})
7+
8+
it('works with nested suites', () => {
9+
cy.visitApp(`specs/runner?file=cypress/e2e/test.cy.js`)
10+
11+
cy.waitForSpecToFinish()
12+
13+
cy.withCtx((ctx) => {
14+
ctx.coreData.cloud.testsForRunResults = {
15+
'cypress/e2e/test.cy.js': ['t2'],
16+
}
17+
})
18+
19+
cy.visitApp(`specs/runner?file=cypress/e2e/test.cy.js&mode=debug`)
20+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1 })
21+
22+
cy.get('.runnable-title').contains('t2')
23+
24+
cy.get('.debug-dismiss').contains('1 / 4 tests').click()
25+
cy.waitForSpecToFinish({ passCount: 2, failCount: 2 })
26+
27+
cy.withCtx((ctx) => {
28+
ctx.coreData.cloud.testsForRunResults = {
29+
'cypress/e2e/test.cy.js': ['s1 t4'],
30+
}
31+
})
32+
33+
cy.visitApp(`specs/runner?file=cypress/e2e/test.cy.js&mode=debug`)
34+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1 })
35+
36+
cy.get('.runnable-title').contains('t4')
37+
})
38+
39+
it('wraps filter UI with large number of tests', () => {
40+
cy.visitApp(`specs/runner?file=cypress/e2e/lots-of-tests.cy.js`)
41+
42+
cy.get('[data-cy="reporter-panel"]').as('reporterPanel')
43+
44+
cy.waitForSpecToFinish()
45+
46+
cy.withCtx((ctx) => {
47+
ctx.coreData.cloud.testsForRunResults = {
48+
'cypress/e2e/lots-of-tests.cy.js': ['test1'],
49+
}
50+
})
51+
52+
cy.visitApp(`specs/runner?file=cypress/e2e/lots-of-tests.cy.js&mode=debug`)
53+
cy.waitForSpecToFinish({ passCount: 50 })
54+
55+
cy.get('@reporterPanel').then((el) => el.width(500))
56+
cy.get('@reporterPanel').percySnapshot('wide')
57+
58+
cy.get('@reporterPanel').then((el) => el.width(350))
59+
cy.get('@reporterPanel').percySnapshot('medium')
60+
61+
cy.get('@reporterPanel').then((el) => el.width(250))
62+
cy.get('@reporterPanel').percySnapshot('narrow')
63+
64+
cy.get('@reporterPanel').then((el) => el.width(150))
65+
cy.get('@reporterPanel').percySnapshot('skinny')
66+
})
67+
68+
it('works with skips and onlys', () => {
69+
cy.visitApp(`specs/runner?file=cypress/e2e/skip-and-only.cy.js`)
70+
71+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1 })
72+
73+
// .only is respected
74+
cy.withCtx((ctx) => {
75+
ctx.coreData.cloud.testsForRunResults = {
76+
'cypress/e2e/skip-and-only.cy.js': ['t1', 't3'],
77+
}
78+
})
79+
80+
cy.visitApp(`specs/runner?file=cypress/e2e/skip-and-only.cy.js&mode=debug`)
81+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1 })
82+
83+
cy.get('.runnable-title').contains('t1')
84+
85+
cy.get('.debug-dismiss').click().waitForSpecToFinish()
86+
87+
// .only is ignored as it is not in set of filtered tests
88+
cy.withCtx((ctx) => {
89+
ctx.coreData.cloud.testsForRunResults = {
90+
'cypress/e2e/skip-and-only.cy.js': ['t3'],
91+
}
92+
})
93+
94+
cy.visitApp(`specs/runner?file=cypress/e2e/skip-and-only.cy.js&mode=debug`)
95+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1 })
96+
97+
cy.get('.runnable-title').contains('t3')
98+
99+
cy.get('.debug-dismiss').click().waitForSpecToFinish()
100+
101+
// .skip is respected
102+
cy.withCtx((ctx) => {
103+
ctx.coreData.cloud.testsForRunResults = {
104+
'cypress/e2e/skip-and-only.cy.js': ['t2', 't3'],
105+
}
106+
})
107+
108+
cy.visitApp(`specs/runner?file=cypress/e2e/skip-and-only.cy.js&mode=debug`)
109+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1, pendingCount: 1 })
110+
cy.get('.runnable-title').first().contains('t2')
111+
cy.get('.runnable-title').last().contains('t3')
112+
113+
cy.get('.debug-dismiss').contains('2 / 4 tests').click().waitForSpecToFinish()
114+
115+
// suite.only is respected
116+
cy.withCtx((ctx) => {
117+
ctx.coreData.cloud.testsForRunResults = {
118+
'cypress/e2e/skip-and-only.cy.js': ['t3', 's1 t4'],
119+
}
120+
})
121+
122+
cy.visitApp(`specs/runner?file=cypress/e2e/skip-and-only.cy.js&mode=debug`)
123+
cy.waitForSpecToFinish({ passCount: 0, failCount: 1 })
124+
cy.get('.runnable-title').contains('t4')
125+
})
126+
127+
it('works with browser filter', () => {
128+
cy.withCtx((ctx) => {
129+
ctx.coreData.cloud.testsForRunResults = {
130+
'cypress/e2e/lots-of-tests.cy.j': ['t1', 's1 t2'],
131+
}
132+
})
133+
134+
cy.visitApp(`specs/runner?file=cypress/e2e/browsers.cy.js&mode=debug`)
135+
136+
cy.get('.runnable-title').eq(0).contains('t1 (skipped due to browser)')
137+
cy.get('.runnable-title').eq(1).contains('s1 (skipped due to browser)')
138+
cy.get('.runnable-title').eq(2).contains('t2')
139+
})
140+
141+
it('filter is maintained across cross-domain reinitialization', () => {
142+
cy.visitApp(`specs/runner?file=cypress/e2e/domain-change.cy.js`)
143+
144+
cy.get('[data-cy="reporter-panel"]').as('reporterPanel')
145+
146+
cy.waitForSpecToFinish()
147+
148+
cy.withCtx((ctx) => {
149+
ctx.coreData.cloud.testsForRunResults = {
150+
'cypress/e2e/lots-of-tests.cy.j': ['t2', 't3'],
151+
}
152+
})
153+
154+
cy.visitApp(`specs/runner?file=cypress/e2e/domain-change.cy.js&mode=debug`)
155+
cy.waitForSpecToFinish({ failCount: 2 })
156+
})
157+
})

0 commit comments

Comments
 (0)