Skip to content

Commit c670ae6

Browse files
feat(app): show previous versions (#18838)
* add gql endpoint and format * types * update schema and endpoint * unused code * lint * types * improve tests * move static strings to i18n Co-authored-by: Jessica Sachs <jess@jessicasachs.io>
1 parent c66a890 commit c670ae6

File tree

15 files changed

+360
-55
lines changed

15 files changed

+360
-55
lines changed

packages/data-context/src/DataContext.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import type { Server } from 'http'
2929
import type { AddressInfo } from 'net'
3030
import EventEmitter from 'events'
3131
import type { App as ElectronApp } from 'electron'
32+
import { VersionsDataSource } from './sources/VersionsDataSource'
3233

3334
const IS_DEV_ENV = process.env.CYPRESS_INTERNAL_ENV !== 'production'
3435

@@ -166,6 +167,10 @@ export class DataContext {
166167
return new GitDataSource(this)
167168
}
168169

170+
async versions () {
171+
return new VersionsDataSource().versions()
172+
}
173+
169174
@cached
170175
get browser () {
171176
return new BrowserDataSource(this)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import execa from 'execa'
2+
3+
interface Version {
4+
id: string
5+
released: string
6+
version: string
7+
}
8+
9+
interface VersionData {
10+
current: Version
11+
latest: Version
12+
}
13+
14+
export class VersionsDataSource {
15+
/**
16+
* Returns most recent and current version of Cypress
17+
* {
18+
* current: {
19+
* version: '8.7.0',
20+
* released: '2021-10-15T21:38:59.983Z'
21+
* },
22+
* latest: {
23+
* version: '8.8.0',
24+
* released: '2021-10-25T21:38:59.983Z'
25+
* }
26+
* }
27+
*/
28+
async versions (): Promise<VersionData> {
29+
const currentCypressVersion = require('cypress/package.json')
30+
const result = await execa(`npm`, [`view`, `cypress`, `time`, `--json`])
31+
32+
const json = JSON.parse(result.stdout)
33+
34+
delete json['modified']
35+
delete json['created']
36+
37+
const latest = Object.keys(json).sort().reverse()?.[0]
38+
39+
if (!latest) {
40+
throw Error('Could not get npm info for Cypress')
41+
}
42+
43+
const latestVersion: Version = {
44+
id: latest,
45+
version: latest,
46+
released: json[latest],
47+
}
48+
49+
return {
50+
latest: latestVersion,
51+
current: {
52+
version: currentCypressVersion.version,
53+
released: currentCypressVersion.version === '0.0.0-development' ? new Date().toISOString() : json[currentCypressVersion.version],
54+
id: currentCypressVersion.version,
55+
},
56+
}
57+
}
58+
}

packages/data-context/src/sources/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export * from './ProjectDataSource'
1313
export * from './SettingsDataSource'
1414
export * from './StorybookDataSource'
1515
export * from './UtilDataSource'
16+
export * from './VersionsDataSource'
1617
export * from './WizardDataSource'

packages/data-context/src/util/urqlCacheKeys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export const urqlCacheKeys: Partial<CacheExchangeOpts> = {
1616
GitInfo: () => null,
1717
BaseError: () => null,
1818
ProjectPreferences: (data) => data.__typename,
19+
VersionData: () => null,
1920
},
2021
}

packages/frontend-shared/cypress/support/mock-graphql/clientTestContext.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import type { CloudUser } from '../generated/test-cloud-graphql-types.gen'
2-
import type { WizardStep, CurrentProject, Browser, WizardBundler, WizardFrontendFramework, TestingTypeEnum, GlobalProject } from '../generated/test-graphql-types.gen'
2+
import type {
3+
WizardStep,
4+
CurrentProject,
5+
Browser,
6+
WizardBundler,
7+
WizardFrontendFramework,
8+
TestingTypeEnum,
9+
GlobalProject,
10+
VersionData,
11+
} from '../generated/test-graphql-types.gen'
312
import { resetTestNodeIdx } from './clientTestUtils'
413
import { stubBrowsers } from './stubgql-Browser'
514
import * as cloudTypes from './stubgql-CloudTypes'
@@ -13,6 +22,7 @@ export interface ClientTestContext {
1322
currentBrowser: Browser | null
1423
browsers: Browser[] | null
1524
}
25+
versions: VersionData
1626
isAuthBrowserOpened: boolean
1727
wizard: {
1828
step: WizardStep
@@ -48,6 +58,21 @@ export function makeClientTestContext (): ClientTestContext {
4858
browsers: stubBrowsers,
4959
currentBrowser: stubBrowsers[0],
5060
},
61+
versions: {
62+
__typename: 'VersionData',
63+
current: {
64+
__typename: 'Version',
65+
id: '8.7.0',
66+
version: '8.7.0',
67+
released: '2021-10-25T21:38:59.983Z',
68+
},
69+
latest: {
70+
__typename: 'Version',
71+
id: '8.6.0',
72+
version: '8.6.0',
73+
released: '2021-10-11T19:40:49.036Z',
74+
},
75+
},
5176
isAuthBrowserOpened: false,
5277
wizard: {
5378
step: 'configFiles',

packages/frontend-shared/cypress/support/mock-graphql/stubgql-Query.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ export const stubQuery: MaybeResolver<Query> = {
1212
currentProject (source, args, ctx) {
1313
return ctx.currentProject
1414
},
15-
projects (soruce, args, ctx) {
15+
projects (source, args, ctx) {
1616
return ctx.projects
1717
},
18+
versions (source, args, ctx) {
19+
return ctx.versions
20+
},
1821
isAuthBrowserOpened (source, args, ctx) {
1922
return ctx.isAuthBrowserOpened
2023
},

packages/frontend-shared/src/gql-components/HeaderBarContent.spec.tsx

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ describe('<HeaderBarContent />', { viewportWidth: 1000, viewportHeight: 750 }, (
2020

2121
it('renders without browser menu by default and other items work', () => {
2222
cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, {
23-
render: (gqlVal) => <div class="resize overflow-auto border-current border-1 h-700px"><HeaderBarContent gql={gqlVal} /></div>,
23+
render: (gqlVal) => (
24+
<div class="resize overflow-auto border-current border-1 h-700px">
25+
<HeaderBarContent gql={gqlVal} />
26+
</div>
27+
),
2428
})
2529

2630
cy.contains('Projects').should('be.visible')
@@ -32,6 +36,69 @@ describe('<HeaderBarContent />', { viewportWidth: 1000, viewportHeight: 750 }, (
3236
cy.contains('a', text.seeAllReleases).should('be.visible')
3337
})
3438

39+
it('does not show hint when on latest version of Cypress', () => {
40+
cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, {
41+
onResult: (result) => {
42+
result.versions = {
43+
__typename: 'VersionData',
44+
latest: {
45+
__typename: 'Version',
46+
id: '8.7.0',
47+
version: '8.7.0',
48+
released: '2021-10-25T21:00:00.000Z',
49+
},
50+
current: {
51+
__typename: 'Version',
52+
id: '8.7.0',
53+
version: '8.7.0',
54+
released: '2021-10-25T21:00:00.000Z',
55+
},
56+
}
57+
},
58+
render: (gqlVal) => (
59+
<div class="resize overflow-auto border-current border-1 h-700px">
60+
<HeaderBarContent gql={gqlVal} />
61+
</div>
62+
),
63+
})
64+
65+
cy.get('[data-cy="topnav-version-list"]').click()
66+
cy.get('[data-cy="latest-version"]').contains('8.7.0')
67+
cy.get('[data-cy="update-hint"]').should('not.exist')
68+
})
69+
70+
it('shows hint to upgrade to latest version of cypress', () => {
71+
cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, {
72+
onResult: (result) => {
73+
result.versions = {
74+
__typename: 'VersionData',
75+
current: {
76+
__typename: 'Version',
77+
id: '8.6.0',
78+
version: '8.6.0',
79+
released: '2021-06-25T21:00:00.000Z',
80+
},
81+
latest: {
82+
__typename: 'Version',
83+
id: '8.7.0',
84+
version: '8.7.0',
85+
released: '2021-10-25T21:00:00.000Z',
86+
},
87+
}
88+
},
89+
render: (gqlVal) => (
90+
<div class="resize overflow-auto border-current border-1 h-700px">
91+
<HeaderBarContent gql={gqlVal} />
92+
</div>
93+
),
94+
})
95+
96+
cy.contains('8.6.0').click()
97+
cy.get('[data-cy="latest-version"]').contains('8.7.0')
98+
cy.get('[data-cy="current-version"]').contains('8.6.0')
99+
cy.get('[data-cy="update-hint"]').should('exist')
100+
})
101+
35102
it('displays the active project name', () => {
36103
cy.mountFragment(HeaderBar_HeaderBarContentFragmentDoc, {
37104
render: (gqlVal) => <div class="resize overflow-auto border-current border-1 h-700px"><HeaderBarContent gql={gqlVal} /></div>,

0 commit comments

Comments
 (0)