-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* adding debug page * Fixing sidebar e2e tests * Adding more content to the Debug page and header updates * Starting to wire up child components * created util function for debug specs mapping and wrote tests * update to debug page graphql extension parsing and tests for utility function * Fix header test * Type fixes * Fix test * Setting hash to same as feature branch * New test for DebugContainer * Test Ids needed for test * Updates to fix type linting * Update to cloud schema and types * Fixing tests * Minor test fix * Updates from review comments * Make use of existing computed value Co-authored-by: Zachary Williams <ZachJW34@gmail.com> * Improve test * Adding descriptions to cloud fields * Encapsulate duration format in composable * Making changes to align with latest cloud update Co-authored-by: Ankit <ankit@cypress.io> Co-authored-by: Zachary Williams <ZachJW34@gmail.com>
- Loading branch information
1 parent
c89cc92
commit ee859f6
Showing
24 changed files
with
1,389 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { ref } from 'vue' | ||
import { useDurationFormat } from './useDurationFormat' | ||
|
||
describe('useDurationFormat', () => { | ||
it('should format duration', () => { | ||
expect(useDurationFormat(1000).value).to.eq('00:01') | ||
expect(useDurationFormat(60000).value).to.eq('01:00') | ||
expect(useDurationFormat(6000000).value).to.eq('01:40:00') | ||
|
||
// expects 24 hours and greater to "roll over" and not include day information | ||
expect(useDurationFormat(86400000).value).to.eq('00:00') | ||
}) | ||
|
||
it('should render with value', () => { | ||
const duration = 1000 | ||
const formatted = useDurationFormat(duration) | ||
|
||
cy.mount(() => (<div> | ||
{formatted.value} | ||
</div>)) | ||
|
||
cy.contains('00:01') | ||
}) | ||
|
||
it('should render with ref and update if ref changes', () => { | ||
const duration = ref(1000) | ||
const formatted = useDurationFormat(duration) | ||
|
||
cy.mount(() => (<div> | ||
{formatted.value} | ||
</div>)) | ||
|
||
cy.contains('00:01').then(() => { | ||
duration.value = 2000 | ||
}) | ||
|
||
cy.contains('00:02') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { computed, Ref, unref } from 'vue' | ||
import { dayjs } from '../runs/utils/day.js' | ||
|
||
/* | ||
Format duration to in HH:mm:ss format. The `totalDuration` field is milliseconds. Remove the leading "00:" if the value is less | ||
than an hour. Currently, there is no expectation that a run duration will be greater 24 hours or greater, so it is okay that | ||
this format would "roll-over" in that scenario. | ||
Ex: 1 second which is 1000ms = 00:01 | ||
Ex: 1 hour and 1 second which is 3601000ms = 01:00:01 | ||
*/ | ||
export function useDurationFormat (value: number | Ref<number>) { | ||
return computed(() => dayjs.duration(unref(value)).format('HH:mm:ss').replace(/^0+:/, '')) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import { DebugSpecsFragmentDoc } from '../generated/graphql-test' | ||
import DebugContainer from './DebugContainer.vue' | ||
import { defaultMessages } from '@cy/i18n' | ||
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store' | ||
import { specsList } from './utils/DebugMapping' | ||
import { CloudRunStubs } from '@packages/graphql/test/stubCloudTypes' | ||
|
||
describe('<DebugContainer />', () => { | ||
context('empty states', () => { | ||
const validateEmptyState = (expectedMessage: string) => { | ||
cy.mountFragment(DebugSpecsFragmentDoc, { | ||
render: (gqlVal) => { | ||
return ( | ||
<DebugContainer | ||
gql={gqlVal} | ||
/> | ||
) | ||
}, | ||
}) | ||
|
||
cy.findByTestId('debug-empty').contains(expectedMessage) | ||
} | ||
|
||
it('shows not logged in', () => { | ||
validateEmptyState(defaultMessages.debugPage.notLoggedIn) | ||
}) | ||
|
||
it('is logged in', () => { | ||
const loginConnectStore = useLoginConnectStore() | ||
|
||
loginConnectStore.setUserFlag('isLoggedIn', true) | ||
|
||
validateEmptyState(defaultMessages.debugPage.notConnected) | ||
}) | ||
|
||
it('has no runs', () => { | ||
const loginConnectStore = useLoginConnectStore() | ||
|
||
loginConnectStore.setUserFlag('isLoggedIn', true) | ||
loginConnectStore.setProjectFlag('isProjectConnected', true) | ||
cy.mountFragment(DebugSpecsFragmentDoc, { | ||
render: (gqlVal) => { | ||
return ( | ||
<DebugContainer | ||
gql={gqlVal} | ||
/> | ||
) | ||
}, | ||
}) | ||
|
||
cy.findByTestId('debug-empty').contains(defaultMessages.debugPage.noRuns) | ||
}) | ||
}) | ||
|
||
describe('render specs and tests', () => { | ||
it('renders data when logged in and connected', () => { | ||
const loginConnectStore = useLoginConnectStore() | ||
|
||
loginConnectStore.setUserFlag('isLoggedIn', true) | ||
loginConnectStore.setProjectFlag('isProjectConnected', true) | ||
cy.mountFragment(DebugSpecsFragmentDoc, { | ||
onResult: (result) => { | ||
if (result.currentProject?.cloudProject?.__typename === 'CloudProject') { | ||
const test = result.currentProject.cloudProject.runByNumber | ||
const other = CloudRunStubs.failingWithTests as typeof test | ||
|
||
result.currentProject.cloudProject.runByNumber = other | ||
} | ||
}, | ||
render: (gqlVal) => { | ||
return ( | ||
<DebugContainer | ||
gql={gqlVal} | ||
/> | ||
) | ||
}, | ||
}) | ||
|
||
// Only asserting that it is rendering the components for failed specs | ||
cy.findByTestId('debug-header').should('be.visible') | ||
cy.findByTestId('debug-spec-item').should('be.visible') | ||
}) | ||
}) | ||
|
||
describe('testing util function: debugMapping', () => { | ||
const createSpecs = (idArr: string[]) => { | ||
const acc: {id: string}[] = [] | ||
|
||
idArr.forEach((val) => { | ||
acc.push({ id: val }) | ||
}) | ||
|
||
return acc | ||
} | ||
|
||
it('maps correctly for a single spec', () => { | ||
const spec = createSpecs(['a1c']) | ||
const tests = [ | ||
{ specId: 'a1c', id: 'random1' }, | ||
{ specId: 'a1c', id: 'random2' }, | ||
] | ||
|
||
const debugMappingArray = specsList(spec, tests) | ||
|
||
expect(debugMappingArray).to.have.length(1) | ||
expect(debugMappingArray[0]).to.deep.equal({ spec: { id: 'a1c' }, tests: [{ specId: 'a1c', id: 'random1' }, { specId: 'a1c', id: 'random2' }] }) | ||
}) | ||
|
||
it('maps correctly for multiple specs and test', () => { | ||
const specs = createSpecs(['123', '456', '789']) | ||
const tests = [ | ||
{ specId: '123', id: 'random1' }, | ||
{ specId: '456', id: 'random2' }, | ||
{ specId: '456', id: 'random3' }, | ||
{ specId: '789', id: 'random4' }, | ||
{ specId: '123', id: 'random6' }, | ||
] | ||
|
||
const debugMappingArray = specsList(specs, tests) | ||
|
||
const expected = [ | ||
{ spec: { id: '123' }, tests: [{ specId: '123', id: 'random1' }, { specId: '123', id: 'random6' }] }, | ||
{ spec: { id: '456' }, tests: [{ specId: '456', id: 'random2' }, { specId: '456', id: 'random3' }] }, | ||
{ spec: { id: '789' }, tests: [{ specId: '789', id: 'random4' }] }, | ||
] | ||
|
||
expect(debugMappingArray).to.deep.equal(expected) | ||
}) | ||
|
||
it('maps does not show specs that do not have tests', () => { | ||
const specs = createSpecs(['123', '456', '789']) | ||
const tests = [{ specId: '123', id: 'random1' }] | ||
|
||
const debugMappingArray = specsList(specs, tests) | ||
|
||
expect(debugMappingArray).to.have.length(1) | ||
expect(debugMappingArray).to.deep.equal([{ spec: { id: '123' }, tests: [{ specId: '123', id: 'random1' }] }]) | ||
}) | ||
|
||
it('throws an error when a test does not map to a spec', () => { | ||
const specs = createSpecs(['123']) | ||
const tests = [ | ||
{ specId: '123', id: 'random1' }, | ||
{ specId: '456', id: 'random2' }, | ||
] | ||
|
||
const specsListWrapper = () => { | ||
return specsList(specs, tests) | ||
} | ||
|
||
expect(specsListWrapper).to.throw('Could not find spec for id 456') | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<template> | ||
<div> | ||
<div | ||
v-if="loginConnectStore.user.isLoggedIn && loginConnectStore.project.isProjectConnected && run" | ||
> | ||
<DebugPageHeader | ||
:gql="run" | ||
:commits-ahead="0" | ||
/> | ||
<DebugSpecList | ||
:specs="debugSpecsArray" | ||
/> | ||
</div> | ||
<div | ||
v-else | ||
data-cy="debug-empty" | ||
> | ||
<div | ||
v-if="!loginConnectStore.user.isLoggedIn" | ||
> | ||
{{ t('debugPage.notLoggedIn') }} | ||
</div> | ||
<div | ||
v-else-if="!loginConnectStore.project.isProjectConnected" | ||
> | ||
{{ t('debugPage.notConnected' ) }} | ||
</div> | ||
<div | ||
v-else-if="!run" | ||
> | ||
{{ t('debugPage.noRuns') }} | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { gql } from '@urql/vue' | ||
import { computed } from '@vue/reactivity' | ||
import type { DebugSpecsFragment } from '../generated/graphql' | ||
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store' | ||
import DebugPageHeader from './DebugPageHeader.vue' | ||
import DebugSpecList from './DebugSpecList.vue' | ||
import { useI18n } from 'vue-i18n' | ||
import { specsList } from './utils/DebugMapping' | ||
const { t } = useI18n() | ||
gql` | ||
fragment DebugSpecs on Query { | ||
currentProject { | ||
id | ||
cloudProject { | ||
__typename | ||
... on CloudProject { | ||
id | ||
runByNumber(runNumber: 2) { | ||
...DebugPage | ||
id | ||
runNumber | ||
status | ||
overLimitActionType | ||
overLimitActionUrl | ||
testsForReview { | ||
id | ||
...DebugSpecListTests | ||
} | ||
specs { | ||
id | ||
...DebugSpecListSpec | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
` | ||
const props = defineProps<{ | ||
gql: DebugSpecsFragment | ||
}>() | ||
const loginConnectStore = useLoginConnectStore() | ||
const run = computed(() => { | ||
return props.gql.currentProject?.cloudProject?.__typename === 'CloudProject' ? props.gql.currentProject.cloudProject.runByNumber : null | ||
}) | ||
const debugSpecsArray = computed(() => { | ||
if (run.value) { | ||
const specs = run.value.specs || [] | ||
const tests = run.value.testsForReview || [] | ||
return specsList(specs, tests) | ||
} | ||
return [] | ||
}) | ||
</script> |
Oops, something went wrong.