', { viewportHeight: 400 }, () => {
// this is the human readable commit time from the stub
cy.contains('an hour ago').should('be.visible')
+ cy.findByTestId('runCard-avatar').should('not.exist')
+ cy.findByTestId('runCard-branchName').should('not.exist')
})
})
context('run timing', () => {
- it('displays HH:mm:ss format for run duration', () => {
+ it('displays HH[h] mm[m] ss[s] format for run duration', { viewportWidth: 1536 }, () => {
cy.mountFragment(RunCardFragmentDoc, {
onResult (result) {
result.totalDuration = HOUR + MINUTE + SECOND
},
render: (gqlVal) => {
return (
-
+
)
@@ -117,17 +161,17 @@ describe('
', { viewportHeight: 400 }, () => {
})
// this is the human readable commit time from the stub
- cy.contains('01:01:01').should('be.visible')
+ cy.contains('01h 01m 01s').should('be.visible')
})
- it('displays mm:ss format for run duration if duration is less than an hour', () => {
+ it('displays mm[m] ss[s] format for run duration if duration is less than an hour', () => {
cy.mountFragment(RunCardFragmentDoc, {
onResult (result) {
result.totalDuration = MINUTE + SECOND
},
render: (gqlVal) => {
return (
-
+
)
@@ -135,43 +179,89 @@ describe('
', { viewportHeight: 400 }, () => {
})
// this is the human readable commit time from the stub
- cy.contains('01:01').should('be.visible')
+ cy.contains('01m 01s').should('be.visible')
})
})
- context('tags', () => {
- it('renders all tags if >= 2', () => {
+ context('tags', { viewportWidth: 1536 }, () => {
+ it('renders all tags if >= 1 with commitInfo', () => {
cy.mountFragment(RunCardFragmentDoc, {
onResult (result) {
- result.tags = generateTags(2)
+ result.tags = generateTags(1)
},
render: (gqlVal) => {
return (
-
+
)
},
})
- cy.get('[data-cy="run-tag"]').should('have.length', 2).each(($el, i) => cy.wrap($el).contains(`tag${i}`))
+ cy.get('[data-cy="runCard-branchName"]').should('be.visible')
+ cy.get('[data-cy="runTagCount"]').should('not.be.visible')
+ cy.get('[data-cy="runTag"]').should('have.length', 1).each(($el, i) => {
+ cy.wrap($el).contains(`tag${i}`)
+ })
})
- it('truncates tags if > 2', () => {
+ it('truncates tags if > 1 with commitInfo', () => {
cy.mountFragment(RunCardFragmentDoc, {
onResult (result) {
result.tags = generateTags(6)
},
render: (gqlVal) => {
return (
-
+
+
+
+ )
+ },
+ })
+
+ cy.get('[data-cy="runCard-branchName"]').should('be.visible')
+ cy.get('[data-cy="runTagCount"]').should('be.visible').contains('+5')
+ cy.get('[data-cy="runTag"]').should('have.length', 1).each(($el, i) => cy.wrap($el).contains(`tag${i}`))
+ })
+
+ it('renders all tags if >= 1', () => {
+ cy.mountFragment(RunCardFragmentDoc, {
+ onResult (result) {
+ result.tags = generateTags(1)
+
+ result.commitInfo = null
+ },
+ render: (gqlVal) => {
+ return (
+
+
+
+ )
+ },
+ })
+
+ cy.get('[data-cy="runTagCount"]').should('not.be.visible')
+ cy.get('[data-cy="runTag"]').should('have.length', 1).each(($el, i) => cy.wrap($el).contains(`tag${i}`))
+ })
+
+ it('truncates tags if > 1', () => {
+ cy.mountFragment(RunCardFragmentDoc, {
+ onResult (result) {
+ result.tags = generateTags(6)
+
+ result.commitInfo = null
+ },
+ render: (gqlVal) => {
+ return (
+
)
},
})
- cy.get('[data-cy="run-tag"]').should('have.length', 3).last().contains('+4')
+ cy.get('[data-cy="runTagCount"]').should('be.visible').contains('+5')
+ cy.get('[data-cy="runTag"]').should('have.length', 1).each(($el, i) => cy.wrap($el).contains(`tag${i}`))
})
})
})
diff --git a/packages/app/src/runs/RunCard.vue b/packages/app/src/runs/RunCard.vue
index 177f015d8b5c..a40a19a72a88 100644
--- a/packages/app/src/runs/RunCard.vue
+++ b/packages/app/src/runs/RunCard.vue
@@ -1,83 +1,165 @@
-
-
-
-
-
-
- {{ run.commitInfo?.summary }}
- {{ tag }}
-
-
-
-
+
+
-
- Commit Author: {{ run.commitInfo.authorName }}
-
-
-
+
+
+
+
-
- Branch Name: {{ run.commitInfo.branch }}
-
-
+ :label="run.commitInfo?.branch"
+ :title="run.commitInfo?.branch"
+ :icon="IconTechnologyBranchH"
+ :icon-label="t('runs.card.branchName')"
+ class="hidden xl:inline-flex min-w-0"
+ data-cy="runCard-branchName"
+ />
+
+
+
+
+
+
- Run Created At: {{ relativeCreatedAt }}
+
+ {{ t('runs.card.commitAuthor') }}
+
+ {{ run.commitInfo.authorName }}
+
-
- Run Total Duration: {{ totalDuration }}
+
+ {{ t('runs.card.totalDuration') }}
+
+ {{ totalDuration }} ({{ relativeCreatedAt }})
+
-
-
-
-
-
-
+
+
+
+ {{ t('runs.card.debugLabel') }}
+
+
+
+ {{ t('runs.card.noDebugAvailable') }}
+
+
+
+
+
+
+const onDebugClick = (event) => {
+ event.preventDefault()
+ event.stopPropagation()
-
+
+
diff --git a/packages/app/src/runs/RunNumber.cy.tsx b/packages/app/src/runs/RunNumber.cy.tsx
new file mode 100644
index 000000000000..54a4b2d58201
--- /dev/null
+++ b/packages/app/src/runs/RunNumber.cy.tsx
@@ -0,0 +1,34 @@
+import type { CloudRunStatus } from '../generated/graphql-test'
+import RunNumber from './RunNumber.vue'
+
+const STATUSES: CloudRunStatus[] = ['PASSED', 'FAILED', 'CANCELLED', 'RUNNING', 'ERRORED']
+
+describe('
', () => {
+ describe('playground', () => {
+ STATUSES.forEach((status) => {
+ it(`status = '${status}'`, () => {
+ cy.mount(() => (
+
+
+
+ ))
+
+ cy.findByTestId(`runNumber-status-${status}`).should('be.visible').should('not.have.class', 'group-focus-visible:outline')
+ })
+ })
+ })
+
+ describe('with hover', () => {
+ STATUSES.forEach((status) => {
+ it(`status = '${status}'`, () => {
+ cy.mount(() => (
+
+
+
+ ))
+
+ cy.findByTestId(`runNumber-status-${status}`).should('be.visible').should('have.class', 'group-focus-visible:outline')
+ })
+ })
+ })
+})
diff --git a/packages/app/src/runs/RunNumber.vue b/packages/app/src/runs/RunNumber.vue
new file mode 100644
index 000000000000..7705618c03ef
--- /dev/null
+++ b/packages/app/src/runs/RunNumber.vue
@@ -0,0 +1,58 @@
+
+
+
+
+ {{ `#${props.value}` }}
+
+
+
+
+
diff --git a/packages/app/src/runs/RunResults.cy.tsx b/packages/app/src/runs/RunResults.cy.tsx
index 140a9ec5daa2..885ab7fa26fe 100644
--- a/packages/app/src/runs/RunResults.cy.tsx
+++ b/packages/app/src/runs/RunResults.cy.tsx
@@ -1,16 +1,16 @@
+import RunResults from './RunResults.vue'
+import { RunResultsFragmentDoc } from '../generated/graphql-test'
import { defaultMessages } from '@cy/i18n'
import { CloudRunStubs } from '@packages/graphql/test/stubCloudTypes'
-import { RunCardFragmentDoc } from '../generated/graphql-test'
-import RunResults from './RunResults.vue'
-describe('
', { viewportHeight: 150, viewportWidth: 250 }, () => {
- it('shows number of passed, skipped, pending and failed tests', () => {
+describe('
', () => {
+ it('shows the failed icon and the number of passed, skipped, pending, failed tests passed through gql props', () => {
const cloudRuns = Object.values(CloudRunStubs)
cy.mount(() => cloudRuns.map((cloudRun, i) => (
)))
cloudRuns.forEach((cloudRun, i) => {
- cy.get(`[data-cy=run-result-${i}]`).within(() => {
+ cy.findByTestId(`run-result-${i}`).within(() => {
cy.get(`[title=${defaultMessages.runs.results.passed}]`).should('contain.text', cloudRun.totalPassed)
cy.get(`[title=${defaultMessages.runs.results.failed}]`).should('contain.text', cloudRun.totalFailed)
cy.get(`[title=${defaultMessages.runs.results.skipped}]`).should('contain.text', cloudRun.totalSkipped)
@@ -18,17 +18,44 @@ describe('
', { viewportHeight: 150, viewportWidth: 250 }, () => {
})
})
})
+})
- it('renders flaky ribbon', () => {
- cy.mountFragment(RunCardFragmentDoc, {
- onResult (result) {
- result.totalFlakyTests = 4
- },
- render (gql) {
- return
- },
- })
+describe('Flaky badge tests', () => {
+ const mountingFragment = (flakyTests: number, useBreakpoint?: boolean) => {
+ return (
+ cy.mountFragment(RunResultsFragmentDoc, {
+ onResult (result) {
+ if (result) {
+ result.totalFlakyTests = flakyTests
+ }
+ },
+ render: (gqlVal) => {
+ return (
+
+ )
+ },
+ })
+ )
+ }
+
+ it('does not show flaky component when flakyTests are < 1', () => {
+ mountingFragment(0)
+ cy.contains('Flaky').should('not.exist')
+ })
+
+ it('contains flaky badge', () => {
+ mountingFragment(4)
+ cy.findByTestId('runResults-flakyBadge').contains(defaultMessages.specPage.flaky.badgeLabel)
+ cy.findByTestId('total-flaky-tests').contains(4)
+ })
+
+ it('responds to breakpoint with ', { viewportWidth: 1279 }, () => {
+ mountingFragment(4, false)
+ cy.findByTestId('runResults-flakyBadge').contains(defaultMessages.specPage.flaky.badgeLabel).should('be.visible')
+ cy.findByTestId('total-flaky-tests').contains(4)
- cy.contains('4 Flaky')
+ mountingFragment(4, true)
+ cy.findByTestId('runResults-flakyBadge').contains(defaultMessages.specPage.flaky.badgeLabel).should('not.be.visible')
+ cy.findByTestId('total-flaky-tests').contains(4)
})
})
diff --git a/packages/app/src/runs/RunResults.vue b/packages/app/src/runs/RunResults.vue
index 85e91002c1e9..8beb0f5060d2 100644
--- a/packages/app/src/runs/RunResults.vue
+++ b/packages/app/src/runs/RunResults.vue
@@ -1,22 +1,43 @@
-
-
{{ props.gql.totalFlakyTests }} Flaky
+
+
+
+ {{ results.totalFlakyTests }}
+
+
+
+ {{ t('specPage.flaky.badgeLabel') }}
+
+
diff --git a/packages/app/src/runs/RunTag.cy.tsx b/packages/app/src/runs/RunTag.cy.tsx
new file mode 100644
index 000000000000..2db3ed2e8490
--- /dev/null
+++ b/packages/app/src/runs/RunTag.cy.tsx
@@ -0,0 +1,37 @@
+import RunTag from './RunTag.vue'
+
+describe('
', () => {
+ it('should show a normal tag', () => {
+ cy.mount({
+ name: 'RunTag',
+ render () {
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runTag"`).should('be.visible').contains('test-label')
+ })
+
+ it('should show a icon tag', () => {
+ cy.mount({
+ name: 'RunTag',
+ render () {
+ return (
+
z}
+ iconLabel="test-sr-text"
+ />
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runTag"`).should('be.visible').contains('test-label')
+ cy.get(`[data-cy="runTag"`).should('be.visible').contains('test-sr-text')
+ cy.get(`[data-cy="runTag"`).should('be.visible').contains('z')
+ })
+})
diff --git a/packages/app/src/runs/RunTag.vue b/packages/app/src/runs/RunTag.vue
new file mode 100644
index 000000000000..f5884e0a2e56
--- /dev/null
+++ b/packages/app/src/runs/RunTag.vue
@@ -0,0 +1,34 @@
+
+
+
+
+ {{ iconLabel }}
+
+
+ {{ label }}
+
+
+
+
+
diff --git a/packages/app/src/runs/RunTagCount.cy.tsx b/packages/app/src/runs/RunTagCount.cy.tsx
new file mode 100644
index 000000000000..976814ffab49
--- /dev/null
+++ b/packages/app/src/runs/RunTagCount.cy.tsx
@@ -0,0 +1,81 @@
+import RunTagCount from './RunTagCount.vue'
+
+describe(' ', () => {
+ it('should show all information', () => {
+ cy.mount({
+ name: 'RunTagCount',
+ render () {
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runTagCount"`).should('be.visible').contains('5')
+ cy.findAllByLabelText('1 Flaky Branch Name: test-branch tag-one tag-two').should('exist')
+ })
+
+ it('should show tags only', () => {
+ cy.mount({
+ name: 'RunTagCount',
+ render () {
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runTagCount"`).should('be.visible').contains('5')
+ cy.findAllByLabelText('tag-one tag-two').should('exist')
+ })
+
+ it('should show flaky only', () => {
+ cy.mount({
+ name: 'RunTagCount',
+ render () {
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runTagCount"`).should('be.visible').contains('5')
+ cy.findAllByLabelText('1 Flaky').should('exist')
+ })
+
+ it('should show branch only', () => {
+ cy.mount({
+ name: 'RunTagCount',
+ render () {
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runTagCount"`).should('be.visible').contains('5')
+ cy.findAllByLabelText('Branch Name: test-branch').should('exist')
+ })
+})
diff --git a/packages/app/src/runs/RunTagCount.vue b/packages/app/src/runs/RunTagCount.vue
new file mode 100644
index 000000000000..7ac2156ec33c
--- /dev/null
+++ b/packages/app/src/runs/RunTagCount.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+ {{ tooltipData.flaky }}
+
+
+
+ {{ t('specPage.flaky.badgeLabel') }}
+
+
+
+
+
+
+ {{ t('runs.card.branchName') }}
+
+
+
+ {{ tooltipData.branchName }}
+
+
+
+
+
+ Tags
+
+
+
+
+
+
+
+
diff --git a/packages/app/src/runs/RunsComposable.ts b/packages/app/src/runs/RunsComposable.ts
index 74de6a22efbb..533dfea788b2 100644
--- a/packages/app/src/runs/RunsComposable.ts
+++ b/packages/app/src/runs/RunsComposable.ts
@@ -5,4 +5,6 @@ export type RunsComposable = {
runs: Ref
reExecuteRunsQuery: () => void
query: any
+ allRunIds?: Ref
+ currentCommitInfo?: Ref<{ sha: string, message: string } | null | undefined>
}
diff --git a/packages/app/src/runs/RunsContainer.cy.tsx b/packages/app/src/runs/RunsContainer.cy.tsx
index f120d782f49b..d296e3f48624 100644
--- a/packages/app/src/runs/RunsContainer.cy.tsx
+++ b/packages/app/src/runs/RunsContainer.cy.tsx
@@ -16,15 +16,16 @@ describe(' ', { keystrokeDelay: 0 }, () => {
cy.mountFragment(RunsContainerFragmentDoc, {
render (gqlVal) {
const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+ const runIds: string[] = runs?.[0]?.id ? [runs?.[0]?.id] : [] as string[]
- return
+ return
},
})
const statuses = ['CANCELLED', 'ERRORED', 'FAILED', 'NOTESTS', 'OVERLIMIT', 'PASSED', 'RUNNING', 'TIMEDOUT']
cy.wrap(statuses).each((status: string) => {
- cy.contains(`fix: make gql work ${ status}`).should('be.visible')
+ cy.get(`[data-cy="runCard-status-${status}"]`).should('exist')
})
cy.percySnapshot()
diff --git a/packages/app/src/runs/RunsContainer.vue b/packages/app/src/runs/RunsContainer.vue
index 4b0c9a7ec11d..5e4a2972ea36 100644
--- a/packages/app/src/runs/RunsContainer.vue
+++ b/packages/app/src/runs/RunsContainer.vue
@@ -1,5 +1,5 @@
-
+
{{ t('launchpadErrors.noInternet.connectProject') }}
@@ -60,10 +60,12 @@
>
{{ t('runs.empty.ensureGitSetupCorrectly') }}
-
@@ -73,10 +75,10 @@
import { computed, ref, watch } from 'vue'
import { useI18n } from '@cy/i18n'
import NoInternetConnection from '@packages/frontend-shared/src/components/NoInternetConnection.vue'
-import RunCard from './RunCard.vue'
import RunsConnect from './RunsConnect.vue'
import RunsConnectSuccessAlert from './RunsConnectSuccessAlert.vue'
import RunsEmpty from './RunsEmpty.vue'
+import RunsLayout from './RunsLayout.vue'
import Warning from '@packages/frontend-shared/src/warning/Warning.vue'
import RunsErrorRenderer from './RunsErrorRenderer.vue'
import { useUserProjectStatusStore } from '@packages/frontend-shared/src/store/user-project-status-store'
@@ -104,11 +106,28 @@ const props = defineProps<{
gql: RunsContainerFragment | RunsGitTreeQuery
runs?: RunCardFragment[]
online: boolean
+ allRunIds?: string[]
+ currentCommitInfo?: { sha: string, message: string } | null
}>()
const showConnectSuccessAlert = ref(false)
const connectionFailed = computed(() => !props.gql.currentProject?.cloudProject && props.online)
+const latestRunUrl = computed(() => {
+ if (props.gql.currentProject?.cloudProject?.__typename !== 'CloudProject') {
+ return '#'
+ }
+
+ return getUrlWithParams({
+ url: props.gql.currentProject?.cloudProject?.cloudProjectUrl,
+ params: {
+ utm_source: getUtmSource(),
+ utm_medium: RUNS_TAB_MEDIUM,
+ utm_campaign: 'View runs in Cypress Cloud',
+ },
+ })
+})
+
const noRunsForBranchMessage = computed(() => {
const learnMoreLink = getUrlWithParams({
url: 'https://on.cypress.io/git-info',
diff --git a/packages/app/src/runs/RunsLayout.cy.tsx b/packages/app/src/runs/RunsLayout.cy.tsx
new file mode 100644
index 000000000000..fb9102d41d70
--- /dev/null
+++ b/packages/app/src/runs/RunsLayout.cy.tsx
@@ -0,0 +1,171 @@
+import RunsLayout from './RunsLayout.vue'
+import { RunsContainerFragmentDoc } from '../generated/graphql-test'
+
+const statuses = ['CANCELLED', 'ERRORED', 'FAILED', 'NOTESTS', 'OVERLIMIT', 'PASSED', 'RUNNING', 'TIMEDOUT']
+
+describe(' ', () => {
+ context('grouped runs when isUsingGit is true', () => {
+ it('displays commits grouped by sha', () => {
+ const shas: string[] = []
+
+ cy.mountFragment(RunsContainerFragmentDoc, {
+ render (gqlVal) {
+ const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+
+ for (let i = 0; i < statuses.length; i += 1) {
+ const runSha = runs?.[i]?.commitInfo?.sha
+
+ if (runSha) {
+ shas.push(runSha)
+ }
+ }
+
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runsLayout-git"`).should('be.visible')
+ cy.get(`[data-cy="runsLayout-no-git"`).should('not.exist')
+ cy.get(`[data-cy="runsLayout-git"`).children('li').should('have.length', 21).each((item, index) => {
+ if (index === 0) {
+ cy.wrap(item).should('be.visible').contains('a message')
+ } else {
+ cy.wrap(item).should('be.visible').contains(`fix: make gql work ${statuses[(index - 1) % statuses.length]}`).should('be.visible')
+ }
+ })
+ })
+
+ it('hides View Runs button when latestRunUrl not present', () => {
+ cy.mountFragment(RunsContainerFragmentDoc, {
+ render (gqlVal) {
+ const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+
+ return (
+
+ )
+ },
+ })
+
+ cy.get('[data-cy="open-cloud-latest').should('not.exist')
+ })
+
+ it('displays newer commit checked out', () => {
+ cy.mountFragment(RunsContainerFragmentDoc, {
+ render (gqlVal) {
+ const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+
+ return (
+
+ )
+ },
+ })
+
+ cy.get('[data-cy="commit-new-sha"]').should('exist').contains('Checked out')
+ cy.get('[data-cy="open-cloud-latest').should('be.visible').contains('View runs in Cypress Cloud')
+ })
+
+ it('displays first commit checked out', () => {
+ let firstRunSha: string | null | undefined = null
+
+ cy.mountFragment(RunsContainerFragmentDoc, {
+ render (gqlVal) {
+ const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+
+ firstRunSha = runs?.[0].commitInfo?.sha
+ const commitInfo = firstRunSha ? { sha: firstRunSha, message: 'a message' } : undefined
+
+ return (
+
+ )
+ },
+ })
+
+ cy.then(() => {
+ cy.get(`[data-cy="commit-${firstRunSha}"`).should('exist').contains('Checked out')
+ })
+
+ cy.get(`[data-cy="open-cloud-latest"`).should('be.visible').contains('View runs in Cypress Cloud')
+ })
+
+ it('displays debug button enabled when allRunIds populated', () => {
+ cy.mountFragment(RunsContainerFragmentDoc, {
+ render (gqlVal) {
+ const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+
+ const firstRunId = runs?.[0].id
+ const secondRunId = runs?.[1].id
+ const runIds = firstRunId && secondRunId ? [firstRunId, secondRunId] : undefined
+
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="open-cloud-latest"`).should('be.visible').contains('View runs in Cypress Cloud')
+ cy.get(`[data-cy="runsLayout-git"`).children('li').should('have.length', 21).each((item, index) => {
+ if (index === 0) return
+
+ if (index < 3) {
+ cy.wrap(item).should('be.visible').contains('Debug').should('be.enabled')
+ } else {
+ cy.wrap(item).should('be.visible').contains('Debug').should('not.be.enabled')
+ }
+ })
+ })
+ })
+
+ context('block runs when isUsingGit is false', () => {
+ it('displays in block layout', () => {
+ cy.mountFragment(RunsContainerFragmentDoc, {
+ render (gqlVal) {
+ const runs = gqlVal.currentProject?.cloudProject?.__typename === 'CloudProject' ? gqlVal.currentProject.cloudProject.runs?.nodes : undefined
+
+ return (
+
+ )
+ },
+ })
+
+ cy.get(`[data-cy="runsLayout-git"`).should('not.exist')
+ cy.get(`[data-cy="runsLayout-no-git"`).should('be.visible')
+ cy.get(`[data-cy="runsLayout-no-git"`).children('li').should('have.length', 20).each((item, index) => {
+ cy.wrap(item).should('be.visible').find(`[data-cy="runCard-status-${statuses[index % statuses.length]}"]`).should('be.visible')
+ })
+ })
+ })
+})
diff --git a/packages/app/src/runs/RunsLayout.vue b/packages/app/src/runs/RunsLayout.vue
new file mode 100644
index 000000000000..f944d4419690
--- /dev/null
+++ b/packages/app/src/runs/RunsLayout.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+ {{ sha.slice(0, 7) }}
+
+
+
+ {{ groupByCommit[sha].message }}
+
+
+ {{ t('runs.layout.checkedOut') }}
+
+
+
+
+
+
+
+ {{ t('runs.layout.viewCloudRuns') }}
+
+
+
+
+
+
diff --git a/packages/app/src/runs/RunsSkeleton.cy.tsx b/packages/app/src/runs/RunsSkeleton.cy.tsx
index 31df937b90e8..7cd8716cb698 100644
--- a/packages/app/src/runs/RunsSkeleton.cy.tsx
+++ b/packages/app/src/runs/RunsSkeleton.cy.tsx
@@ -1,7 +1,15 @@
import RunsSkeleton from './RunsSkeleton.vue'
describe(' ', () => {
- it('playground', () => {
+ it('displays git structure', () => {
+ cy.mount( )
+
+ cy.get(`[data-cy="runsSkeleton-git"`).should('be.visible')
+ })
+
+ it('displays default structure', () => {
cy.mount( )
+
+ cy.get(`[data-cy="runsSkeleton-default"`).should('be.visible')
})
})
diff --git a/packages/app/src/runs/RunsSkeleton.vue b/packages/app/src/runs/RunsSkeleton.vue
index d95de7065cd7..33bd4b5c6702 100644
--- a/packages/app/src/runs/RunsSkeleton.vue
+++ b/packages/app/src/runs/RunsSkeleton.vue
@@ -1,43 +1,67 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ •
+
+
+
+
+
+
+
diff --git a/packages/app/src/runs/RunsSkeletonRow.cy.tsx b/packages/app/src/runs/RunsSkeletonRow.cy.tsx
new file mode 100644
index 000000000000..8d4fa2998b51
--- /dev/null
+++ b/packages/app/src/runs/RunsSkeletonRow.cy.tsx
@@ -0,0 +1,7 @@
+import RunsSkeletonRow from './RunsSkeletonRow.vue'
+
+describe('
', () => {
+ it('playground', () => {
+ cy.mount(
)
+ })
+})
diff --git a/packages/app/src/runs/RunsSkeletonRow.vue b/packages/app/src/runs/RunsSkeletonRow.vue
new file mode 100644
index 000000000000..ec72b6f5807c
--- /dev/null
+++ b/packages/app/src/runs/RunsSkeletonRow.vue
@@ -0,0 +1,39 @@
+
+
+
diff --git a/packages/app/src/runs/useGitTreeRuns.ts b/packages/app/src/runs/useGitTreeRuns.ts
index 5871798a03c9..5a4eb6ff919f 100644
--- a/packages/app/src/runs/useGitTreeRuns.ts
+++ b/packages/app/src/runs/useGitTreeRuns.ts
@@ -21,6 +21,7 @@ fragment RunsGitTreeProject on Query {
__typename
... on CloudProject {
id
+ cloudProjectUrl
}
}
}
@@ -52,6 +53,14 @@ export const useGitTreeRuns = (online: Ref
): RunsComposable => {
return nodes
})
+ const allRunIds = computed(() => {
+ return relevantRuns?.value.all?.map((run) => run.runId) || []
+ })
+
+ const currentCommitInfo = computed(() => {
+ return relevantRuns?.value.currentCommitInfo
+ })
+
function reExecuteRunsQuery () {
query.executeQuery()
}
@@ -60,5 +69,7 @@ export const useGitTreeRuns = (online: Ref): RunsComposable => {
runs,
reExecuteRunsQuery,
query,
+ allRunIds,
+ currentCommitInfo,
}
}
diff --git a/packages/app/src/runs/useProjectRuns.ts b/packages/app/src/runs/useProjectRuns.ts
index 49da4a413d1c..6ecefab19984 100644
--- a/packages/app/src/runs/useProjectRuns.ts
+++ b/packages/app/src/runs/useProjectRuns.ts
@@ -31,6 +31,7 @@ fragment RunsContainer on Query {
__typename
... on CloudProject {
id
+ cloudProjectUrl
runs(first: 10) {
...RunsContainer_RunsConnection
}
diff --git a/packages/data-context/src/sources/RelevantRunsDataSource.ts b/packages/data-context/src/sources/RelevantRunsDataSource.ts
index 284369d0309a..0d378bbd117d 100644
--- a/packages/data-context/src/sources/RelevantRunsDataSource.ts
+++ b/packages/data-context/src/sources/RelevantRunsDataSource.ts
@@ -218,7 +218,7 @@ export class RelevantRunsDataSource {
}
#takeLatestRuns (runs: RelevantRunInfo[]) {
- const latestRuns = take(runs, 10)
+ const latestRuns = take(runs, 100)
debug('latest runs after take', latestRuns)
diff --git a/packages/frontend-shared/src/components/ResultCounts.vue b/packages/frontend-shared/src/components/ResultCounts.vue
index 4779af03272c..d94e4c42aae4 100644
--- a/packages/frontend-shared/src/components/ResultCounts.vue
+++ b/packages/frontend-shared/src/components/ResultCounts.vue
@@ -11,6 +11,7 @@
:is="result.icon"
class="mt-px h-[12px] mr-1 w-[12px]"
:class="result.class"
+ aria-hidden="true"
/>
{
await ctx.actions.project.debugCloudRun(args.runNumber)
- return {}
+ return true
},
})
},
diff --git a/yarn.lock b/yarn.lock
index 38a98fab6fca..33f62e2a3034 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2276,7 +2276,14 @@
resolve-pkg "^2.0.0"
tailwindcss "^3.3.3"
-"@cypress-design/icon-registry@*", "@cypress-design/icon-registry@^0.27.0":
+"@cypress-design/icon-registry@*", "@cypress-design/icon-registry@^0.28.0":
+ version "0.28.0"
+ resolved "https://registry.yarnpkg.com/@cypress-design/icon-registry/-/icon-registry-0.28.0.tgz#a3c5336f7b544d8be82b6a941b8915ba7084d5c9"
+ integrity sha512-xJvE1u3KBQz6Hc0Ea3ia9xUDKxTj5MdKrgYrlE9t321qKxStxVN34VB595TfWzluHZzUb6Qu7QqgqdCTFTccgw==
+ dependencies:
+ "@cypress-design/css" "^0.15.1"
+
+"@cypress-design/icon-registry@^0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@cypress-design/icon-registry/-/icon-registry-0.27.0.tgz#3feedb6bad82c7a461a348f72e62225fe912c49b"
integrity sha512-2tiH0YklKLYQ59pduni9aAsCu5uMKf/ZVHFjoP5xZW8em3FP5NZtmIAZzdIWLXjqihz/Q4TcOAL77qi8T11UJQ==
@@ -2297,6 +2304,13 @@
dependencies:
"@cypress-design/icon-registry" "^0.27.0"
+"@cypress-design/vue-icon@^0.26.0":
+ version "0.26.0"
+ resolved "https://registry.yarnpkg.com/@cypress-design/vue-icon/-/vue-icon-0.26.0.tgz#f56bee36514dc4f9b9606a75f69201e312ff9c70"
+ integrity sha512-ZiMpIvjNWX/x6OJDyhb9VrXXlwPQTgSx87PA4VMVC9JVARXja4UZ950KVTZVEdDuCG8MGYu3N4/hWOrNxCKXCQ==
+ dependencies:
+ "@cypress-design/icon-registry" "^0.28.0"
+
"@cypress-design/vue-statusicon@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@cypress-design/vue-statusicon/-/vue-statusicon-0.5.0.tgz#a183214a323528be86608229cba1ba99011b80ee"