diff --git a/packages/driver/cypress/e2e/commands/prompt.cy.ts b/packages/driver/cypress/e2e/commands/prompt.cy.ts index 9fb327349909..78ba0620c4bc 100644 --- a/packages/driver/cypress/e2e/commands/prompt.cy.ts +++ b/packages/driver/cypress/e2e/commands/prompt.cy.ts @@ -1,5 +1,12 @@ describe('src/cy/commands/prompt', () => { it('executes the prompt command', () => { + // TODO: (cy.prompt) We will look into supporting other browsers + // as this is rolled out. We will add error messages for other browsers + // and add tests if necessary + if (Cypress.isBrowser('webkit') || Cypress.isBrowser('firefox')) { + return + } + cy.visit('/fixtures/dom.html') // TODO: add more tests when cy.prompt is built out, but for now this just diff --git a/packages/driver/src/cy/commands/prompt/index.ts b/packages/driver/src/cy/commands/prompt/index.ts index 211cfc4f1c23..96d00215a12e 100644 --- a/packages/driver/src/cy/commands/prompt/index.ts +++ b/packages/driver/src/cy/commands/prompt/index.ts @@ -43,6 +43,12 @@ export default (Commands, Cypress, cy) => { if (Cypress.config('experimentalPromptCommand')) { Commands.addAll({ async prompt (message: string) { + if (Cypress.browser.family !== 'chromium' && Cypress.browser.name !== 'electron') { + // TODO: (cy.prompt) We will look into supporting other browsers (and testing them) + // as this is rolled out + throw new Error('`cy.prompt()` is not supported in this browser.') + } + try { let cloud = initializedCyPrompt diff --git a/packages/server/lib/browsers/browser-cri-client.ts b/packages/server/lib/browsers/browser-cri-client.ts index fe6aa66851a0..db53b515950e 100644 --- a/packages/server/lib/browsers/browser-cri-client.ts +++ b/packages/server/lib/browsers/browser-cri-client.ts @@ -8,7 +8,7 @@ import * as errors from '../errors' import type { CypressError } from '@packages/errors' import { CriClient, DEFAULT_NETWORK_ENABLE_OPTIONS } from './cri-client' import { serviceWorkerClientEventHandler, serviceWorkerClientEventHandlerName } from '@packages/proxy/lib/http/util/service-worker-manager' -import type { ProtocolManagerShape } from '@packages/types' +import type { CyPromptManagerShape, ProtocolManagerShape } from '@packages/types' import type { ServiceWorkerEventHandler } from '@packages/proxy/lib/http/util/service-worker-manager' const debug = Debug('cypress:server:browsers:browser-cri-client') @@ -38,6 +38,7 @@ type BrowserCriClientCreateOptions = { onReconnect?: (client: CriClient) => void port: number protocolManager?: ProtocolManagerShape + cyPromptManager?: CyPromptManagerShape onServiceWorkerClientEvent: ServiceWorkerEventHandler } @@ -184,10 +185,12 @@ export class BrowserCriClient { private browserName: string private onAsynchronousError: (err: CypressError) => void private protocolManager?: ProtocolManagerShape + private cyPromptManager?: CyPromptManagerShape private fullyManageTabs?: boolean onServiceWorkerClientEvent: ServiceWorkerEventHandler currentlyAttachedTarget: CriClient | undefined currentlyAttachedProtocolTarget: CriClient | undefined + currentlyAttachedCyPromptTarget: CriClient | undefined // whenever we instantiate the instance we're already connected bc // we receive an underlying CRI connection // TODO: remove "connected" in favor of closing/closed or disconnected @@ -466,8 +469,9 @@ export class BrowserCriClient { // otherwise it means the the browser itself was closed // always close the connection to the page target because it was destroyed - browserCriClient.currentlyAttachedTarget.close().catch(() => { }), - browserCriClient.currentlyAttachedProtocolTarget?.close().catch(() => {}) + browserCriClient.currentlyAttachedTarget.close().catch(() => { }) + browserCriClient.currentlyAttachedProtocolTarget?.close().catch(() => { }) + browserCriClient.currentlyAttachedCyPromptTarget?.close().catch(() => { }) new Bluebird((resolve) => { // this event could fire either expectedly or unexpectedly @@ -565,9 +569,10 @@ export class BrowserCriClient { // which we do when we exit out of studio in open mode. if (!this.currentlyAttachedProtocolTarget) { this.currentlyAttachedProtocolTarget = await this.currentlyAttachedTarget.clone() - await this.protocolManager?.connectToBrowser(this.currentlyAttachedProtocolTarget) } + await this.protocolManager?.connectToBrowser(this.currentlyAttachedProtocolTarget) + return this.currentlyAttachedTarget }, this.browserName, this.port) } @@ -606,8 +611,11 @@ export class BrowserCriClient { debug('target closed', this.currentlyAttachedTarget.targetId) - await this.currentlyAttachedTarget.close().catch(() => {}) - await this.currentlyAttachedProtocolTarget?.close().catch(() => {}) + await Promise.all([ + this.currentlyAttachedTarget.close().catch(() => {}), + this.currentlyAttachedProtocolTarget?.close().catch(() => {}), + this.currentlyAttachedCyPromptTarget?.close().catch(() => {}), + ]) debug('target client closed', this.currentlyAttachedTarget.targetId) } @@ -620,6 +628,10 @@ export class BrowserCriClient { this.browserClient.off(subscription.eventName, subscription.cb as any) }) + this.currentlyAttachedCyPromptTarget?.queue.subscriptions.forEach((subscription) => { + this.browserClient.off(subscription.eventName, subscription.cb as any) + }) + if (target) { this.currentlyAttachedTarget = await CriClient.create({ target: target.targetId, @@ -631,13 +643,24 @@ export class BrowserCriClient { browserClient: this.browserClient, }) - // Clone the target here so that we separate the protocol client and the main client. - // This allows us to close the protocol client independently of the main client - // which we do when we exit out of studio in open mode. - this.currentlyAttachedProtocolTarget = await this.currentlyAttachedTarget.clone() + const currentTarget = this.currentlyAttachedTarget + + const createProtocolTarget = async () => { + this.currentlyAttachedProtocolTarget = await currentTarget.clone() + } + + const createCyPromptTarget = async () => { + this.currentlyAttachedCyPromptTarget = await currentTarget.clone() + } + + await Promise.all([ + createProtocolTarget(), + createCyPromptTarget(), + ]) } else { this.currentlyAttachedTarget = undefined this.currentlyAttachedProtocolTarget = undefined + this.currentlyAttachedCyPromptTarget = undefined } this.resettingBrowserTargets = false @@ -696,8 +719,11 @@ export class BrowserCriClient { this.connected = false if (this.currentlyAttachedTarget) { - await this.currentlyAttachedTarget.close() - await this.currentlyAttachedProtocolTarget?.close() + await Promise.all([ + this.currentlyAttachedTarget.close(), + this.currentlyAttachedProtocolTarget?.close(), + this.currentlyAttachedCyPromptTarget?.close(), + ]) } await this.browserClient.close() diff --git a/packages/server/lib/browsers/chrome.ts b/packages/server/lib/browsers/chrome.ts index c2d969d3b73b..ea00e5401049 100644 --- a/packages/server/lib/browsers/chrome.ts +++ b/packages/server/lib/browsers/chrome.ts @@ -21,7 +21,7 @@ import type { CriClient } from './cri-client' import type { Automation } from '../automation' import memory from './memory' -import type { BrowserLaunchOpts, BrowserNewTabOpts, ProtocolManagerShape, RunModeVideoApi } from '@packages/types' +import type { BrowserLaunchOpts, BrowserNewTabOpts, ProtocolManagerShape, CyPromptManagerShape, RunModeVideoApi } from '@packages/types' import type { CDPSocketServer } from '@packages/socket/lib/cdp-socket' import { DEFAULT_CHROME_FLAGS } from '../util/chromium_flags' @@ -412,6 +412,18 @@ export = { await options.protocolManager?.connectToBrowser(browserCriClient.currentlyAttachedProtocolTarget) }, + async connectCyPromptToBrowser (options: { cyPromptManager?: CyPromptManagerShape }) { + const browserCriClient = this._getBrowserCriClient() + + if (!browserCriClient?.currentlyAttachedTarget) throw new Error('Missing pageCriClient in connectCyPromptToBrowser') + + if (!browserCriClient.currentlyAttachedCyPromptTarget) { + browserCriClient.currentlyAttachedCyPromptTarget = await browserCriClient.currentlyAttachedTarget.clone() + } + + await options.cyPromptManager?.connectToBrowser(browserCriClient.currentlyAttachedCyPromptTarget) + }, + async closeProtocolConnection () { const browserCriClient = this._getBrowserCriClient() diff --git a/packages/server/lib/browsers/electron.ts b/packages/server/lib/browsers/electron.ts index 07762ae2b7c7..fb75f9d7593e 100644 --- a/packages/server/lib/browsers/electron.ts +++ b/packages/server/lib/browsers/electron.ts @@ -12,7 +12,7 @@ import type { Browser, BrowserInstance, GracefulShutdownOptions } from './types' // tslint:disable-next-line no-implicit-dependencies - electron dep needs to be defined import type { BrowserWindow } from 'electron' import type { Automation } from '../automation' -import type { BrowserLaunchOpts, Preferences, ProtocolManagerShape, RunModeVideoApi } from '@packages/types' +import type { BrowserLaunchOpts, Preferences, ProtocolManagerShape, CyPromptManagerShape, RunModeVideoApi } from '@packages/types' import type { CDPSocketServer } from '@packages/socket/lib/cdp-socket' import memory from './memory' import { BrowserCriClient } from './browser-cri-client' @@ -500,6 +500,19 @@ export = { await options.protocolManager?.connectToBrowser(browserCriClient.currentlyAttachedProtocolTarget) }, + async connectCyPromptToBrowser (options: { cyPromptManager?: CyPromptManagerShape }) { + const browserCriClient = this._getBrowserCriClient() + + if (!browserCriClient?.currentlyAttachedTarget) throw new Error('Missing pageCriClient in connectCyPromptToBrowser') + + // Clone the target here so that we separate the cy prompt client and the main client. + if (!browserCriClient.currentlyAttachedCyPromptTarget) { + browserCriClient.currentlyAttachedCyPromptTarget = await browserCriClient.currentlyAttachedTarget.clone() + } + + await options.cyPromptManager?.connectToBrowser(browserCriClient.currentlyAttachedCyPromptTarget) + }, + async closeProtocolConnection () { const browserCriClient = this._getBrowserCriClient() diff --git a/packages/server/lib/browsers/firefox.ts b/packages/server/lib/browsers/firefox.ts index 9cdc2c4e4c9e..34850fc0e3de 100644 --- a/packages/server/lib/browsers/firefox.ts +++ b/packages/server/lib/browsers/firefox.ts @@ -439,6 +439,10 @@ export function connectProtocolToBrowser (): Promise { throw new Error('Protocol is not yet supported in firefox.') } +export function connectCyPromptToBrowser (): Promise { + throw new Error('CyPrompt is not yet supported in firefox.') +} + export function closeProtocolConnection (): Promise { throw new Error('Protocol is not yet supported in firefox.') } diff --git a/packages/server/lib/browsers/index.ts b/packages/server/lib/browsers/index.ts index b492d76b823a..ed09ac4c0799 100644 --- a/packages/server/lib/browsers/index.ts +++ b/packages/server/lib/browsers/index.ts @@ -7,7 +7,7 @@ import check from 'check-more-types' import { exec } from 'child_process' import util from 'util' import os from 'os' -import { BROWSER_FAMILY, BrowserLaunchOpts, BrowserNewTabOpts, FoundBrowser, ProtocolManagerShape } from '@packages/types' +import { BROWSER_FAMILY, BrowserLaunchOpts, BrowserNewTabOpts, FoundBrowser, ProtocolManagerShape, CyPromptManagerShape } from '@packages/types' import type { Browser, BrowserInstance, BrowserLauncher } from './types' import type { Automation } from '../automation' import type { DataContext } from '@packages/data-context' @@ -147,6 +147,12 @@ export = { await browserLauncher.connectProtocolToBrowser(options) }, + async connectCyPromptToBrowser (options: { browser: Browser, foundBrowsers?: FoundBrowser[], cyPromptManager?: CyPromptManagerShape }) { + const browserLauncher = await getBrowserLauncher(options.browser, options.foundBrowsers || []) + + await browserLauncher.connectCyPromptToBrowser(options) + }, + async closeProtocolConnection (options: { browser: Browser, foundBrowsers?: FoundBrowser[] }) { const browserLauncher = await getBrowserLauncher(options.browser, options.foundBrowsers || []) diff --git a/packages/server/lib/browsers/types.ts b/packages/server/lib/browsers/types.ts index d0579439d622..59668bd41915 100644 --- a/packages/server/lib/browsers/types.ts +++ b/packages/server/lib/browsers/types.ts @@ -1,4 +1,4 @@ -import type { FoundBrowser, BrowserLaunchOpts, BrowserNewTabOpts, ProtocolManagerShape } from '@packages/types' +import type { FoundBrowser, BrowserLaunchOpts, BrowserNewTabOpts, ProtocolManagerShape, CyPromptManagerShape } from '@packages/types' import type { EventEmitter } from 'events' import type { Automation } from '../automation' import type { CDPSocketServer } from '@packages/socket/lib/cdp-socket' @@ -45,6 +45,10 @@ export type BrowserLauncher = { * Used to connect the protocol to an existing browser. */ connectProtocolToBrowser: (options: { protocolManager?: ProtocolManagerShape }) => Promise + /** + * Used to connect the cy prompt to an existing browser. + */ + connectCyPromptToBrowser: (options: { cyPromptManager?: CyPromptManagerShape }) => Promise /** * Closes the protocol connection to the browser. */ diff --git a/packages/server/lib/browsers/webkit.ts b/packages/server/lib/browsers/webkit.ts index 794990cedccc..22ccf58a3302 100644 --- a/packages/server/lib/browsers/webkit.ts +++ b/packages/server/lib/browsers/webkit.ts @@ -40,6 +40,10 @@ export function connectProtocolToBrowser (): Promise { throw new Error('Protocol is not yet supported in WebKit.') } +export function connectCyPromptToBrowser (): Promise { + throw new Error('CyPrompt is not yet supported in WebKit.') +} + export function closeProtocolConnection (): Promise { throw new Error('Protocol is not yet supported in WebKit.') } diff --git a/packages/server/lib/cloud/api/cy-prompt/get_cy_prompt_bundle.ts b/packages/server/lib/cloud/api/cy-prompt/get_cy_prompt_bundle.ts index fbdc12171478..0eb3f3879afa 100644 --- a/packages/server/lib/cloud/api/cy-prompt/get_cy_prompt_bundle.ts +++ b/packages/server/lib/cloud/api/cy-prompt/get_cy_prompt_bundle.ts @@ -10,7 +10,7 @@ import { verifySignatureFromFile } from '../../encryption' const pkg = require('@packages/root') const _delay = linearDelay(500) -export const getCyPromptBundle = async ({ cyPromptUrl, projectId, bundlePath }: { cyPromptUrl: string, projectId: string, bundlePath: string }) => { +export const getCyPromptBundle = async ({ cyPromptUrl, projectId, bundlePath }: { cyPromptUrl: string, projectId?: string, bundlePath: string }) => { let responseSignature: string | null = null await (asyncRetry(async () => { diff --git a/packages/server/lib/cloud/cy-prompt/CyPromptLifecycleManager.ts b/packages/server/lib/cloud/cy-prompt/CyPromptLifecycleManager.ts index e7bce3cd41cb..931d709c1ed1 100644 --- a/packages/server/lib/cloud/cy-prompt/CyPromptLifecycleManager.ts +++ b/packages/server/lib/cloud/cy-prompt/CyPromptLifecycleManager.ts @@ -30,7 +30,7 @@ export class CyPromptLifecycleManager { cloudDataSource, ctx, }: { - projectId: string + projectId?: string cloudDataSource: CloudDataSource ctx: DataContext }): void { @@ -88,7 +88,7 @@ export class CyPromptLifecycleManager { projectId, cloudDataSource, }: { - projectId: string + projectId?: string cloudDataSource: CloudDataSource }): Promise { const cyPromptSession = await postCyPromptSession({ diff --git a/packages/server/lib/cloud/cy-prompt/CyPromptManager.ts b/packages/server/lib/cloud/cy-prompt/CyPromptManager.ts index ce247d5a156f..c3d08058b4d6 100644 --- a/packages/server/lib/cloud/cy-prompt/CyPromptManager.ts +++ b/packages/server/lib/cloud/cy-prompt/CyPromptManager.ts @@ -1,4 +1,4 @@ -import type { CyPromptManagerShape, CyPromptStatus, CyPromptServerDefaultShape, CyPromptServerShape, CyPromptCloudApi } from '@packages/types' +import type { CyPromptManagerShape, CyPromptStatus, CyPromptServerDefaultShape, CyPromptServerShape, CyPromptCloudApi, CyPromptCDPClient } from '@packages/types' import type { Router } from 'express' import Debug from 'debug' import { requireScript } from '../require_script' @@ -40,7 +40,13 @@ export class CyPromptManager implements CyPromptManagerShape { async handleBackendRequest (eventName: string, ...args: any[]): Promise { if (this._cyPromptServer) { - return this.invokeAsync('handleBackendRequest', { isEssential: true }, eventName, ...args) + return this.invokeAsync('handleBackendRequest', { isEssential: false }, eventName, ...args) + } + } + + connectToBrowser (target: CyPromptCDPClient): void { + if (this._cyPromptServer) { + return this.invokeSync('connectToBrowser', { isEssential: true }, target) } } @@ -54,6 +60,7 @@ export class CyPromptManager implements CyPromptManagerShape { } try { + // @ts-expect-error - TS not associating the method & args properly, even though we know it's correct return this._cyPromptServer[method].apply(this._cyPromptServer, args) } catch (error: unknown) { let actualError: Error diff --git a/packages/server/lib/cloud/cy-prompt/ensure_cy_prompt_bundle.ts b/packages/server/lib/cloud/cy-prompt/ensure_cy_prompt_bundle.ts index 14af0eac0e07..5248c479e558 100644 --- a/packages/server/lib/cloud/cy-prompt/ensure_cy_prompt_bundle.ts +++ b/packages/server/lib/cloud/cy-prompt/ensure_cy_prompt_bundle.ts @@ -7,7 +7,7 @@ import path from 'path' interface EnsureCyPromptBundleOptions { cyPromptPath: string cyPromptUrl: string - projectId: string + projectId?: string bundlePath: string } diff --git a/packages/server/lib/open_project.ts b/packages/server/lib/open_project.ts index 797eeac8f590..0f60e82c5189 100644 --- a/packages/server/lib/open_project.ts +++ b/packages/server/lib/open_project.ts @@ -235,6 +235,10 @@ export class OpenProject { await browsers.connectProtocolToBrowser(options) } + async connectCyPromptToBrowser (options) { + await browsers.connectCyPromptToBrowser(options) + } + changeUrlToSpec (spec: Cypress.Spec) { if (!this.projectBase) { debug('No projectBase, cannot change url') diff --git a/packages/server/lib/project-base.ts b/packages/server/lib/project-base.ts index 1264799e2592..222201d23c59 100644 --- a/packages/server/lib/project-base.ts +++ b/packages/server/lib/project-base.ts @@ -17,7 +17,7 @@ import { SocketCt } from './socket-ct' import { SocketE2E } from './socket-e2e' import { ensureProp } from './util/class-helpers' import system from './util/system' -import { BannersState, FoundBrowser, FoundSpec, OpenProjectLaunchOptions, ProtocolManagerShape, ReceivedCypressOptions, ResolvedConfigurationOptions, TestingType, VideoRecording, AutomationCommands, StudioMetricsTypes } from '@packages/types' +import { BannersState, FoundBrowser, FoundSpec, OpenProjectLaunchOptions, ProtocolManagerShape, CyPromptManagerShape, ReceivedCypressOptions, ResolvedConfigurationOptions, TestingType, VideoRecording, AutomationCommands, StudioMetricsTypes } from '@packages/types' import { DataContext, getCtx } from '@packages/data-context' import { createHmac } from 'crypto' import { ServerBase } from './server-base' @@ -158,7 +158,7 @@ export class ProjectBase extends EE { process.chdir(this.projectRoot) this._server = new ServerBase(cfg) - if (cfg.projectId && cfg.experimentalPromptCommand) { + if (cfg.experimentalPromptCommand) { const cyPromptLifecycleManager = new CyPromptLifecycleManager() cyPromptLifecycleManager.initializeCyPromptManager({ @@ -514,6 +514,10 @@ export class ProjectBase extends EE { } }, + onCyPromptReady: async (cyPromptManager: CyPromptManagerShape) => { + await browsers.connectCyPromptToBrowser({ browser: this.browser, foundBrowsers: this.options.browsers, cyPromptManager }) + }, + onCaptureVideoFrames: (data: any) => { // TODO: move this to browser automation middleware this.emit('capture:video:frames', data) diff --git a/packages/server/lib/socket-base.ts b/packages/server/lib/socket-base.ts index e99e18f5d2bd..aa254b2e4285 100644 --- a/packages/server/lib/socket-base.ts +++ b/packages/server/lib/socket-base.ts @@ -154,6 +154,7 @@ export class SocketBase { onCaptureVideoFrames () {}, onStudioInit () {}, onStudioDestroy () {}, + onCyPromptReady () {}, }) let automationClient @@ -545,7 +546,9 @@ export class SocketBase { case 'close:extra:targets': return options.closeExtraTargets() case 'wait:for:cy:prompt:ready': - return getCtx().coreData.cyPromptLifecycleManager?.getCyPrompt().then((cyPrompt) => { + return getCtx().coreData.cyPromptLifecycleManager?.getCyPrompt().then(async (cyPrompt) => { + await options.onCyPromptReady(cyPrompt) + return { success: cyPrompt && cyPrompt.status === 'INITIALIZED', } diff --git a/packages/server/test/support/fixtures/cloud/cy-prompt/test-cy-prompt.ts b/packages/server/test/support/fixtures/cloud/cy-prompt/test-cy-prompt.ts index 513a7e6107a6..cde602ab31ff 100644 --- a/packages/server/test/support/fixtures/cloud/cy-prompt/test-cy-prompt.ts +++ b/packages/server/test/support/fixtures/cloud/cy-prompt/test-cy-prompt.ts @@ -1,6 +1,6 @@ /// -import type { CyPromptServerShape, CyPromptServerDefaultShape } from '@packages/types' +import type { CyPromptServerShape, CyPromptServerDefaultShape, CyPromptCDPClient } from '@packages/types' import type { Router } from 'express' class CyPromptServer implements CyPromptServerShape { @@ -11,6 +11,10 @@ class CyPromptServer implements CyPromptServerShape { handleBackendRequest (eventName: string, ...args: any[]): Promise { return Promise.resolve() } + + connectToBrowser (criClient: CyPromptCDPClient): void { + // This is a test implementation that does nothing + } } const cyPromptServerDefault: CyPromptServerDefaultShape = { diff --git a/packages/server/test/unit/browsers/browser-cri-client_spec.ts b/packages/server/test/unit/browsers/browser-cri-client_spec.ts index 39e18c66ad1a..5647f1179a13 100644 --- a/packages/server/test/unit/browsers/browser-cri-client_spec.ts +++ b/packages/server/test/unit/browsers/browser-cri-client_spec.ts @@ -4,7 +4,7 @@ import { expect, proxyquire, sinon } from '../../spec_helper' import * as protocol from '../../../lib/browsers/protocol' import { stripAnsi } from '@packages/errors' import net from 'net' -import { ProtocolManagerShape } from '@packages/types' +import { ProtocolManagerShape, CyPromptManagerShape } from '@packages/types' import type { Protocol } from 'devtools-protocol' import { serviceWorkerClientEventHandlerName } from '@packages/proxy/lib/http/util/service-worker-manager' @@ -14,6 +14,7 @@ const THROWS_PORT = 65535 type GetClientParams = { protocolManager?: ProtocolManagerShape + cyPromptManager?: CyPromptManagerShape fullyManageTabs?: boolean } @@ -370,6 +371,9 @@ describe('lib/browsers/browser-cri-client', function () { currentlyAttachedProtocolTarget: { close: sinon.stub().resolves(), }, + currentlyAttachedCyPromptTarget: { + close: sinon.stub().resolves(), + }, resettingBrowserTargets: false, }, event: { @@ -386,6 +390,7 @@ describe('lib/browsers/browser-cri-client', function () { expect(options.browserCriClient.getExtraTargetClient).not.to.be.called expect(options.browserCriClient.currentlyAttachedTarget.close).not.to.be.called expect(options.browserCriClient.currentlyAttachedProtocolTarget.close).not.to.be.called + expect(options.browserCriClient.currentlyAttachedCyPromptTarget.close).not.to.be.called }) it('closes the extra target client', () => { @@ -451,7 +456,7 @@ describe('lib/browsers/browser-cri-client', function () { it('creates a page client when the passed in url is found', async function () { const mockProtocolClient = {} const mockPageClient = { - clone: sinon.stub().returns(mockProtocolClient), + clone: sinon.stub().onFirstCall().returns(mockProtocolClient), } send.withArgs('Target.getTargets').resolves({ targetInfos: [{ targetId: '1', url: 'http://foo.com' }, { targetId: '2', url: 'http://bar.com' }] }) @@ -468,7 +473,7 @@ describe('lib/browsers/browser-cri-client', function () { it('creates a page client when the passed in url is found and notifies the protocol manager and fully managed tabs', async function () { const mockProtocolClient = {} const mockPageClient = { - clone: sinon.stub().returns(mockProtocolClient), + clone: sinon.stub().onFirstCall().returns(mockProtocolClient), } const protocolManager: any = { connectToBrowser: sinon.stub().resolves(), @@ -491,7 +496,7 @@ describe('lib/browsers/browser-cri-client', function () { it('creates a page client when the passed in url is found and notifies the protocol manager and fully managed tabs and attaching to target throws', async function () { const mockProtocolClient = {} const mockPageClient = { - clone: sinon.stub().returns(mockProtocolClient), + clone: sinon.stub().onFirstCall().returns(mockProtocolClient), } const protocolManager: any = { connectToBrowser: sinon.stub().resolves(), @@ -582,13 +587,28 @@ describe('lib/browsers/browser-cri-client', function () { }, } + const mockCurrentlyAttachedCyPromptTarget = { + targetId: '100', + close: sinon.stub().resolves(sinon.stub().resolves()), + queue: { + subscriptions: [{ + eventName: 'Network.requestWillBeSent', + cb: sinon.stub(), + }], + }, + } + const mockUpdatedCurrentlyAttachedProtocolTarget = { targetId: '101', } + const mockUpdatedCurrentlyAttachedCyPromptTarget = { + targetId: '101', + } + const mockUpdatedCurrentlyAttachedTarget = { targetId: '101', - clone: sinon.stub().returns(mockUpdatedCurrentlyAttachedProtocolTarget), + clone: sinon.stub().onFirstCall().returns(mockUpdatedCurrentlyAttachedProtocolTarget).onSecondCall().returns(mockUpdatedCurrentlyAttachedCyPromptTarget), } send.withArgs('Target.createTarget', { url: 'about:blank' }).resolves(mockUpdatedCurrentlyAttachedTarget) @@ -600,6 +620,7 @@ describe('lib/browsers/browser-cri-client', function () { browserClient.currentlyAttachedTarget = mockCurrentlyAttachedTarget browserClient.currentlyAttachedProtocolTarget = mockCurrentlyAttachedProtocolTarget + browserClient.currentlyAttachedCyPromptTarget = mockCurrentlyAttachedCyPromptTarget browserClient.browserClient.off = sinon.stub() await browserClient.resetBrowserTargets(true) @@ -607,8 +628,10 @@ describe('lib/browsers/browser-cri-client', function () { expect(mockCurrentlyAttachedTarget.close).to.be.called expect(browserClient.currentlyAttachedTarget).to.eql(mockUpdatedCurrentlyAttachedTarget) expect(browserClient.currentlyAttachedProtocolTarget).to.eql(mockUpdatedCurrentlyAttachedProtocolTarget) + expect(browserClient.currentlyAttachedCyPromptTarget).to.eql(mockUpdatedCurrentlyAttachedCyPromptTarget) expect(browserClient.browserClient.off).to.be.calledWith('Network.requestWillBeSent', mockCurrentlyAttachedTarget.queue.subscriptions[0].cb) expect(browserClient.browserClient.off).to.be.calledWith('Network.requestWillBeSent', mockCurrentlyAttachedProtocolTarget.queue.subscriptions[0].cb) + expect(browserClient.browserClient.off).to.be.calledWith('Network.requestWillBeSent', mockCurrentlyAttachedCyPromptTarget.queue.subscriptions[0].cb) }) it('closes the currently attached target without keeping a tab open', async function () { @@ -628,19 +651,30 @@ describe('lib/browsers/browser-cri-client', function () { }, } + const mockCurrentlyAttachedCyPromptTarget = { + targetId: '100', + close: sinon.stub().resolves(sinon.stub().resolves()), + queue: { + subscriptions: [], + }, + } + send.withArgs('Target.closeTarget', { targetId: '100' }).resolves() const browserClient = await getClient() as any browserClient.currentlyAttachedTarget = mockCurrentlyAttachedTarget browserClient.currentlyAttachedProtocolTarget = mockCurrentlyAttachedProtocolTarget + browserClient.currentlyAttachedCyPromptTarget = mockCurrentlyAttachedCyPromptTarget await browserClient.resetBrowserTargets(false) expect(mockCurrentlyAttachedTarget.close).to.be.called expect(mockCurrentlyAttachedProtocolTarget.close).to.be.called + expect(mockCurrentlyAttachedCyPromptTarget.close).to.be.called expect(browserClient.currentlyAttachedTarget).to.be.undefined expect(browserClient.currentlyAttachedProtocolTarget).to.be.undefined + expect(browserClient.currentlyAttachedCyPromptTarget).to.be.undefined }) it('throws when there is no currently attached target', async function () { @@ -688,14 +722,25 @@ describe('lib/browsers/browser-cri-client', function () { close: sinon.stub().resolves(), } + const mockCurrentlyAttachedProtocolTarget = { + close: sinon.stub().resolves(), + } + + const mockCurrentlyAttachedCyPromptTarget = { + close: sinon.stub().resolves(), + } + const browserClient = await getClient() as any browserClient.currentlyAttachedTarget = mockCurrentlyAttachedTarget + browserClient.currentlyAttachedProtocolTarget = mockCurrentlyAttachedProtocolTarget + browserClient.currentlyAttachedCyPromptTarget = mockCurrentlyAttachedCyPromptTarget await browserClient.close() expect(mockCurrentlyAttachedTarget.close).to.be.called - expect(close).to.be.called + expect(mockCurrentlyAttachedProtocolTarget.close).to.be.called + expect(mockCurrentlyAttachedCyPromptTarget.close).to.be.called }) it('just the browser client with no currently attached target', async function () { diff --git a/packages/server/test/unit/browsers/browsers_spec.js b/packages/server/test/unit/browsers/browsers_spec.js index a7ec2835070b..811e7d266434 100644 --- a/packages/server/test/unit/browsers/browsers_spec.js +++ b/packages/server/test/unit/browsers/browsers_spec.js @@ -118,6 +118,19 @@ describe('lib/browsers/index', () => { }) }) + context('.connectCyPromptToBrowser', () => { + it('connects browser to cy prompt', async () => { + sinon.stub(chrome, 'connectCyPromptToBrowser').resolves() + await browsers.connectCyPromptToBrowser({ + browser: { + family: 'chromium', + }, + }) + + expect(chrome.connectCyPromptToBrowser).to.be.called + }) + }) + context('.closeProtocolConnection', () => { it('calls close on instance', async () => { sinon.stub(chrome, 'closeProtocolConnection').resolves() diff --git a/packages/server/test/unit/browsers/chrome_spec.js b/packages/server/test/unit/browsers/chrome_spec.js index 62436c7a4670..fa4bfb73a569 100644 --- a/packages/server/test/unit/browsers/chrome_spec.js +++ b/packages/server/test/unit/browsers/chrome_spec.js @@ -665,6 +665,82 @@ describe('lib/browsers/chrome', () => { }) }) + context('#connectCyPromptToBrowser', () => { + it('connects to the browser cri client', async function () { + const cyPromptManager = { + connectToBrowser: sinon.stub().resolves(), + } + + const mockCurrentlyAttachedCyPromptTarget = {} + + const pageCriClient = { + clone: sinon.stub().returns(mockCurrentlyAttachedCyPromptTarget), + } + + const browserCriClient = { + currentlyAttachedTarget: pageCriClient, + currentlyAttachedCyPromptTarget: mockCurrentlyAttachedCyPromptTarget, + } + + sinon.stub(chrome, '_getBrowserCriClient').returns(browserCriClient) + + await chrome.connectCyPromptToBrowser({ cyPromptManager }) + + expect(pageCriClient.clone).not.to.be.called + expect(cyPromptManager.connectToBrowser).to.be.calledWith(mockCurrentlyAttachedCyPromptTarget) + }) + + it('connects to the browser cri client when the cy prompt target has not been created', async function () { + const cyPromptManager = { + connectToBrowser: sinon.stub().resolves(), + } + + const mockCurrentlyAttachedCyPromptTarget = {} + + const pageCriClient = { + clone: sinon.stub().resolves(mockCurrentlyAttachedCyPromptTarget), + } + + const browserCriClient = { + currentlyAttachedTarget: pageCriClient, + } + + sinon.stub(chrome, '_getBrowserCriClient').returns(browserCriClient) + + await chrome.connectCyPromptToBrowser({ cyPromptManager }) + + expect(pageCriClient.clone).to.be.called + expect(cyPromptManager.connectToBrowser).to.be.calledWith(mockCurrentlyAttachedCyPromptTarget) + expect(browserCriClient.currentlyAttachedCyPromptTarget).to.eq(mockCurrentlyAttachedCyPromptTarget) + }) + + it('throws error if there is no browser cri client', function () { + const cyPromptManager = { + connectToBrowser: sinon.stub().resolves(), + } + + sinon.stub(chrome, '_getBrowserCriClient').returns(null) + + expect(chrome.connectCyPromptToBrowser({ cyPromptManager })).to.be.rejectedWith('Missing pageCriClient in connectCyPromptToBrowser') + expect(cyPromptManager.connectToBrowser).not.to.be.called + }) + + it('throws error if there is no page cri client', function () { + const cyPromptManager = { + connectToBrowser: sinon.stub().resolves(), + } + + const browserCriClient = { + currentlyAttachedTarget: null, + } + + sinon.stub(chrome, '_getBrowserCriClient').returns(browserCriClient) + + expect(chrome.connectCyPromptToBrowser({ cyPromptManager })).to.be.rejectedWith('Missing pageCriClient in connectCyPromptToBrowser') + expect(cyPromptManager.connectToBrowser).not.to.be.called + }) + }) + context('#closeProtocolConnection', () => { it('closes the protocol connection', async function () { const mockCurrentlyAttachedProtocolTarget = { diff --git a/packages/server/test/unit/browsers/electron_spec.js b/packages/server/test/unit/browsers/electron_spec.js index 338db60b46d8..5c679f250d82 100644 --- a/packages/server/test/unit/browsers/electron_spec.js +++ b/packages/server/test/unit/browsers/electron_spec.js @@ -24,6 +24,10 @@ describe('lib/browsers/electron', () => { connectToBrowser: sinon.stub().resolves(), } + this.cyPromptManager = { + connectToBrowser: sinon.stub().resolves(), + } + this.url = 'https://foo.com' this.state = {} this.options = { @@ -280,6 +284,47 @@ describe('lib/browsers/electron', () => { }) }) + context('.connectCyPromptToBrowser', () => { + it('connects to the browser cri client', async function () { + const mockCurrentlyAttachedCyPromptTarget = {} + + this.browserCriClient.currentlyAttachedCyPromptTarget = mockCurrentlyAttachedCyPromptTarget + sinon.stub(electron, '_getBrowserCriClient').returns(this.browserCriClient) + + await electron.connectCyPromptToBrowser({ cyPromptManager: this.cyPromptManager }) + expect(this.pageCriClient.clone).not.to.be.called + expect(this.cyPromptManager.connectToBrowser).to.be.calledWith(mockCurrentlyAttachedCyPromptTarget) + }) + + it('connects to the browser cri client when the cy prompt target has not been created', async function () { + const mockCurrentlyAttachedCyPromptTarget = {} + + this.pageCriClient.clone.resolves(mockCurrentlyAttachedCyPromptTarget) + sinon.stub(electron, '_getBrowserCriClient').returns(this.browserCriClient) + + await electron.connectCyPromptToBrowser({ cyPromptManager: this.cyPromptManager }) + expect(this.pageCriClient.clone).to.be.called + expect(this.cyPromptManager.connectToBrowser).to.be.calledWith(mockCurrentlyAttachedCyPromptTarget) + expect(this.browserCriClient.currentlyAttachedCyPromptTarget).to.eq(mockCurrentlyAttachedCyPromptTarget) + }) + + it('throws error if there is no browser cri client', function () { + sinon.stub(electron, '_getBrowserCriClient').returns(null) + + expect(electron.connectCyPromptToBrowser({ cyPromptManager: this.cyPromptManager })).to.be.rejectedWith('Missing pageCriClient in connectCyPromptToBrowser') + expect(this.cyPromptManager.connectToBrowser).not.to.be.called + }) + + it('throws error if there is no page cri client', async function () { + this.browserCriClient.currentlyAttachedTarget = null + + sinon.stub(electron, '_getBrowserCriClient').returns(this.browserCriClient) + + expect(electron.connectCyPromptToBrowser({ cyPromptManager: this.cyPromptManager })).to.be.rejectedWith('Missing pageCriClient in connectCyPromptToBrowser') + expect(this.cyPromptManager.connectToBrowser).not.to.be.called + }) + }) + context('#closeProtocolConnection', () => { it('closes the protocol connection', async function () { const mockCurrentlyAttachedProtocolTarget = { @@ -515,7 +560,7 @@ describe('lib/browsers/electron', () => { it('registers onRequest automation middleware and calls show when requesting to be focused', function () { sinon.spy(this.automation, 'use') - return electron._launch(this.win, this.url, this.automation, this.options, undefined, undefined, { attachCDPClient: sinon.stub() }, undefined, undefined, { attachCDPClient: sinon.stub() }) + return electron._launch(this.win, this.url, this.automation, this.options, undefined, undefined, { attachCDPClient: sinon.stub() }) .then(() => { expect(this.automation.use).to.be.called expect(this.automation.use.lastCall.args[0].onRequest).to.be.a('function') diff --git a/packages/server/test/unit/browsers/firefox_spec.ts b/packages/server/test/unit/browsers/firefox_spec.ts index a7d1b76c65cc..f89a46112129 100644 --- a/packages/server/test/unit/browsers/firefox_spec.ts +++ b/packages/server/test/unit/browsers/firefox_spec.ts @@ -684,6 +684,12 @@ describe('lib/browsers/firefox', () => { }) }) + context('#connectCyPromptToBrowser', () => { + it('throws error', () => { + expect(firefox.connectCyPromptToBrowser).to.throw('CyPrompt is not yet supported in firefox.') + }) + }) + context('#closeProtocolConnection', () => { it('throws error', () => { expect(firefox.closeProtocolConnection).to.throw('Protocol is not yet supported in firefox.') diff --git a/packages/server/test/unit/browsers/webkit_spec.ts b/packages/server/test/unit/browsers/webkit_spec.ts index bff4d0f7d490..97a9f9e7994c 100644 --- a/packages/server/test/unit/browsers/webkit_spec.ts +++ b/packages/server/test/unit/browsers/webkit_spec.ts @@ -78,6 +78,14 @@ describe('lib/browsers/webkit', () => { }) }) + context('#connectCyPromptToBrowser', () => { + it('throws error', () => { + const webkit = getWebkit() + + expect(webkit.connectCyPromptToBrowser).to.throw('CyPrompt is not yet supported in WebKit.') + }) + }) + context('#closeProtocolConnection', () => { it('throws error', async () => { const webkit = getWebkit() diff --git a/packages/server/test/unit/cloud/cy-prompt/CyPromptLifecycleManager_spec.ts b/packages/server/test/unit/cloud/cy-prompt/CyPromptLifecycleManager_spec.ts index bbe38fb9beed..7f6d4df6e7e9 100644 --- a/packages/server/test/unit/cloud/cy-prompt/CyPromptLifecycleManager_spec.ts +++ b/packages/server/test/unit/cloud/cy-prompt/CyPromptLifecycleManager_spec.ts @@ -91,7 +91,7 @@ describe('CyPromptLifecycleManager', () => { }) const cyPromptReadyPromise = new Promise((resolve) => { - cyPromptLifecycleManager?.registerCyPromptReadyListener((cyPromptManager) => { + cyPromptLifecycleManager?.registerCyPromptReadyListener(async (cyPromptManager) => { resolve(cyPromptManager) }) }) diff --git a/packages/server/test/unit/cloud/cy-prompt/CyPromptManager_spec.ts b/packages/server/test/unit/cloud/cy-prompt/CyPromptManager_spec.ts index f57a98542cb9..bbf19ce91af1 100644 --- a/packages/server/test/unit/cloud/cy-prompt/CyPromptManager_spec.ts +++ b/packages/server/test/unit/cloud/cy-prompt/CyPromptManager_spec.ts @@ -52,6 +52,8 @@ describe('lib/cloud/cy-prompt', () => { cyPromptManager.initializeRoutes({} as any) expect(cyPromptManager.status).to.eq('IN_ERROR') + + // TODO: (cy.prompt) test that the error is reported }) }) @@ -63,7 +65,7 @@ describe('lib/cloud/cy-prompt', () => { await cyPromptManager.handleBackendRequest('cy:prompt:start', {} as any) - expect(cyPromptManager.status).to.eq('IN_ERROR') + // TODO: (cy.prompt) test that the error is reported }) }) @@ -99,4 +101,30 @@ describe('lib/cloud/cy-prompt', () => { expect(invokeSyncSpy).to.not.be.called }) }) + + describe('connectToBrowser', () => { + it('connects to the browser', () => { + const mockCriClient = { + send: sinon.stub().resolves(), + on: sinon.stub().resolves(), + } + + sinon.stub(cyPrompt, 'connectToBrowser') + + cyPromptManager.connectToBrowser(mockCriClient) + + expect(cyPrompt.connectToBrowser).to.be.calledWith(mockCriClient) + }) + + it('does not call connectToBrowser when cy prompt server is not defined', () => { + // Set _cyPromptServer to undefined + (cyPromptManager as any)._cyPromptServer = undefined + + const invokeSyncSpy = sinon.spy(cyPromptManager, 'invokeSync') + + cyPromptManager.connectToBrowser({} as any) + + expect(invokeSyncSpy).to.not.be.called + }) + }) }) diff --git a/packages/server/test/unit/open_project_spec.js b/packages/server/test/unit/open_project_spec.js index ad0ed0f067fb..6f7e489d569c 100644 --- a/packages/server/test/unit/open_project_spec.js +++ b/packages/server/test/unit/open_project_spec.js @@ -266,4 +266,13 @@ describe('lib/open_project', () => { expect(browsers.connectProtocolToBrowser).to.be.calledWith(options) }) }) + + context('#connectCyPromptToBrowser', () => { + it('connects cy prompt to browser', async () => { + sinon.stub(browsers, 'connectCyPromptToBrowser').resolves() + const options = sinon.stub() + + await openProject.connectCyPromptToBrowser(options) + }) + }) }) diff --git a/packages/server/test/unit/project_spec.js b/packages/server/test/unit/project_spec.js index 244460e45e03..8f3477b3365d 100644 --- a/packages/server/test/unit/project_spec.js +++ b/packages/server/test/unit/project_spec.js @@ -477,18 +477,6 @@ This option will not have an effect in Some-other-name. Tests that rely on web s expect(CyPromptLifecycleManager.prototype.initializeCyPromptManager).not.to.be.called }) }) - - it('does not initialize cy prompt lifecycle manager if projectId is not set', function () { - this.config.projectId = undefined - this.config.experimentalPromptCommand = true - - sinon.stub(CyPromptLifecycleManager.prototype, 'initializeCyPromptManager') - - return this.project.open() - .then(() => { - expect(CyPromptLifecycleManager.prototype.initializeCyPromptManager).not.to.be.called - }) - }) }) describe('saved state', function () { @@ -1039,6 +1027,40 @@ This option will not have an effect in Some-other-name. Tests that rely on web s expect(protocolManager.close).to.have.been.calledOnce expect(this.project['_protocolManager']).to.be.undefined }) + + it('passes onCyPromptReady callback', async function () { + const mockCyPromptManager = { + foo: 'bar', + } + + // Create a browser object + this.project.browser = { + name: 'chrome', + family: 'chromium', + } + + this.project.options = { browsers: [this.project.browser] } + + sinon.stub(browsers, 'connectCyPromptToBrowser') + + // Modify the startWebsockets stub to track the callbacks + const callbackPromise = new Promise((resolve) => { + this.project.server.startWebsockets.callsFake(async (automation, config, callbacks) => { + await callbacks.onCyPromptReady(mockCyPromptManager) + resolve() + }) + }) + + this.project.startWebsockets({}, {}) + + await callbackPromise + + expect(browsers.connectCyPromptToBrowser).to.have.been.calledWith({ + browser: this.project.browser, + foundBrowsers: this.project.options.browsers, + cyPromptManager: mockCyPromptManager, + }) + }) }) context('#getProjectId', () => { diff --git a/packages/server/test/unit/socket_spec.js b/packages/server/test/unit/socket_spec.js index e22b260b9774..ec2d3878202b 100644 --- a/packages/server/test/unit/socket_spec.js +++ b/packages/server/test/unit/socket_spec.js @@ -66,6 +66,7 @@ describe('lib/socket', () => { onSavedStateChanged: sinon.spy(), onStudioInit: sinon.stub(), onStudioDestroy: sinon.stub(), + onCyPromptReady: sinon.stub(), } this.automation = new Automation({ @@ -558,6 +559,8 @@ describe('lib/socket', () => { return this.client.emit('backend:request', 'wait:for:cy:prompt:ready', (resp) => { expect(resp.response).to.deep.eq({ success: true }) + expect(this.options.onCyPromptReady).to.be.calledWith(mockCyPrompt) + return done() }) }) @@ -578,25 +581,25 @@ describe('lib/socket', () => { }) context('on(backend:request, cy:prompt)', () => { - it('calls handleBackendRequest with the correct arguments', function (done) { + it('calls handleBackendRequest with the correct arguments', async function () { // Verify that registerCyPromptReadyListener was called expect(ctx.coreData.cyPromptLifecycleManager.registerCyPromptReadyListener).to.be.called // Check that the callback was called with the mock cy prompt object const registerCyPromptReadyListenerCallback = ctx.coreData.cyPromptLifecycleManager.registerCyPromptReadyListener.firstCall.args[0] - expect(registerCyPromptReadyListenerCallback).to.be.a('function') - // Verify the mock cy prompt's handleBackendRequest was called by the callback const mockCyPrompt = { handleBackendRequest: sinon.stub().resolves({ foo: 'bar' }) } - registerCyPromptReadyListenerCallback(mockCyPrompt) + await registerCyPromptReadyListenerCallback(mockCyPrompt) - return this.client.emit('backend:request', 'cy:prompt:init', 'foo', (resp) => { - expect(resp.response).to.deep.eq({ foo: 'bar' }) - expect(mockCyPrompt.handleBackendRequest).to.be.calledWith('cy:prompt:init', 'foo') + await new Promise((resolve) => { + this.client.emit('backend:request', 'cy:prompt:init', 'foo', (resp) => { + expect(resp.response).to.deep.eq({ foo: 'bar' }) + expect(mockCyPrompt.handleBackendRequest).to.be.calledWith('cy:prompt:init', 'foo') - return done() + resolve() + }) }) }) }) diff --git a/packages/types/src/cy-prompt/cy-prompt-server-types.ts b/packages/types/src/cy-prompt/cy-prompt-server-types.ts index 8e6cdd83fb3b..be0df63c42ad 100644 --- a/packages/types/src/cy-prompt/cy-prompt-server-types.ts +++ b/packages/types/src/cy-prompt/cy-prompt-server-types.ts @@ -4,9 +4,18 @@ /// +import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping.d' import type { Router } from 'express' import type { AxiosInstance } from 'axios' +export type CyPromptCommands = ProtocolMapping.Commands + +export type CyPromptCommand = CyPromptCommands[T] + +export type CyPromptEvents = ProtocolMapping.Events + +export type CyPromptEvent = CyPromptEvents[T] + interface RetryOptions { maxAttempts: number retryDelay?: (attempt: number) => number @@ -34,9 +43,21 @@ export interface CyPromptServerOptions { cloudApi: CyPromptCloudApi } +export interface CyPromptCDPClient { + send>( + command: T, + params?: CyPromptCommand['paramsType'][0] + ): Promise['returnType']> + on>( + eventName: T, + cb: (event: CyPromptEvent[0]) => void | Promise + ): void +} + export interface CyPromptServerShape { initializeRoutes(router: Router): void handleBackendRequest: (eventName: string, ...args: any[]) => Promise + connectToBrowser: (cdpClient: CyPromptCDPClient) => void } export interface CyPromptServerDefaultShape { diff --git a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json index 39dd8c01fafb..49e2fbfc1cb3 100644 --- a/tooling/v8-snapshot/cache/darwin/snapshot-meta.json +++ b/tooling/v8-snapshot/cache/darwin/snapshot-meta.json @@ -1052,6 +1052,8 @@ "./node_modules/@cypress/commit-info/src/index.js", "./node_modules/@cypress/commit-info/src/utils.js", "./node_modules/@cypress/get-windows-proxy/node_modules/debug/src/common.js", + "./node_modules/@cypress/get-windows-proxy/node_modules/registry-js/dist/lib/index.js", + "./node_modules/@cypress/get-windows-proxy/node_modules/registry-js/dist/lib/registry.js", "./node_modules/@cypress/get-windows-proxy/src/index.js", "./node_modules/@cypress/parse-domain/build/tries/icann.complete.json", "./node_modules/@cypress/parse-domain/build/tries/private.complete.json", @@ -3183,6 +3185,8 @@ "./node_modules/recast/parsers/babel.js", "./node_modules/recast/parsers/esprima.js", "./node_modules/recast/parsers/typescript.js", + "./node_modules/registry-js/dist/lib/index.js", + "./node_modules/registry-js/dist/lib/registry.js", "./node_modules/request-promise-core/configure/request2.js", "./node_modules/request-promise-core/errors.js", "./node_modules/request-promise-core/lib/errors.js", @@ -3854,6 +3858,8 @@ "./packages/server/lib/browsers/webkit.ts", "./packages/server/lib/cloud/api/axios_middleware/logging.ts", "./packages/server/lib/cloud/api/axios_middleware/transform_error.ts", + "./packages/server/lib/cloud/api/cy-prompt/get_cy_prompt_bundle.ts", + "./packages/server/lib/cloud/api/cy-prompt/post_cy_prompt_session.ts", "./packages/server/lib/cloud/api/scrub_url.ts", "./packages/server/lib/cloud/api/studio/get_studio_bundle.ts", "./packages/server/lib/cloud/api/studio/post_studio_session.ts", @@ -3863,6 +3869,9 @@ "./packages/server/lib/cloud/artifacts/print_protocol_upload_error.ts", "./packages/server/lib/cloud/artifacts/upload_artifacts.ts", "./packages/server/lib/cloud/constants.ts", + "./packages/server/lib/cloud/cy-prompt/CyPromptLifecycleManager.ts", + "./packages/server/lib/cloud/cy-prompt/CyPromptManager.ts", + "./packages/server/lib/cloud/cy-prompt/ensure_cy_prompt_bundle.ts", "./packages/server/lib/cloud/encryption.ts", "./packages/server/lib/cloud/environment.ts", "./packages/server/lib/cloud/get_cloud_metadata.ts", @@ -4167,6 +4176,8 @@ "./packages/types/src/cloud.ts", "./packages/types/src/config.ts", "./packages/types/src/constants.ts", + "./packages/types/src/cy-prompt/cy-prompt-server-types.ts", + "./packages/types/src/cy-prompt/index.ts", "./packages/types/src/driver.ts", "./packages/types/src/editors.ts", "./packages/types/src/git.ts",