Skip to content

Commit 3c2fea2

Browse files
authored
chore(server): convert remaining browsers code to typescript (#23556)
1 parent 4871ebc commit 3c2fea2

File tree

26 files changed

+588
-602
lines changed

26 files changed

+588
-602
lines changed

packages/app/cypress/e2e/cypress-in-cypress-component.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ describe('Cypress In Cypress CT', { viewportWidth: 1500, defaultCommandTimeout:
144144
expect(ctx.actions.browser.setActiveBrowserById).to.have.been.calledWith(browserId)
145145
expect(genId).to.eql('firefox-firefox-stable')
146146
expect(ctx.actions.project.launchProject).to.have.been.calledWith(
147-
ctx.coreData.currentTestingType, {}, o.sinon.match(new RegExp('cypress\-in\-cypress\/src\/TestComponent\.spec\.jsx$')),
147+
ctx.coreData.currentTestingType, undefined, o.sinon.match(new RegExp('cypress\-in\-cypress\/src\/TestComponent\.spec\.jsx$')),
148148
)
149149
})
150150
})

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ describe('App Top Nav Workflows', () => {
110110
expect(ctx.actions.browser.setActiveBrowserById).to.have.been.calledWith(browserId)
111111
expect(genId).to.eql('edge-chromium-stable')
112112
expect(ctx.actions.project.launchProject).to.have.been.calledWith(
113-
ctx.coreData.currentTestingType, {}, undefined,
113+
ctx.coreData.currentTestingType, undefined, undefined,
114114
)
115115
})
116116
})

packages/data-context/src/actions/ProjectActions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { CodeGenType, MutationSetProjectPreferencesInGlobalCacheArgs, NexusGenObjects, NexusGenUnions } from '@packages/graphql/src/gen/nxs.gen'
2-
import type { InitializeProjectOptions, FoundBrowser, FoundSpec, LaunchOpts, OpenProjectLaunchOptions, Preferences, TestingType, ReceivedCypressOptions, AddProject, FullConfig, AllowedState, SpecWithRelativeRoot } from '@packages/types'
2+
import type { InitializeProjectOptions, FoundBrowser, FoundSpec, OpenProjectLaunchOptions, Preferences, TestingType, ReceivedCypressOptions, AddProject, FullConfig, AllowedState, SpecWithRelativeRoot, OpenProjectLaunchOpts } from '@packages/types'
33
import type { EventEmitter } from 'events'
44
import execa from 'execa'
55
import path from 'path'
@@ -22,7 +22,7 @@ export interface ProjectApiShape {
2222
* order for CT to startup
2323
*/
2424
openProjectCreate(args: InitializeProjectOptions, options: OpenProjectLaunchOptions): Promise<unknown>
25-
launchProject(browser: FoundBrowser, spec: Cypress.Spec, options: LaunchOpts): Promise<void>
25+
launchProject(browser: FoundBrowser, spec: Cypress.Spec, options?: OpenProjectLaunchOpts): Promise<void>
2626
insertProjectToCache(projectRoot: string): Promise<void>
2727
removeProjectFromCache(projectRoot: string): Promise<void>
2828
getProjectRootsFromCache(): Promise<ProjectShape[]>
@@ -175,7 +175,7 @@ export class ProjectActions {
175175
// When switching testing type, the project should be relaunched in the previously selected browser
176176
if (this.ctx.coreData.app.relaunchBrowser) {
177177
this.ctx.project.setRelaunchBrowser(false)
178-
await this.ctx.actions.project.launchProject(this.ctx.coreData.currentTestingType, {})
178+
await this.ctx.actions.project.launchProject(this.ctx.coreData.currentTestingType)
179179
}
180180
})
181181
} catch (e) {
@@ -228,7 +228,7 @@ export class ProjectActions {
228228
}
229229
}
230230

