diff --git a/graphql-codegen.yml b/graphql-codegen.yml
index c70f4e72a2..5bc8361b3e 100644
--- a/graphql-codegen.yml
+++ b/graphql-codegen.yml
@@ -57,7 +57,7 @@ generates:
nonOptionalTypename: true
- 'packages/frontend-shared/script/codegen-type-map.js'
- './packages/frontend-shared/cypress/support/generated/test-cloud-graphql-types.gen.ts':
+ './packages/graphql/src/gen/test-cloud-graphql-types.gen.ts':
schema: 'packages/graphql/schemas/cloud.graphql'
plugins:
- add:
diff --git a/guides/e2e-open-testing.md b/guides/e2e-open-testing.md
index e68c9b7278..ff2e7e3643 100644
--- a/guides/e2e-open-testing.md
+++ b/guides/e2e-open-testing.md
@@ -47,12 +47,8 @@ When we hit the remote GraphQL server, we mock against the same mocked schema we
cy.remoteGraphQLIntercept(async (obj) => {
// Currently, all remote requests go through here, we want to use this to modify the
// remote request before it's used and avoid touching the login query
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- if (proj.runs?.nodes) {
- proj.runs.nodes = []
- }
- }
+ if (obj.result.data?.cloudProjectBySlug.runs?.nodes) {
+ obj.result.data.cloudProjectBySlug.runs.nodes = []
}
return obj.result
diff --git a/package.json b/package.json
index d63ffccfd5..c9954e45eb 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,6 @@
"@graphql-codegen/typescript": "2.4.2",
"@graphql-codegen/typescript-operations": "2.2.3",
"@graphql-codegen/typescript-urql-graphcache": "2.2.3",
- "@graphql-tools/batch-delegate": "8.1.0",
"@graphql-tools/delegate": "8.2.1",
"@graphql-tools/utils": "8.2.3",
"@graphql-tools/wrap": "8.1.1",
diff --git a/packages/app/cypress/e2e/runs.cy.ts b/packages/app/cypress/e2e/runs.cy.ts
index fb450748f1..0dda1323a4 100644
--- a/packages/app/cypress/e2e/runs.cy.ts
+++ b/packages/app/cypress/e2e/runs.cy.ts
@@ -219,18 +219,18 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.remoteGraphQLIntercept(async (obj) => {
// Currently, all remote requests go through here, we want to use this to modify the
// remote request before it's used and avoid touching the login query
+ if (obj.result.data?.cloudProjectBySlug && obj.variables._v0_slug === 'abcdef42') {
+ const proj = obj.result.data.cloudProjectBySlug
- if (obj.result.data?.cloudProjectsBySlugs && obj.variables._v0_slugs.includes('abcdef42')) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- proj.__typename = 'CloudProjectNotFound'
- proj.message = 'Cloud Project Not Found'
- }
+ proj.__typename = 'CloudProjectNotFound'
+ proj.message = 'Cloud Project Not Found'
}
if (obj.result.data?.cloudViewer?.organizations?.nodes) {
const projectNodes = obj.result.data?.cloudViewer.organizations.nodes[0].projects.nodes
projectNodes.push({
+ __typename: 'CloudProject',
id: '1',
slug: 'ghijkl',
name: 'Mock Project',
@@ -270,12 +270,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
it('if project Id is specified in config file that is not accessible, shows call to action', () => {
cy.remoteGraphQLIntercept(async (obj) => {
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- proj.__typename = 'CloudProjectUnauthorized'
- proj.message = 'Cloud Project Unauthorized'
- proj.hasRequestedAccess = false
- }
+ if (obj.result.data?.cloudProjectBySlug) {
+ const proj = obj.result.data.cloudProjectBySlug
+
+ proj.__typename = 'CloudProjectUnauthorized'
+ proj.message = 'Cloud Project Unauthorized'
+ proj.hasRequestedAccess = false
}
return obj.result
@@ -299,12 +299,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
return obj.result
}
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- proj.__typename = 'CloudProjectUnauthorized'
- proj.message = 'Cloud Project Unauthorized'
- proj.hasRequestedAccess = false
- }
+ if (obj.result.data?.cloudProjectBySlug) {
+ const proj = obj.result.data.cloudProjectBySlug
+
+ proj.__typename = 'CloudProjectUnauthorized'
+ proj.message = 'Cloud Project Unauthorized'
+ proj.hasRequestedAccess = false
}
return obj.result
@@ -321,13 +321,13 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
it('updates the button text when the request access button is clicked', () => {
cy.remoteGraphQLIntercept(async (obj, testState) => {
- if (obj.operationName === 'Runs_currentProject_cloudProject_batched') {
- for (const proj of obj!.result!.data!.cloudProjectsBySlugs) {
- proj.__typename = 'CloudProjectUnauthorized'
- proj.message = 'Cloud Project Unauthorized'
- proj.hasRequestedAccess = false
- testState.project = proj
- }
+ if (obj.operationName === 'Runs_currentProject_cloudProject_cloudProjectBySlug') {
+ const proj = obj!.result!.data!.cloudProjectBySlug
+
+ proj.__typename = 'CloudProjectUnauthorized'
+ proj.message = 'Cloud Project Unauthorized'
+ proj.hasRequestedAccess = false
+ testState.project = proj
} else if (obj.operationName === 'RunsErrorRenderer_RequestAccess_cloudProjectRequestAccess') {
obj!.result!.data!.cloudProjectRequestAccess = {
...testState.project,
@@ -355,12 +355,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
// Currently, all remote requests go through here, we want to use this to modify the
// remote request before it's used and avoid touching the login query
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- proj.__typename = 'CloudProjectUnauthorized'
- proj.message = 'Cloud Project Unauthorized'
- proj.hasRequestedAccess = true
- }
+ if (obj.result.data?.cloudProjectBySlug) {
+ const proj = obj.result.data.cloudProjectBySlug
+
+ proj.__typename = 'CloudProjectUnauthorized'
+ proj.message = 'Cloud Project Unauthorized'
+ proj.hasRequestedAccess = true
}
return obj.result
@@ -386,12 +386,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.remoteGraphQLIntercept(async (obj) => {
// Currently, all remote requests go through here, we want to use this to modify the
// remote request before it's used and avoid touching the login query
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- if (proj.runs?.nodes) {
- proj.runs.nodes = []
- }
- }
+ if (obj.result.data?.cloudProjectBySlug?.runs?.nodes) {
+ obj.result.data.cloudProjectBySlug.runs.nodes = []
}
return obj.result
@@ -409,12 +405,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.loginUser()
cy.remoteGraphQLIntercept(async (obj) => {
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- if (proj.runs?.nodes) {
- proj.runs.nodes = []
- }
- }
+ if (obj.result.data?.cloudProjectBySlug?.runs?.nodes) {
+ obj.result.data.cloudProjectBySlug.runs.nodes = []
}
return obj.result
@@ -438,12 +430,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.loginUser()
cy.remoteGraphQLIntercept(async (obj) => {
- if (obj.result.data?.cloudProjectsBySlugs) {
- for (const proj of obj.result.data.cloudProjectsBySlugs) {
- if (proj.runs?.nodes) {
- proj.runs.nodes = []
- }
- }
+ if (obj.result.data?.cloudProjectBySlug?.runs?.nodes) {
+ obj.result.data.cloudProjectBySlug.runs.nodes = []
}
return obj.result
@@ -480,17 +468,17 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.get('[href="http://dummy.cypress.io/runs/0"]').first().within(() => {
cy.findByText('fix: make gql work CANCELLED')
- cy.get('[data-cy="run-card-icon"]')
+ cy.get('[data-cy="run-card-icon-CANCELLED"]')
})
cy.get('[href="http://dummy.cypress.io/runs/1"]').first().within(() => {
cy.findByText('fix: make gql work ERRORED')
- cy.get('[data-cy="run-card-icon"]')
+ cy.get('[data-cy="run-card-icon-ERRORED"]')
})
cy.get('[href="http://dummy.cypress.io/runs/2"]').first().within(() => {
cy.findByText('fix: make gql work FAILED')
- cy.get('[data-cy="run-card-icon"]')
+ cy.get('[data-cy="run-card-icon-FAILED"]')
})
cy.get('[href="http://dummy.cypress.io/runs/0"]').first().as('firstRun')
@@ -565,4 +553,110 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.get('[data-cy=warning-alert]').should('not.exist')
})
})
+
+ describe('refetching', () => {
+ let obj: {toCall?: Function} = {}
+ const RUNNING_COUNT = 3
+
+ beforeEach(() => {
+ cy.scaffoldProject('component-tests')
+ cy.openProject('component-tests')
+ cy.startAppServer('component')
+ cy.loginUser()
+ cy.remoteGraphQLIntercept((obj, testState) => {
+ if (obj.result.data?.cloudProjectBySlug?.runs?.nodes.length) {
+ obj.result.data.cloudProjectBySlug.runs.nodes.map((run) => {
+ run.status = 'RUNNING'
+ })
+
+ obj.result.data.cloudProjectBySlug.runs.nodes = obj.result.data.cloudProjectBySlug.runs.nodes.slice(0, 3)
+ }
+
+ return obj.result
+ })
+
+ cy.visitApp('/runs', {
+ onBeforeLoad (win) {
+ const setTimeout = win.setTimeout
+
+ // @ts-expect-error
+ win.setTimeout = function (fn, time) {
+ if (fn.name === 'fetchNewerRuns') {
+ obj.toCall = fn
+ } else {
+ setTimeout(fn, time)
+ }
+ }
+ },
+ })
+ })
+
+ it('should re-query for executing runs', () => {
+ cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', RUNNING_COUNT).should('be.visible')
+
+ cy.remoteGraphQLIntercept(async (obj) => {
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ if (obj.result.data?.cloudNode?.newerRuns?.nodes) {
+ obj.result.data.cloudNode.newerRuns.nodes = []
+ }
+
+ if (obj.result.data?.cloudNodesByIds) {
+ obj.result.data?.cloudNodesByIds.map((node) => {
+ node.status = 'RUNNING'
+ })
+
+ obj.result.data.cloudNodesByIds[0].status = 'PASSED'
+ }
+
+ return obj.result
+ })
+
+ function completeNext (passed) {
+ cy.wrap(obj).invoke('toCall').then(() => {
+ cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', passed).should('be.visible')
+ if (passed < RUNNING_COUNT) {
+ completeNext(passed + 1)
+ }
+ })
+ }
+
+ completeNext(1)
+ })
+
+ it('should fetch newer runs and maintain them when navigating', () => {
+ cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', RUNNING_COUNT).should('be.visible')
+
+ cy.remoteGraphQLIntercept(async (obj) => {
+ await new Promise((resolve) => setTimeout(resolve, 100))
+
+ if (obj.result.data?.cloudNodesByIds) {
+ obj.result.data?.cloudNodesByIds.map((node) => {
+ node.status = 'PASSED'
+ node.totalPassed = 100
+ })
+ }
+
+ return obj.result
+ })
+
+ cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 3).should('be.visible')
+ cy.wrap(obj).invoke('toCall')
+
+ cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible').within(() => {
+ cy.get('[data-cy="runResults-passed-count"]').should('contain', 100)
+ })
+
+ cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 2).should('be.visible')
+
+ // If we navigate away & back, we should see the same runs
+ cy.get('[href="#/settings"]').click()
+ cy.remoteGraphQLIntercept((obj) => obj.result)
+
+ cy.get('[href="#/runs"]').click()
+
+ cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible')
+ cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 2).should('be.visible')
+ })
+ })
})
diff --git a/packages/app/cypress/e2e/subscriptions/createCloudOrgModal-subscription.cy.ts b/packages/app/cypress/e2e/subscriptions/createCloudOrgModal-subscription.cy.ts
index f5c3996af3..4765c7bc57 100644
--- a/packages/app/cypress/e2e/subscriptions/createCloudOrgModal-subscription.cy.ts
+++ b/packages/app/cypress/e2e/subscriptions/createCloudOrgModal-subscription.cy.ts
@@ -17,8 +17,9 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.loginUser()
cy.visitApp()
+ // Simulate no orgs
cy.remoteGraphQLIntercept(async (obj) => {
- if ((obj.operationName === 'CheckCloudOrganizations_cloudViewerChange_cloudViewer' || obj.operationName === 'Runs_cloudViewer') && obj.callCount < 2) {
+ if ((obj.operationName === 'CheckCloudOrganizations_cloudViewerChange_cloudViewer' || obj.operationName === 'Runs_cloudViewer')) {
if (obj.result.data?.cloudViewer?.organizations?.nodes) {
obj.result.data.cloudViewer.organizations.nodes = []
}
@@ -41,6 +42,11 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.contains('button', defaultMessages.runs.connect.modal.createOrg.waitingButton).should('be.visible')
cy.contains('a', defaultMessages.links.needHelp).should('have.attr', 'href', 'https://on.cypress.io/adding-new-project')
+ // Clear the current intercept to simulate a response with orgs
+ cy.remoteGraphQLIntercept((obj) => {
+ return obj.result
+ })
+
cy.withCtx(async (ctx) => {
await ctx.util.fetch(`http://127.0.0.1:${ctx.gqlServerPort}/cloud-notification?operationName=orgCreated`)
})
diff --git a/packages/app/cypress/e2e/top-nav.cy.ts b/packages/app/cypress/e2e/top-nav.cy.ts
index 0f05737d0c..e1178f3553 100644
--- a/packages/app/cypress/e2e/top-nav.cy.ts
+++ b/packages/app/cypress/e2e/top-nav.cy.ts
@@ -366,8 +366,8 @@ describe('App Top Nav Workflows', () => {
cy.startAppServer('component')
cy.remoteGraphQLIntercept((obj) => {
- if (obj.result.data?.cloudProjectsBySlugs) {
- throw new Error('Unauthorized')
+ if (obj.result.data?.cloudProjectBySlug) {
+ return new obj.Response('Unauthorized', { status: 401 })
}
return obj.result
diff --git a/packages/app/src/pages/Runs.vue b/packages/app/src/pages/Runs.vue
index 6632500498..a8801d1023 100644
--- a/packages/app/src/pages/Runs.vue
+++ b/packages/app/src/pages/Runs.vue
@@ -5,18 +5,20 @@
diff --git a/packages/app/src/runs/CloudConnectButton.cy.tsx b/packages/app/src/runs/CloudConnectButton.cy.tsx
index 0cadb8d961..7a52d1ae83 100644
--- a/packages/app/src/runs/CloudConnectButton.cy.tsx
+++ b/packages/app/src/runs/CloudConnectButton.cy.tsx
@@ -1,6 +1,6 @@
import CloudConnectButton from './CloudConnectButton.vue'
import { CloudConnectButtonFragmentDoc } from '../generated/graphql-test'
-import { CloudUserStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
+import { CloudUserStubs } from '@packages/graphql/test/stubCloudTypes'
describe('', () => {
it('show user connect if not connected', () => {
diff --git a/packages/app/src/runs/RunCard.cy.tsx b/packages/app/src/runs/RunCard.cy.tsx
index 0c929140b5..b62e0f015f 100644
--- a/packages/app/src/runs/RunCard.cy.tsx
+++ b/packages/app/src/runs/RunCard.cy.tsx
@@ -1,4 +1,4 @@
-import { CloudRunStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
+import { CloudRunStubs } from '@packages/graphql/test/stubCloudTypes'
import { RunCardFragmentDoc } from '../generated/graphql-test'
import RunCard from './RunCard.vue'
diff --git a/packages/app/src/runs/RunCard.vue b/packages/app/src/runs/RunCard.vue
index b2e499ef64..61d29b1131 100644
--- a/packages/app/src/runs/RunCard.vue
+++ b/packages/app/src/runs/RunCard.vue
@@ -8,7 +8,7 @@
>
{{ run.commitInfo?.summary }}
diff --git a/packages/app/src/runs/RunResults.cy.tsx b/packages/app/src/runs/RunResults.cy.tsx
index 52faf82dae..45dda69f87 100644
--- a/packages/app/src/runs/RunResults.cy.tsx
+++ b/packages/app/src/runs/RunResults.cy.tsx
@@ -1,5 +1,5 @@
import { defaultMessages } from '@cy/i18n'
-import { CloudRunStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
+import { CloudRunStubs } from '@packages/graphql/test/stubCloudTypes'
import { RunCardFragmentDoc } from '../generated/graphql-test'
import RunResults from './RunResults.vue'
diff --git a/packages/app/src/runs/RunResults.vue b/packages/app/src/runs/RunResults.vue
index 5bb0829d5e..722c63c326 100644
--- a/packages/app/src/runs/RunResults.vue
+++ b/packages/app/src/runs/RunResults.vue
@@ -5,6 +5,7 @@
:key="i"
class="flex px-2 items-center hover:bg-indigo-50"
:title="result.name"
+ :data-cy="`runResults-${result.name}-count`"
>
diff --git a/packages/app/src/runs/RunsContainer.cy.tsx b/packages/app/src/runs/RunsContainer.cy.tsx
index 3c18c20d4b..21aa63a26a 100644
--- a/packages/app/src/runs/RunsContainer.cy.tsx
+++ b/packages/app/src/runs/RunsContainer.cy.tsx
@@ -1,6 +1,6 @@
import RunsContainer from './RunsContainer.vue'
import { RunsContainerFragmentDoc } from '../generated/graphql-test'
-import { CloudUserStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
+import { CloudUserStubs } from '@packages/graphql/test/stubCloudTypes'
import { defaultMessages } from '@cy/i18n'
@@ -17,7 +17,7 @@ describe('', { keystrokeDelay: 0 }, () => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
- return
+ return
},
})
@@ -39,7 +39,7 @@ describe('', { keystrokeDelay: 0 }, () => {
}
},
render (gqlVal) {
- return
+ return
},
})
@@ -58,7 +58,7 @@ describe('', { keystrokeDelay: 0 }, () => {
it('renders instructions and login button', () => {
cy.mountFragment(RunsContainerFragmentDoc, {
render (gqlVal) {
- return
+ return
},
})
diff --git a/packages/app/src/runs/RunsContainer.vue b/packages/app/src/runs/RunsContainer.vue
index 20a2fd1b8c..6c7d097c26 100644
--- a/packages/app/src/runs/RunsContainer.vue
+++ b/packages/app/src/runs/RunsContainer.vue
@@ -44,26 +44,31 @@