Skip to content

Commit 873e67d

Browse files
authored
Merge branch '10.0-release' into UNIFY-1346-utm-params
2 parents da9a3a8 + 383bdb1 commit 873e67d

Some content is hidden

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

60 files changed

+1834
-465
lines changed

graphql-codegen.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ generates:
5757
nonOptionalTypename: true
5858
- 'packages/frontend-shared/script/codegen-type-map.js'
5959

60-
'./packages/frontend-shared/cypress/support/generated/test-cloud-graphql-types.gen.ts':
60+
'./packages/graphql/src/gen/test-cloud-graphql-types.gen.ts':
6161
schema: 'packages/graphql/schemas/cloud.graphql'
6262
plugins:
6363
- add:

guides/e2e-open-testing.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,8 @@ When we hit the remote GraphQL server, we mock against the same mocked schema we
4747
cy.remoteGraphQLIntercept(async (obj) => {
4848
// Currently, all remote requests go through here, we want to use this to modify the
4949
// remote request before it's used and avoid touching the login query
50-
if (obj.result.data?.cloudProjectsBySlugs) {
51-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
52-
if (proj.runs?.nodes) {
53-
proj.runs.nodes = []
54-
}
55-
}
50+
if (obj.result.data?.cloudProjectBySlug.runs?.nodes) {
51+
obj.result.data.cloudProjectBySlug.runs.nodes = []
5652
}
5753

5854
return obj.result

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@
8787
"@graphql-codegen/typescript": "2.4.2",
8888
"@graphql-codegen/typescript-operations": "2.2.3",
8989
"@graphql-codegen/typescript-urql-graphcache": "2.2.3",
90-
"@graphql-tools/batch-delegate": "8.1.0",
9190
"@graphql-tools/delegate": "8.2.1",
9291
"@graphql-tools/utils": "8.2.3",
9392
"@graphql-tools/wrap": "8.1.1",

packages/app/cypress/e2e/runs.cy.ts

Lines changed: 145 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -219,18 +219,18 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
219219
cy.remoteGraphQLIntercept(async (obj) => {
220220
// Currently, all remote requests go through here, we want to use this to modify the
221221
// remote request before it's used and avoid touching the login query
222+
if (obj.result.data?.cloudProjectBySlug && obj.variables._v0_slug === 'abcdef42') {
223+
const proj = obj.result.data.cloudProjectBySlug
222224

223-
if (obj.result.data?.cloudProjectsBySlugs && obj.variables._v0_slugs.includes('abcdef42')) {
224-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
225-
proj.__typename = 'CloudProjectNotFound'
226-
proj.message = 'Cloud Project Not Found'
227-
}
225+
proj.__typename = 'CloudProjectNotFound'
226+
proj.message = 'Cloud Project Not Found'
228227
}
229228

230229
if (obj.result.data?.cloudViewer?.organizations?.nodes) {
231230
const projectNodes = obj.result.data?.cloudViewer.organizations.nodes[0].projects.nodes
232231

233232
projectNodes.push({
233+
__typename: 'CloudProject',
234234
id: '1',
235235
slug: 'ghijkl',
236236
name: 'Mock Project',
@@ -270,12 +270,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
270270

271271
it('if project Id is specified in config file that is not accessible, shows call to action', () => {
272272
cy.remoteGraphQLIntercept(async (obj) => {
273-
if (obj.result.data?.cloudProjectsBySlugs) {
274-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
275-
proj.__typename = 'CloudProjectUnauthorized'
276-
proj.message = 'Cloud Project Unauthorized'
277-
proj.hasRequestedAccess = false
278-
}
273+
if (obj.result.data?.cloudProjectBySlug) {
274+
const proj = obj.result.data.cloudProjectBySlug
275+
276+
proj.__typename = 'CloudProjectUnauthorized'
277+
proj.message = 'Cloud Project Unauthorized'
278+
proj.hasRequestedAccess = false
279279
}
280280

281281
return obj.result
@@ -299,12 +299,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
299299
return obj.result
300300
}
301301

302-
if (obj.result.data?.cloudProjectsBySlugs) {
303-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
304-
proj.__typename = 'CloudProjectUnauthorized'
305-
proj.message = 'Cloud Project Unauthorized'
306-
proj.hasRequestedAccess = false
307-
}
302+
if (obj.result.data?.cloudProjectBySlug) {
303+
const proj = obj.result.data.cloudProjectBySlug
304+
305+
proj.__typename = 'CloudProjectUnauthorized'
306+
proj.message = 'Cloud Project Unauthorized'
307+
proj.hasRequestedAccess = false
308308
}
309309

310310
return obj.result
@@ -321,13 +321,13 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
321321

322322
it('updates the button text when the request access button is clicked', () => {
323323
cy.remoteGraphQLIntercept(async (obj, testState) => {
324-
if (obj.operationName === 'Runs_currentProject_cloudProject_batched') {
325-
for (const proj of obj!.result!.data!.cloudProjectsBySlugs) {
326-
proj.__typename = 'CloudProjectUnauthorized'
327-
proj.message = 'Cloud Project Unauthorized'
328-
proj.hasRequestedAccess = false
329-
testState.project = proj
330-
}
324+
if (obj.operationName === 'Runs_currentProject_cloudProject_cloudProjectBySlug') {
325+
const proj = obj!.result!.data!.cloudProjectBySlug
326+
327+
proj.__typename = 'CloudProjectUnauthorized'
328+
proj.message = 'Cloud Project Unauthorized'
329+
proj.hasRequestedAccess = false
330+
testState.project = proj
331331
} else if (obj.operationName === 'RunsErrorRenderer_RequestAccess_cloudProjectRequestAccess') {
332332
obj!.result!.data!.cloudProjectRequestAccess = {
333333
...testState.project,
@@ -355,12 +355,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
355355
// Currently, all remote requests go through here, we want to use this to modify the
356356
// remote request before it's used and avoid touching the login query
357357

358-
if (obj.result.data?.cloudProjectsBySlugs) {
359-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
360-
proj.__typename = 'CloudProjectUnauthorized'
361-
proj.message = 'Cloud Project Unauthorized'
362-
proj.hasRequestedAccess = true
363-
}
358+
if (obj.result.data?.cloudProjectBySlug) {
359+
const proj = obj.result.data.cloudProjectBySlug
360+
361+
proj.__typename = 'CloudProjectUnauthorized'
362+
proj.message = 'Cloud Project Unauthorized'
363+
proj.hasRequestedAccess = true
364364
}
365365

366366
return obj.result
@@ -386,12 +386,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
386386
cy.remoteGraphQLIntercept(async (obj) => {
387387
// Currently, all remote requests go through here, we want to use this to modify the
388388
// remote request before it's used and avoid touching the login query
389-
if (obj.result.data?.cloudProjectsBySlugs) {
390-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
391-
if (proj.runs?.nodes) {
392-
proj.runs.nodes = []
393-
}
394-
}
389+
if (obj.result.data?.cloudProjectBySlug?.runs?.nodes) {
390+
obj.result.data.cloudProjectBySlug.runs.nodes = []
395391
}
396392

397393
return obj.result
@@ -409,12 +405,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
409405

410406
cy.loginUser()
411407
cy.remoteGraphQLIntercept(async (obj) => {
412-
if (obj.result.data?.cloudProjectsBySlugs) {
413-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
414-
if (proj.runs?.nodes) {
415-
proj.runs.nodes = []
416-
}
417-
}
408+
if (obj.result.data?.cloudProjectBySlug?.runs?.nodes) {
409+
obj.result.data.cloudProjectBySlug.runs.nodes = []
418410
}
419411

420412
return obj.result
@@ -438,12 +430,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
438430

439431
cy.loginUser()
440432
cy.remoteGraphQLIntercept(async (obj) => {
441-
if (obj.result.data?.cloudProjectsBySlugs) {
442-
for (const proj of obj.result.data.cloudProjectsBySlugs) {
443-
if (proj.runs?.nodes) {
444-
proj.runs.nodes = []
445-
}
446-
}
433+
if (obj.result.data?.cloudProjectBySlug?.runs?.nodes) {
434+
obj.result.data.cloudProjectBySlug.runs.nodes = []
447435
}
448436

449437
return obj.result
@@ -480,17 +468,17 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
480468

481469
cy.get('[href="http://dummy.cypress.io/runs/0"]').first().within(() => {
482470
cy.findByText('fix: make gql work CANCELLED')
483-
cy.get('[data-cy="run-card-icon"]')
471+
cy.get('[data-cy="run-card-icon-CANCELLED"]')
484472
})
485473

486474
cy.get('[href="http://dummy.cypress.io/runs/1"]').first().within(() => {
487475
cy.findByText('fix: make gql work ERRORED')
488-
cy.get('[data-cy="run-card-icon"]')
476+
cy.get('[data-cy="run-card-icon-ERRORED"]')
489477
})
490478

491479
cy.get('[href="http://dummy.cypress.io/runs/2"]').first().within(() => {
492480
cy.findByText('fix: make gql work FAILED')
493-
cy.get('[data-cy="run-card-icon"]')
481+
cy.get('[data-cy="run-card-icon-FAILED"]')
494482
})
495483

496484
cy.get('[href="http://dummy.cypress.io/runs/0"]').first().as('firstRun')
@@ -565,4 +553,110 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
565553
cy.get('[data-cy=warning-alert]').should('not.exist')
566554
})
567555
})
556+
557+
describe('refetching', () => {
558+
let obj: {toCall?: Function} = {}
559+
const RUNNING_COUNT = 3
560+
561+
beforeEach(() => {
562+
cy.scaffoldProject('component-tests')
563+
cy.openProject('component-tests')
564+
cy.startAppServer('component')
565+
cy.loginUser()
566+
cy.remoteGraphQLIntercept((obj, testState) => {
567+
if (obj.result.data?.cloudProjectBySlug?.runs?.nodes.length) {
568+
obj.result.data.cloudProjectBySlug.runs.nodes.map((run) => {
569+
run.status = 'RUNNING'
570+
})
571+
572+
obj.result.data.cloudProjectBySlug.runs.nodes = obj.result.data.cloudProjectBySlug.runs.nodes.slice(0, 3)
573+
}
574+
575+
return obj.result
576+
})
577+
578+
cy.visitApp('/runs', {
579+
onBeforeLoad (win) {
580+
const setTimeout = win.setTimeout
581+
582+
// @ts-expect-error
583+
win.setTimeout = function (fn, time) {
584+
if (fn.name === 'fetchNewerRuns') {
585+
obj.toCall = fn
586+
} else {
587+
setTimeout(fn, time)
588+
}
589+
}
590+
},
591+
})
592+
})
593+
594+
it('should re-query for executing runs', () => {
595+
cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', RUNNING_COUNT).should('be.visible')
596+
597+
cy.remoteGraphQLIntercept(async (obj) => {
598+
await new Promise((resolve) => setTimeout(resolve, 100))
599+
600+
if (obj.result.data?.cloudNode?.newerRuns?.nodes) {
601+
obj.result.data.cloudNode.newerRuns.nodes = []
602+
}
603+
604+
if (obj.result.data?.cloudNodesByIds) {
605+
obj.result.data?.cloudNodesByIds.map((node) => {
606+
node.status = 'RUNNING'
607+
})
608+
609+
obj.result.data.cloudNodesByIds[0].status = 'PASSED'
610+
}
611+
612+
return obj.result
613+
})
614+
615+
function completeNext (passed) {
616+
cy.wrap(obj).invoke('toCall').then(() => {
617+
cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', passed).should('be.visible')
618+
if (passed < RUNNING_COUNT) {
619+
completeNext(passed + 1)
620+
}
621+
})
622+
}
623+
624+
completeNext(1)
625+
})
626+
627+
it('should fetch newer runs and maintain them when navigating', () => {
628+
cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', RUNNING_COUNT).should('be.visible')
629+
630+
cy.remoteGraphQLIntercept(async (obj) => {
631+
await new Promise((resolve) => setTimeout(resolve, 100))
632+
633+
if (obj.result.data?.cloudNodesByIds) {
634+
obj.result.data?.cloudNodesByIds.map((node) => {
635+
node.status = 'PASSED'
636+
node.totalPassed = 100
637+
})
638+
}
639+
640+
return obj.result
641+
})
642+
643+
cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 3).should('be.visible')
644+
cy.wrap(obj).invoke('toCall')
645+
646+
cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible').within(() => {
647+
cy.get('[data-cy="runResults-passed-count"]').should('contain', 100)
648+
})
649+
650+
cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 2).should('be.visible')
651+
652+
// If we navigate away & back, we should see the same runs
653+
cy.get('[href="#/settings"]').click()
654+
cy.remoteGraphQLIntercept((obj) => obj.result)
655+
656+
cy.get('[href="#/runs"]').click()
657+
658+
cy.get('[data-cy="run-card-icon-PASSED"]').should('have.length', 3).should('be.visible')
659+
cy.get('[data-cy="run-card-icon-RUNNING"]').should('have.length', 2).should('be.visible')
660+
})
661+
})
568662
})

packages/app/cypress/e2e/subscriptions/createCloudOrgModal-subscription.cy.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
1717
cy.loginUser()
1818
cy.visitApp()
1919

20+
// Simulate no orgs
2021
cy.remoteGraphQLIntercept(async (obj) => {
21-
if ((obj.operationName === 'CheckCloudOrganizations_cloudViewerChange_cloudViewer' || obj.operationName === 'Runs_cloudViewer') && obj.callCount < 2) {
22+
if ((obj.operationName === 'CheckCloudOrganizations_cloudViewerChange_cloudViewer' || obj.operationName === 'Runs_cloudViewer')) {
2223
if (obj.result.data?.cloudViewer?.organizations?.nodes) {
2324
obj.result.data.cloudViewer.organizations.nodes = []
2425
}
@@ -41,6 +42,11 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
4142
cy.contains('button', defaultMessages.runs.connect.modal.createOrg.waitingButton).should('be.visible')
4243
cy.contains('a', defaultMessages.links.needHelp).should('have.attr', 'href', 'https://on.cypress.io/adding-new-project')
4344

45+
// Clear the current intercept to simulate a response with orgs
46+
cy.remoteGraphQLIntercept((obj) => {
47+
return obj.result
48+
})
49+
4450
cy.withCtx(async (ctx) => {
4551
await ctx.util.fetch(`http://127.0.0.1:${ctx.gqlServerPort}/cloud-notification?operationName=orgCreated`)
4652
})

packages/app/cypress/e2e/top-nav.cy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,8 @@ describe('App Top Nav Workflows', () => {
367367
cy.startAppServer('component')
368368

369369
cy.remoteGraphQLIntercept((obj) => {
370-
if (obj.result.data?.cloudProjectsBySlugs) {
371-
throw new Error('Unauthorized')
370+
if (obj.result.data?.cloudProjectBySlug) {
371+
return new obj.Response('Unauthorized', { status: 401 })
372372
}
373373

374374
return obj.result

packages/app/src/pages/Runs.vue

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@
55
<RunsContainer
66
v-else
77
:gql="query.data.value"
8-
@reexecute-runs-query="reexecuteRunsQuery"
8+
:online="isOnlineRef"
99
/>
1010
</TransitionQuickFade>
1111
</div>
1212
</template>
1313

1414
<script lang="ts" setup>
15+
import { ref, watchEffect } from 'vue'
1516
import { gql, useQuery } from '@urql/vue'
1617
import { RunsDocument } from '../generated/graphql'
1718
import RunsSkeleton from '../runs/RunsSkeleton.vue'
1819
import RunsContainer from '../runs/RunsContainer.vue'
1920
import TransitionQuickFade from '@cy/components/transitions/TransitionQuickFade.vue'
21+
import { useOnline } from '@vueuse/core'
2022
2123
gql`
2224
query Runs {
@@ -25,7 +27,19 @@ query Runs {
2527
2628
const query = useQuery({ query: RunsDocument, requestPolicy: 'network-only' })
2729
28-
function reexecuteRunsQuery () {
29-
query.executeQuery()
30-
}
30+
const isOnlineRef = ref(true)
31+
const online = useOnline()
32+
33+
watchEffect(() => {
34+
// We want to keep track of the previous state to refetch the query
35+
// when the internet connection is back
36+
if (!online.value && isOnlineRef.value) {
37+
isOnlineRef.value = false
38+
}
39+
40+
if (online.value && !isOnlineRef.value) {
41+
isOnlineRef.value = true
42+
query.executeQuery()
43+
}
44+
})
3145
</script>

packages/app/src/runs/CloudConnectButton.cy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import CloudConnectButton from './CloudConnectButton.vue'
22
import { CloudConnectButtonFragmentDoc } from '../generated/graphql-test'
3-
import { CloudUserStubs } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-CloudTypes'
3+
import { CloudUserStubs } from '@packages/graphql/test/stubCloudTypes'
44

55
describe('<CloudConnectButton />', () => {
66
it('show user connect if not connected', () => {

0 commit comments

Comments
 (0)