231-
async launchProject (testingType: Cypress.TestingType | null, options: LaunchOpts, specPath?: string | null) {
231+
async launchProject (testingType: Cypress.TestingType | null, options?: OpenProjectLaunchOpts, specPath?: string | null) {
232232
if (!this.ctx.currentProject) {
233233
return null
234234
}

packages/data-context/src/data/ProjectLifecycleManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export class ProjectLifecycleManager {
287287
if (this.ctx.coreData.activeBrowser) {
288288
// if `cypress open` was launched with a `--project` and `--testingType`, go ahead and launch the `--browser`
289289
if (this.ctx.modeOptions.project && this.ctx.modeOptions.testingType) {
290-
await this.ctx.actions.project.launchProject(this.ctx.coreData.currentTestingType, {})
290+
await this.ctx.actions.project.launchProject(this.ctx.coreData.currentTestingType)
291291
}
292292

293293
return

packages/frontend-shared/cypress/e2e/support/e2eSupport.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ function startAppServer (mode: 'component' | 'e2e' = 'e2e', options: { skipMocki
294294
if (!ctx.lifecycleManager.browsers?.length) throw new Error('No browsers available in startAppServer')
295295

296296
await ctx.actions.browser.setActiveBrowser(ctx.lifecycleManager.browsers[0])
297+
// @ts-expect-error this interface is strict about the options it expects
297298
await ctx.actions.project.launchProject(o.mode, { url: o.url })
298299

299300
if (!o.skipMockingPrompts

packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ export const mutation = mutationType({
290290
specPath: stringArg(),
291291
},
292292
resolve: async (_, args, ctx) => {
293-
await ctx.actions.project.launchProject(ctx.coreData.currentTestingType, {}, args.specPath)
293+
await ctx.actions.project.launchProject(ctx.coreData.currentTestingType, undefined, args.specPath)
294294

295295
return ctx.lifecycleManager
296296
},

packages/server/lib/browsers/browser-cri-client.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import CRI from 'chrome-remote-interface'
22
import Debug from 'debug'
33
import { _connectAsync, _getDelayMsForRetry } from './protocol'
44
import * as errors from '../errors'
5-
import { create, CRIWrapper } from './cri-client'
5+
import { create, CriClient } from './cri-client'
66

77
const HOST = '127.0.0.1'
88

@@ -67,8 +67,8 @@ const retryWithIncreasingDelay = async <T>(retryable: () => Promise<T>, browserN
6767
}
6868

6969
export class BrowserCriClient {
70-
currentlyAttachedTarget: CRIWrapper.Client | undefined
71-
private constructor (private browserClient: CRIWrapper.Client, private versionInfo, private port: number, private browserName: string, private onAsynchronousError: Function) {}
70+
currentlyAttachedTarget: CriClient | undefined
71+
private constructor (private browserClient: CriClient, private versionInfo, private port: number, private browserName: string, private onAsynchronousError: Function) {}
7272

7373
/**
7474
* Factory method for the browser cri client. Connects to the browser and then returns a chrome remote interface wrapper around the
@@ -79,7 +79,7 @@ export class BrowserCriClient {
7979
* @param onAsynchronousError callback for any cdp fatal errors
8080
* @returns a wrapper around the chrome remote interface that is connected to the browser target
8181
*/
82-
static async create (port: number, browserName: string, onAsynchronousError: Function, onReconnect?: (client: CRIWrapper.Client) => void): Promise<BrowserCriClient> {
82+
static async create (port: number, browserName: string, onAsynchronousError: Function, onReconnect?: (client: CriClient) => void): Promise<BrowserCriClient> {
8383
await ensureLiveBrowser(port, browserName)
8484

8585
return retryWithIncreasingDelay(async () => {
@@ -110,7 +110,7 @@ export class BrowserCriClient {
110110
* @param url the url to attach to
111111
* @returns the chrome remote interface wrapper for the target
112112
*/
113-
attachToTargetUrl = async (url: string): Promise<CRIWrapper.Client> => {
113+
attachToTargetUrl = async (url: string): Promise<CriClient> => {
114114
// Continue trying to re-attach until succcessful.
115115
// If the browser opens slowly, this will fail until
116116
// The browser and automation API is ready, so we try a few

packages/server/lib/browsers/cdp_automation.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
import _ from 'lodash'
44
import Bluebird from 'bluebird'
55
import type { Protocol } from 'devtools-protocol'
6+
import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping'
67
import { cors, uri } from '@packages/network'
78
import debugModule from 'debug'
89
import { URL } from 'url'
910

1011
import type { Automation } from '../automation'
1112
import type { ResourceType, BrowserPreRequest, BrowserResponseReceived } from '@packages/proxy'
1213

14+
export type CdpCommand = keyof ProtocolMapping.Commands
15+
16+
export type CdpEvent = keyof ProtocolMapping.Events
17+
1318
const debugVerbose = debugModule('cypress-verbose:server:browsers:cdp_automation')
1419

1520
export type CyCookie = Pick<chrome.cookies.Cookie, 'name' | 'value' | 'expirationDate' | 'hostOnly' | 'domain' | 'path' | 'secure' | 'httpOnly'> & {
@@ -163,9 +168,9 @@ export const normalizeResourceType = (resourceType: string | undefined): Resourc
163168
return ffToStandardResourceTypeMap[resourceType] || 'other'
164169
}
165170

166-
type SendDebuggerCommand = (message: string, data?: any) => Promise<any>
167-
type SendCloseCommand = (shouldKeepTabOpen: boolean) => Promise<any>
168-
type OnFn = (eventName: string, cb: Function) => void
171+
type SendDebuggerCommand = (message: CdpCommand, data?: any) => Promise<any>
172+
type SendCloseCommand = (shouldKeepTabOpen: boolean) => Promise<any> | void
173+
type OnFn = (eventName: CdpEvent, cb: Function) => void
169174

170175
// the intersection of what's valid in CDP and what's valid in FFCDP
171176
// Firefox: https://searchfox.org/mozilla-central/rev/98a9257ca2847fad9a19631ac76199474516b31e/remote/cdp/domains/parent/Network.jsm#22

packages/server/lib/browsers/chrome.ts

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@ import utils from './utils'
1818
import type { Browser } from './types'
1919
import { BrowserCriClient } from './browser-cri-client'
2020
import type { LaunchedBrowser } from '@packages/launcher/lib/browsers'
21-
import type { CRIWrapper } from './cri-client'
21+
import type { CriClient } from './cri-client'
2222
import type { Automation } from '../automation'
23-
24-
// TODO: this is defined in `cypress-npm-api` but there is currently no way to get there
25-
type CypressConfiguration = any
23+
import type { BrowserLaunchOpts, BrowserNewTabOpts } from '@packages/types'
2624

2725
const debug = debugModule('cypress:server:browsers:chrome')
2826

@@ -123,7 +121,7 @@ const DEFAULT_ARGS = [
123121
'--disable-dev-shm-usage',
124122
]
125123

126-
let browserCriClient
124+
let browserCriClient: BrowserCriClient | undefined
127125

128126
/**
129127
* Reads all known preference files (CHROME_PREFERENCE_PATHS) from disk and retur
@@ -320,15 +318,15 @@ const _handleDownloads = async function (client, dir, automation) {
320318
let frameTree
321319
let gettingFrameTree
322320

323-
const onReconnect = (client: CRIWrapper.Client) => {
321+
const onReconnect = (client: CriClient) => {
324322
// if the client disconnects (e.g. due to a computer sleeping), update
325323
// the frame tree on reconnect in cases there were changes while
326324
// the client was disconnected
327325
return _updateFrameTree(client, 'onReconnect')()
328326
}
329327

330328
// eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces
331-
const _updateFrameTree = (client: CRIWrapper.Client, eventName) => async () => {
329+
const _updateFrameTree = (client: CriClient, eventName) => async () => {
332330
debug(`update frame tree for ${eventName}`)
333331

334332
gettingFrameTree = new Promise<void>(async (resolve) => {
@@ -433,8 +431,8 @@ const _handlePausedRequests = async (client) => {
433431
})
434432
}
435433

436-
const _setAutomation = async (client: CRIWrapper.Client, automation: Automation, resetBrowserTargets: (shouldKeepTabOpen: boolean) => Promise<void>, options: CypressConfiguration = {}) => {
437-
const cdpAutomation = await CdpAutomation.create(client.send, client.on, resetBrowserTargets, automation, options.experimentalSessionAndOrigin)
434+
const _setAutomation = async (client: CriClient, automation: Automation, resetBrowserTargets: (shouldKeepTabOpen: boolean) => Promise<void>, options: BrowserLaunchOpts) => {
435+
const cdpAutomation = await CdpAutomation.create(client.send, client.on, resetBrowserTargets, automation, !!options.experimentalSessionAndOrigin)
438436

439437
return automation.use(cdpAutomation)
440438
}
@@ -490,7 +488,7 @@ export = {
490488
return extensionDest
491489
},
492490

493-
_getArgs (browser: Browser, options: CypressConfiguration, port: string) {
491+
_getArgs (browser: Browser, options: BrowserLaunchOpts, port: string) {
494492
const args = ([] as string[]).concat(DEFAULT_ARGS)
495493

496494
if (os.platform() === 'linux') {
@@ -551,43 +549,60 @@ export = {
551549
return args
552550
},
553551

554-
async connectToNewSpec (browser: Browser, options: CypressConfiguration = {}, automation: Automation) {
552+
async connectToNewSpec (browser: Browser, options: BrowserNewTabOpts, automation: Automation) {
555553
debug('connecting to new chrome tab in existing instance with url and debugging port', { url: options.url })
556554

557555
const browserCriClient = this._getBrowserCriClient()
556+
557+
if (!browserCriClient) throw new Error('Missing browserCriClient in connectToNewSpec')
558+
558559
const pageCriClient = browserCriClient.currentlyAttachedTarget
559560

561+
if (!pageCriClient) throw new Error('Missing pageCriClient in connectToNewSpec')
562+
563+
if (!options.url) throw new Error('Missing url in connectToNewSpec')
564+
565+
await this.attachListeners(browser, options.url, pageCriClient, automation, options)
566+
},
567+
568+
async connectToExisting (browser: Browser, options: BrowserLaunchOpts, automation) {
569+
const port = await protocol.getRemoteDebuggingPort()
570+
571+
debug('connecting to existing chrome instance with url and debugging port', { url: options.url, port })
572+
if (!options.onError) throw new Error('Missing onError in connectToExisting')
573+
574+
const browserCriClient = await BrowserCriClient.create(port, browser.displayName, options.onError, onReconnect)
575+
576+
if (!options.url) throw new Error('Missing url in connectToExisting')
577+
578+
const pageCriClient = await browserCriClient.attachToTargetUrl(options.url)
579+
580+
await this._setAutomation(pageCriClient, automation, browserCriClient.resetBrowserTargets, options)
581+
},
582+
583+
async attachListeners (browser: Browser, url: string, pageCriClient, automation: Automation, options: BrowserLaunchOpts & { onInitializeNewBrowserTab?: () => void }) {
584+
if (!browserCriClient) throw new Error('Missing browserCriClient in attachListeners')
585+
560586
await this._setAutomation(pageCriClient, automation, browserCriClient.resetBrowserTargets, options)
561587

562-
// make sure page events are re enabled or else frame tree updates will NOT work as well as other items listening for page events
563588
await pageCriClient.send('Page.enable')
564589

565-
await options.onInitializeNewBrowserTab()
590+
await options.onInitializeNewBrowserTab?.()
566591

567592
await Promise.all([
568593
this._maybeRecordVideo(pageCriClient, options, browser.majorVersion),
569594
this._handleDownloads(pageCriClient, options.downloadsFolder, automation),
570595
])
571596

572-
await this._navigateUsingCRI(pageCriClient, options.url)
597+
await this._navigateUsingCRI(pageCriClient, url)
573598

574599
if (options.experimentalSessionAndOrigin) {
575600
await this._handlePausedRequests(pageCriClient)
576601
_listenForFrameTreeChanges(pageCriClient)
577602
}
578603
},
579604

580-
async connectToExisting (browser: Browser, options: CypressConfiguration = {}, automation) {
581-
const port = await protocol.getRemoteDebuggingPort()
582-
583-
debug('connecting to existing chrome instance with url and debugging port', { url: options.url, port })
584-
const browserCriClient = await BrowserCriClient.create(port, browser.displayName, options.onError, onReconnect)
585-
const pageCriClient = await browserCriClient.attachToTargetUrl(options.url)
586-
587-
await this._setAutomation(pageCriClient, automation, browserCriClient.resetBrowserTargets, options)
588-
},
589-
590-
async open (browser: Browser, url, options: CypressConfiguration = {}, automation: Automation): Promise<LaunchedBrowser> {
605+
async open (browser: Browser, url, options: BrowserLaunchOpts, automation: Automation): Promise<LaunchedBrowser> {
591606
const { isTextTerminal } = options
592607

593608
const userDir = utils.getProfileDir(browser, isTextTerminal)
@@ -646,6 +661,8 @@ export = {
646661
// SECOND connect to the Chrome remote interface
647662
// and when the connection is ready
648663
// navigate to the actual url
664+
if (!options.onError) throw new Error('Missing onError in chrome#open')
665+
649666
browserCriClient = await BrowserCriClient.create(port, browser.displayName, options.onError, onReconnect)
650667

651668
la(browserCriClient, 'expected Chrome remote interface reference', browserCriClient)
@@ -669,7 +686,7 @@ export = {
669686
debug('closing remote interface client')
670687

671688
// Do nothing on failure here since we're shutting down anyway
672-
browserCriClient.close().catch()
689+
browserCriClient?.close().catch()
673690
browserCriClient = undefined
674691

675692
debug('closing chrome')
@@ -679,21 +696,7 @@ export = {
679696

680697
const pageCriClient = await browserCriClient.attachToTargetUrl('about:blank')
681698

682-
await this._setAutomation(pageCriClient, automation, browserCriClient.resetBrowserTargets, options)
683-
684-
await pageCriClient.send('Page.enable')
685-
686-
await Promise.all([
687-
this._maybeRecordVideo(pageCriClient, options, browser.majorVersion),
688-
this._handleDownloads(pageCriClient, options.downloadsFolder, automation),
689-
])
690-
691-
await this._navigateUsingCRI(pageCriClient, url)
692-
693-
if (options.experimentalSessionAndOrigin) {
694-
await this._handlePausedRequests(pageCriClient)
695-
_listenForFrameTreeChanges(pageCriClient)
696-
}
699+
await this.attachListeners(browser, url, pageCriClient, automation, options)
697700

698701
// return the launched browser process
699702
// with additional method to close the remote connection

0 commit comments

Comments
 (0)