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: openInIDE for failed debug spec #25691

Merged
merged 7 commits into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 8 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
## 12.6.0

_Released 02/14/2023 (PENDING)_

**Features:**

- Added the "Open in IDE" feature for failed tests reported from the Debug page. Addressed in [#25691](/~https://github.com/cypress-io/cypress/pull/25691).

## 12.5.1

_Released 02/10/2023_
Expand Down
46 changes: 34 additions & 12 deletions packages/app/cypress/e2e/debug.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { OpenFileInIdeQuery } from '../../src/generated/graphql-test'
import RelevantRunsDataSource_RunsByCommitShas from '../fixtures/gql-RelevantRunsDataSource_RunsByCommitShas.json'

Cypress.on('window:before:load', (win) => {
Expand Down Expand Up @@ -31,27 +32,27 @@ describe('App - Debug Page', () => {
it('all tests passed', () => {
// This mocks all the responses so we can get deterministic
// results to test the debug page.
cy.intercept('POST', '/__cypress/graphql/query-Debug', {
cy.intercept('query-Debug', {
fixture: 'debug-Passing/gql-Debug.json',
})

cy.intercept('POST', '/__cypress/graphql/query-CloudViewerAndProject_RequiredData', {
cy.intercept('query-CloudViewerAndProject_RequiredData', {
fixture: 'debug-Passing/gql-CloudViewerAndProject_RequiredData.json',
})

cy.intercept('POST', '/__cypress/graphql/query-MainAppQuery', {
cy.intercept('query-MainAppQuery', {
fixture: 'debug-Passing/gql-MainAppQuery.json',
})

cy.intercept('POST', '/__cypress/graphql/query-SideBarNavigationContainer', {
cy.intercept('query-SideBarNavigationContainer', {
fixture: 'debug-Passing/gql-SideBarNavigationContainer',
})

cy.intercept('POST', '/__cypress/graphql/query-HeaderBar_HeaderBarQuery', {
cy.intercept('query-HeaderBar_HeaderBarQuery', {
fixture: 'debug-Passing/gql-HeaderBar_HeaderBarQuery',
})

cy.intercept('POST', '/__cypress/graphql/query-SpecsPageContainer', {
cy.intercept('query-SpecsPageContainer', {
fixture: 'debug-Passing/gql-SpecsPageContainer',
})

Expand Down Expand Up @@ -86,30 +87,44 @@ describe('App - Debug Page', () => {
})

it('shows information about a failed spec', () => {
cy.intercept('POST', '/__cypress/graphql/query-Debug', {
cy.intercept('query-Debug', {
fixture: 'debug-Failing/gql-Debug.json',
})

cy.intercept('POST', '/__cypress/graphql/query-CloudViewerAndProject_RequiredData', {
cy.intercept('query-CloudViewerAndProject_RequiredData', {
fixture: 'debug-Failing/gql-CloudViewerAndProject_RequiredData.json',
})

cy.intercept('POST', '/__cypress/graphql/query-MainAppQuery', {
cy.intercept('query-MainAppQuery', {
fixture: 'debug-Failing/gql-MainAppQuery.json',
})

cy.intercept('POST', '/__cypress/graphql/query-SideBarNavigationContainer', {
cy.intercept('query-SideBarNavigationContainer', {
fixture: 'debug-Failing/gql-SideBarNavigationContainer',
})

cy.intercept('POST', '/__cypress/graphql/query-HeaderBar_HeaderBarQuery', {
cy.intercept('query-HeaderBar_HeaderBarQuery', {
fixture: 'debug-Failing/gql-HeaderBar_HeaderBarQuery',
})

cy.intercept('POST', '/__cypress/graphql/query-SpecsPageContainer', {
cy.intercept('query-SpecsPageContainer', {
fixture: 'debug-Failing/gql-SpecsPageContainer',
})

cy.intercept('query-OpenFileInIDE', (req) => {
req.on('response', (res) => {
const gqlData = res.body.data as OpenFileInIdeQuery

gqlData.localSettings.preferences.preferredEditorBinary = 'code'
})
})

cy.intercept('mutation-OpenFileInIDE_Mutation').as('openFileInIDE')

cy.withCtx((ctx, { sinon }) => {
sinon.stub(ctx.actions.file, 'openFile')
})

cy.visitApp()

cy.findByTestId('sidebar-link-debug-page').click()
Expand Down Expand Up @@ -147,5 +162,12 @@ describe('App - Debug Page', () => {
cy.findByTestId('test-row').contains('InfoPanel')
cy.findByTestId('test-row').contains('renders')
cy.findByTestId('run-failures').should('exist').should('have.attr', 'href', '#/specs/runner?file=src/components/InfoPanel/InfoPanel.cy.ts&mode=debug')

cy.findByTestId('open-in-ide').click().then(() => {
ZachJW34 marked this conversation as resolved.
Show resolved Hide resolved
cy.wait('@openFileInIDE')
cy.withCtx((ctx) => {
expect(ctx.actions.file.openFile).to.have.been.calledWith('src/components/InfoPanel/InfoPanel.cy.ts', 1, 1)
})
})
})
})
49 changes: 49 additions & 0 deletions packages/app/src/debug/DebugSpec.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,52 @@ describe('Run Failures button', () => {
.and('not.have.attr', 'aria-disabled')
})
})

describe('Open in IDE', () => {
const spec = {
id: '8879798756s88d',
path: 'cypress/tests/',
fileName: 'auth',
fileExtension: '.spec.ts',
fullPath: 'cypress/tests/auth.spec.ts',
testsPassed: resultCounts(22, 22),
testsFailed: resultCounts(2, 2),
testsPending: resultCounts(1, 1),
specDuration: {
min: 143000,
max: 143000,
},
}

const renderDebugSpec = ({ foundLocally } = { foundLocally: true }) => cy.mount(() =>
<div class="px-24px">
<DebugSpec spec={spec}
testResults={testResultSingleGroup}
groups={singleGroup}
testingType={'e2e'}
foundLocally={foundLocally}
matchesCurrentTestingType={true}
/>
</div>)

it('shows openInIDE if file is found locally', () => {
renderDebugSpec()

cy.findByTestId('open-in-ide').as('openInIDE').realHover()
cy.findByTestId('open-in-ide-tooltip').should('be.visible').and('contain', defaultMessages.debugPage.openFile.openInIDE)
cy.percySnapshot()

cy.get('@openInIDE').click()

cy.findByLabelText('External editor preferences').should('be.visible')
cy.findByLabelText('Close').click()
})

it('shows disabled openInIDE if file is not found locally', () => {
renderDebugSpec({ foundLocally: false })

cy.findByTestId('open-in-ide-disabled').as('openInIDE').realHover()
cy.findByTestId('open-in-ide-disabled-tooltip').should('be.visible').and('contain', defaultMessages.debugPage.openFile.notFoundLocally)
cy.percySnapshot()
})
})
66 changes: 60 additions & 6 deletions packages/app/src/debug/DebugSpec.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,64 @@
class="flex w-full grid px-18px gap-y-8px items-center"
>
<div class="flex-grow flex w-full gap-x-2 truncate items-center">
<IconDocumentText
stroke-color="gray-500"
fill-color="gray-100"
size="16"
/>
<Tooltip
v-if="foundLocally"
placement="bottom"
color="dark"
data-cy="open-in-ide"
>
ZachJW34 marked this conversation as resolved.
Show resolved Hide resolved
<OpenFileInIDE
v-slot="{onClick}"
:file-path="specData.fullPath"
>
Comment on lines +25 to +28
Copy link
Contributor

Choose a reason for hiding this comment

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

When the user opens the IDE and then returns to the app, the tooltip reshows itself. Can this be closed on click or I saw there is an auto-hide prop for the tooltip component we are using.

Screen.Recording.2023-02-03.at.10.15.51.AM.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would say this is expected behavior. The tooltip shows on hover/focus, when you click back into the app the browser restores focus to the button, causing the tooltip to appear. You could probably workaround it, but I don't think the workaround would be worth the investment

<button
class="rounded-md border-1px border-gray-100 p-4px group hocus:border-indigo-200"
@click="onClick"
>
ZachJW34 marked this conversation as resolved.
Show resolved Hide resolved
<IconDocumentText
stroke-color="gray-500"
fill-color="gray-100"
hocus-stroke-color="indigo-400"
hocus-fill-color="indigo-200"
size="16"
interactive-colors-on-group
/>
</button>
</OpenFileInIDE>
<template
#popper
>
<div
class="text-center text-sm max-w-240px"
data-cy="open-in-ide-tooltip"
>
{{ t('debugPage.openFile.openInIDE') }}
</div>
</template>
</Tooltip>
<Tooltip
v-else
class="rounded-md border-1px border-gray-100 p-4px"
placement="bottom"
color="dark"
data-cy="open-in-ide-disabled"
>
ZachJW34 marked this conversation as resolved.
Show resolved Hide resolved
<IconDocumentMinus
stroke-color="gray-500"
fill-color="gray-100"
size="16"
/>
<template
#popper
>
<div
class="text-center text-sm max-w-240px"
data-cy="open-in-ide-disabled-tooltip"
>
{{ t('debugPage.openFile.notFoundLocally') }}
</div>
</template>
</Tooltip>
<div
data-cy="spec-path"
class="flex-grow text-base non-italic truncate"
Expand Down Expand Up @@ -142,7 +195,7 @@
<script lang="ts" setup>

import { computed, unref } from 'vue'
import { IconActionRefresh, IconDocumentText } from '@cypress-design/vue-icon'
import { IconActionRefresh, IconDocumentText, IconDocumentMinus } from '@cypress-design/vue-icon'
import type { SpecDataAggregate, CloudRunInstance } from '@packages/data-context/src/gen/graphcache-config.gen'
import DebugFailedTest from './DebugFailedTest.vue'
import StatsMetaData from './StatsMetadata.vue'
Expand All @@ -154,6 +207,7 @@ import { useI18n } from '@cy/i18n'
import { useDurationFormat } from '../composables/useDurationFormat'
import { posixify } from '../paths'
import type { StatsMetadata_GroupsFragment, TestingTypeEnum } from '../generated/graphql'
import OpenFileInIDE from '@cy/gql-components/OpenFileInIDE.vue'

export interface Spec {
id: string
Expand Down
4 changes: 4 additions & 0 deletions packages/frontend-shared/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,10 @@
}
},
"debugPage": {
"openFile": {
"openInIDE": "Open in IDE",
"notFoundLocally": "Opening in IDE is disabled because the spec is not found in this project"
},
"limit": {
"title": "Cypress renders up to 100 failed test results",
"message": "This run has {n} failed tests | This run has {n} failed test | This run has {n} failed tests",
Expand Down