diff --git a/packages/launcher/lib/browsers.ts b/packages/launcher/lib/browsers.ts index e7b9b466edd4..821cda74a7b4 100644 --- a/packages/launcher/lib/browsers.ts +++ b/packages/launcher/lib/browsers.ts @@ -97,7 +97,6 @@ export function launch ( browser: FoundBrowser, url: string, args: string[] = [], - opts: { pipeStdio?: boolean } = {}, ) { log('launching browser %o', { browser, url }) @@ -111,15 +110,7 @@ export function launch ( log('spawning browser with args %o', { args }) - const stdio = ['ignore', 'pipe', 'pipe'] - - if (opts.pipeStdio) { - // also pipe stdio 3 and 4 for access to debugger protocol - stdio.push('pipe', 'pipe') - } - - // @ts-ignore - const proc = cp.spawn(browser.path, args, { stdio }) + const proc = cp.spawn(browser.path, args, { stdio: ['ignore', 'pipe', 'pipe'] }) proc.stdout.on('data', (buf) => { log('%s stdout: %s', browser.name, String(buf).trim()) diff --git a/packages/server/__snapshots__/5_cdp_spec.ts.js b/packages/server/__snapshots__/5_cdp_spec.ts.js index 82cd998b06f9..6c378afb74dc 100644 --- a/packages/server/__snapshots__/5_cdp_spec.ts.js +++ b/packages/server/__snapshots__/5_cdp_spec.ts.js @@ -1,4 +1,4 @@ -exports['e2e cdp / with TCP transport / handles disconnections as expected'] = ` +exports['e2e cdp / handles disconnections as expected'] = ` ==================================================================================================== @@ -59,67 +59,4 @@ Error: connect ECONNREFUSED 127.0.0.1:7777 ✖ 1 of 1 failed (100%) XX:XX - - 1 - - -` - -exports['e2e cdp / with stdio transport / falls back to connecting via tcp when stdio cannot be connected'] = ` - -==================================================================================================== - - (Run Starting) - - ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Cypress: 1.2.3 │ - │ Browser: FooBrowser 88 │ - │ Specs: 1 found (spec.ts) │ - │ Searched: cypress/integration/spec.ts │ - └────────────────────────────────────────────────────────────────────────────────────────────────┘ - - -──────────────────────────────────────────────────────────────────────────────────────────────────── - - Running: spec.ts (1 of 1) -Warning: Cypress failed to connect to Chrome via stdio after 1 second. Falling back to TCP... -Connecting to Chrome via TCP was successful, continuing with tests. - - - passes - ✓ passes - - - 1 passing - - - (Results) - - ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Tests: 1 │ - │ Passing: 1 │ - │ Failing: 0 │ - │ Pending: 0 │ - │ Skipped: 0 │ - │ Screenshots: 0 │ - │ Video: true │ - │ Duration: X seconds │ - │ Spec Ran: spec.ts │ - └────────────────────────────────────────────────────────────────────────────────────────────────┘ - - - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/spec.ts.mp4 (X second) - - -==================================================================================================== - - (Run Finished) - - - Spec Tests Passing Failing Pending Skipped - ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ ✔ spec.ts XX:XX 1 1 - - - │ - └────────────────────────────────────────────────────────────────────────────────────────────────┘ - ✔ All specs passed! XX:XX 1 1 - - - - - -` +` \ No newline at end of file diff --git a/packages/server/lib/browsers/chrome.ts b/packages/server/lib/browsers/chrome.ts index 373aa0c9110e..f1f815c48cb2 100644 --- a/packages/server/lib/browsers/chrome.ts +++ b/packages/server/lib/browsers/chrome.ts @@ -15,7 +15,6 @@ import * as CriClient from './cri-client' import * as protocol from './protocol' import utils from './utils' import { Browser } from './types' -import errors from '../errors' // TODO: this is defined in `cypress-npm-api` but there is currently no way to get there type CypressConfiguration = any @@ -38,9 +37,6 @@ type ChromePreferences = { localState: object } -const staticCdpPort = Number(process.env.CYPRESS_REMOTE_DEBUGGING_PORT) -const stdioTimeoutMs = Number(process.env.CYPRESS_CDP_TARGET_TIMEOUT) || 60000 - const pathToExtension = extension.getPathToExtension() const pathToTheme = extension.getPathToTheme() @@ -177,7 +173,9 @@ const _writeChromePreferences = (userDir: string, originalPrefs: ChromePreferenc } const getRemoteDebuggingPort = async () => { - return staticCdpPort || utils.getPort() + const port = Number(process.env.CYPRESS_REMOTE_DEBUGGING_PORT) + + return port || utils.getPort() } /** @@ -245,47 +243,19 @@ const _disableRestorePagesPrompt = function (userDir) { .catch(() => { }) } -const useStdioCdp = (browser) => { - return ( - // CDP via stdio doesn't seem to work in browsers older than 72 - // @see https://github.com/cyrus-and/chrome-remote-interface/issues/381#issuecomment-445277683 - browser.majorVersion >= 72 - // allow users to force TCP by specifying a port in environment - && !staticCdpPort - ) -} - // After the browser has been opened, we can connect to // its remote interface via a websocket. -const _connectToChromeRemoteInterface = function (browser, process, port, onError) { - const connectTcp = () => { - // @ts-ignore - la(check.userPort(port), 'expected port number to connect CRI to', port) - - debug('connecting to Chrome remote interface at random port %d', port) - - return protocol.getWsTargetFor(port) - .then((wsUrl) => { - debug('received wsUrl %s for port %d', wsUrl, port) - - return CriClient.create({ target: wsUrl }, onError) - }) - } - - if (!useStdioCdp(browser)) { - return connectTcp() - } - - return CriClient.create({ process }, onError) - .timeout(stdioTimeoutMs) - .catch(Bluebird.TimeoutError, async () => { - errors.warning('CDP_STDIO_TIMEOUT', browser.displayName, stdioTimeoutMs) +const _connectToChromeRemoteInterface = function (port, onError) { + // @ts-ignore + la(check.userPort(port), 'expected port number to connect CRI to', port) - const client = await connectTcp() + debug('connecting to Chrome remote interface at random port %d', port) - errors.warning('CDP_FALLBACK_SUCCEEDED', browser.displayName) + return protocol.getWsTargetFor(port) + .then((wsUrl) => { + debug('received wsUrl %s for port %d', wsUrl, port) - return client + return CriClient.create(wsUrl, onError) }) } @@ -465,10 +435,6 @@ export = { args.push(`--remote-debugging-port=${port}`) args.push('--remote-debugging-address=127.0.0.1') - if (useStdioCdp(browser)) { - args.push('--remote-debugging-pipe') - } - return args }, @@ -524,16 +490,14 @@ export = { // first allows us to connect the remote interface, // start video recording and then // we will load the actual page - const launchedBrowser = await utils.launch(browser, 'about:blank', args, { - pipeStdio: useStdioCdp(browser), - }) + const launchedBrowser = await utils.launch(browser, 'about:blank', args) la(launchedBrowser, 'did not get launched browser instance') // SECOND connect to the Chrome remote interface // and when the connection is ready // navigate to the actual url - const criClient = await this._connectToChromeRemoteInterface(browser, launchedBrowser, port, options.onError) + const criClient = await this._connectToChromeRemoteInterface(port, options.onError) la(criClient, 'expected Chrome remote interface reference', criClient) diff --git a/packages/server/lib/browsers/cri-client.ts b/packages/server/lib/browsers/cri-client.ts index eb1e64a22477..4d44ad710efc 100644 --- a/packages/server/lib/browsers/cri-client.ts +++ b/packages/server/lib/browsers/cri-client.ts @@ -1,7 +1,6 @@ import Bluebird from 'bluebird' import debugModule from 'debug' import _ from 'lodash' -import { ChildProcess } from 'child_process' const chromeRemoteInterface = require('chrome-remote-interface') const errors = require('../errors') @@ -86,40 +85,41 @@ const getMajorMinorVersion = (version: string): Version => { const maybeDebugCdpMessages = (cri) => { if (debugVerboseReceive.enabled) { - const handleMessage = cri._handleMessage - - cri._handleMessage = (message) => { - const formatted = _.cloneDeep(message) - - ;([ - 'params.data', // screencast frame data - 'result.data', // screenshot data - ]).forEach((truncatablePath) => { - const str = _.get(formatted, truncatablePath) + cri._ws.on('message', (data) => { + data = _ + .chain(JSON.parse(data)) + .tap((data) => { + ([ + 'params.data', // screencast frame data + 'result.data', // screenshot data + ]).forEach((truncatablePath) => { + const str = _.get(data, truncatablePath) + + if (!_.isString(str)) { + return + } - if (!_.isString(str)) { - return - } + _.set(data, truncatablePath, _.truncate(str, { + length: 100, + omission: `... [truncated string of total bytes: ${str.length}]`, + })) + }) - _.set(formatted, truncatablePath, _.truncate(str, { - length: 100, - omission: `... [truncated string of total bytes: ${str.length}]`, - })) + return data }) + .value() - debugVerboseReceive('received CDP message %o', formatted) - - return handleMessage.call(cri, message) - } + debugVerboseReceive('received CDP message %o', data) + }) } if (debugVerboseSend.enabled) { - const send = cri._send + const send = cri._ws.send - cri._send = (data, callback) => { + cri._ws.send = (data, callback) => { debugVerboseSend('sending CDP command %o', JSON.parse(data)) - return send.call(cri, data, callback) + return send.call(cri._ws, data, callback) } } } @@ -135,36 +135,17 @@ export { chromeRemoteInterface } type DeferredPromise = { resolve: Function, reject: Function } -type CreateOpts = { - target?: websocketUrl - process?: ChildProcess -} - -type Message = { - method: CRI.Command - params?: any - sessionId?: string -} - -export const create = Bluebird.method((opts: CreateOpts, onAsynchronousError: Function): Bluebird => { +export const create = Bluebird.method((target: websocketUrl, onAsynchronousError: Function): Bluebird => { const subscriptions: {eventName: CRI.EventName, cb: Function}[] = [] - let enqueuedCommands: {message: Message, params: any, p: DeferredPromise }[] = [] + let enqueuedCommands: {command: CRI.Command, params: any, p: DeferredPromise }[] = [] let closed = false // has the user called .close on this? let connected = false // is this currently connected to CDP? let cri let client: CRIWrapper - let sessionId: string | undefined const reconnect = () => { - if (opts.process) { - // reconnecting doesn't make sense for stdio - onAsynchronousError(errors.get('CDP_STDIO_ERROR')) - - return - } - debug('disconnected, attempting to reconnect... %o', { closed }) connected = false @@ -181,7 +162,7 @@ export const create = Bluebird.method((opts: CreateOpts, onAsynchronousError: Fu }) enqueuedCommands.forEach((cmd) => { - cri.sendRaw(cmd.message) + cri.send(cmd.command, cmd.params) .then(cmd.p.resolve, cmd.p.reject) }) @@ -195,10 +176,10 @@ export const create = Bluebird.method((opts: CreateOpts, onAsynchronousError: Fu const connect = () => { cri?.close() - debug('connecting %o', opts) + debug('connecting %o', { target }) return chromeRemoteInterface({ - ...opts, + target, local: true, }) .then((newCri) => { @@ -212,46 +193,6 @@ export const create = Bluebird.method((opts: CreateOpts, onAsynchronousError: Fu // @see https://github.com/cyrus-and/chrome-remote-interface/issues/72 cri._notifier.on('disconnect', reconnect) - - if (opts.process) { - // if using stdio, we need to find the target before declaring the connection complete - return findTarget() - } - - return - }) - } - - const findTarget = () => { - debug('finding CDP target...') - - return new Bluebird((resolve, reject) => { - const isAboutBlank = (target) => target.type === 'page' && target.url === 'about:blank' - - const attachToTarget = _.once(({ targetId }) => { - debug('attaching to target %o', { targetId }) - cri.send('Target.attachToTarget', { - targetId, - flatten: true, // enable selecting via sessionId - }).then((result) => { - debug('attached to target %o', result) - sessionId = result.sessionId - resolve() - }).catch(reject) - }) - - cri.send('Target.setDiscoverTargets', { discover: true }) - .then(() => { - cri.on('Target.targetCreated', (target) => { - if (isAboutBlank(target)) { - attachToTarget(target) - } - }) - - return cri.send('Target.getTargets') - .then(({ targetInfos }) => targetInfos.filter(isAboutBlank).map(attachToTarget)) - }) - .catch(reject) }) } @@ -281,23 +222,14 @@ export const create = Bluebird.method((opts: CreateOpts, onAsynchronousError: Fu ensureMinimumProtocolVersion, getProtocolVersion, send: Bluebird.method((command: CRI.Command, params?: object) => { - const message: Message = { - method: command, - params, - } - - if (sessionId) { - message.sessionId = sessionId - } - const enqueue = () => { return new Bluebird((resolve, reject) => { - enqueuedCommands.push({ message, params, p: { resolve, reject } }) + enqueuedCommands.push({ command, params, p: { resolve, reject } }) }) } if (connected) { - return cri.sendRaw(message) + return cri.send(command, params) .catch((err) => { if (!WEBSOCKET_NOT_OPEN_RE.test(err.message)) { throw err diff --git a/packages/server/lib/errors.js b/packages/server/lib/errors.js index ae44fd6c26ad..4c4d305e54f2 100644 --- a/packages/server/lib/errors.js +++ b/packages/server/lib/errors.js @@ -5,7 +5,6 @@ const chalk = require('chalk') const AU = require('ansi_up') const Promise = require('bluebird') const { stripIndent } = require('./util/strip_indent') -const humanTime = require('./util/human_time') const ansi_up = new AU.default @@ -857,12 +856,6 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) { There was an error reconnecting to the Chrome DevTools protocol. Please restart the browser. ${arg1.stack}` - case 'CDP_STDIO_ERROR': - return 'The connection between Cypress and Chrome has unexpectedly ended. Please restart the browser.' - case 'CDP_STDIO_TIMEOUT': - return `Warning: Cypress failed to connect to ${arg1} via stdio after ${humanTime.long(arg2)}. Falling back to TCP...` - case 'CDP_FALLBACK_SUCCEEDED': - return `Connecting to ${arg1} via TCP was successful, continuing with tests.` case 'CDP_RETRYING_CONNECTION': return `Failed to connect to Chrome, retrying in 1 second (attempt ${chalk.yellow(arg1)}/62)` case 'DEPRECATED_BEFORE_BROWSER_LAUNCH_ARGS': diff --git a/packages/server/package.json b/packages/server/package.json index a81223be2895..ac776a69982b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -39,7 +39,7 @@ "chalk": "2.4.2", "check-more-types": "2.24.0", "chokidar": "3.2.2", - "chrome-remote-interface": "cypress-io/chrome-remote-interface#147192810f29951cd96c5e406495e9b4d740ba95", + "chrome-remote-interface": "0.28.2", "cli-table3": "0.5.1", "coffeescript": "1.12.7", "color-string": "1.5.4", diff --git a/packages/server/test/e2e/5_cdp_spec.ts b/packages/server/test/e2e/5_cdp_spec.ts index 677c7d744ea6..c80af4680e13 100644 --- a/packages/server/test/e2e/5_cdp_spec.ts +++ b/packages/server/test/e2e/5_cdp_spec.ts @@ -4,61 +4,36 @@ import Fixtures from '../support/helpers/fixtures' describe('e2e cdp', function () { e2e.setup() + let restoreEnv: Function - context('with TCP transport', function () { - let restoreEnv: Function - - beforeEach(() => { - restoreEnv = mockedEnv({ - CYPRESS_REMOTE_DEBUGGING_PORT: '7777', - }) - }) - - afterEach(() => { - restoreEnv() - }) - - // NOTE: this test takes almost a minute and is largely redundant with protocol_spec - e2e.it.skip('fails when remote debugging port cannot be connected to', { - project: Fixtures.projectPath('remote-debugging-port-removed'), - spec: 'spec.ts', - browser: 'chrome', - expectedExitCode: 1, + beforeEach(() => { + restoreEnv = mockedEnv({ + CYPRESS_REMOTE_DEBUGGING_PORT: '7777', }) + }) - // https://github.com/cypress-io/cypress/issues/5685 - e2e.it('handles disconnections as expected', { - project: Fixtures.projectPath('remote-debugging-disconnect'), - spec: 'spec.ts', - browser: 'chrome', - expectedExitCode: 1, - snapshot: true, - onStdout: (stdout) => { - // the location of this warning is non-deterministic - return stdout.replace('The automation client disconnected. Cannot continue running tests.\n', '') - }, - }) + afterEach(() => { + restoreEnv() }) - // @see https://github.com/cypress-io/cypress/pull/14348 - context('with stdio transport', function () { - e2e.it('can run tests in chrome even with remote-debugging-port omitted', { - project: Fixtures.projectPath('remote-debugging-port-removed'), - spec: 'spec.ts', - browser: 'chrome', - expectedExitCode: 0, - }) + // NOTE: this test takes almost a minute and is largely redundant with protocol_spec + e2e.it.skip('fails when remote debugging port cannot be connected to', { + project: Fixtures.projectPath('remote-debugging-port-removed'), + spec: 'spec.ts', + browser: 'chrome', + expectedExitCode: 1, + }) - e2e.it('falls back to connecting via tcp when stdio cannot be connected', { - project: Fixtures.projectPath('remote-debugging-port-removed'), - processEnv: { - CY_REMOVE_PIPE: '1', - CYPRESS_CDP_TARGET_TIMEOUT: '1000', - }, - spec: 'spec.ts', - browser: 'chrome', - expectedExitCode: 0, - snapshot: true, - }) + // https://github.com/cypress-io/cypress/issues/5685 + e2e.it('handles disconnections as expected', { + project: Fixtures.projectPath('remote-debugging-disconnect'), + spec: 'spec.ts', + browser: 'chrome', + expectedExitCode: 1, + snapshot: true, + onStdout: (stdout) => { + // the location of this warning is non-deterministic + return stdout.replace('The automation client disconnected. Cannot continue running tests.\n', '') + }, }) }) diff --git a/packages/server/test/support/fixtures/projects/remote-debugging-port-removed/cypress/plugins.js b/packages/server/test/support/fixtures/projects/remote-debugging-port-removed/cypress/plugins.js index 244534b11503..bcc725e90a00 100644 --- a/packages/server/test/support/fixtures/projects/remote-debugging-port-removed/cypress/plugins.js +++ b/packages/server/test/support/fixtures/projects/remote-debugging-port-removed/cypress/plugins.js @@ -4,10 +4,8 @@ module.exports = (on) => { on('before:browser:launch', (browser = {}, options) => { la(browser.family === 'chromium', 'this test can only be run with a chromium-family browser') - const cdpArg = process.env.CY_REMOVE_PIPE ? '--remote-debugging-pipe' : '--remote-debugging-port' - - // remove debugging pipe or port so that the browser connection fails - const newArgs = options.args.filter((arg) => !arg.startsWith(cdpArg)) + // remove debugging port so that the browser connection fails + const newArgs = options.args.filter((arg) => !arg.startsWith('--remote-debugging-port=')) la(newArgs.length === options.args.length - 1, 'exactly one argument should have been removed') diff --git a/packages/server/test/unit/browsers/cri-client_spec.ts b/packages/server/test/unit/browsers/cri-client_spec.ts index c584d85b7a4e..eeb45bcfb520 100644 --- a/packages/server/test/unit/browsers/cri-client_spec.ts +++ b/packages/server/test/unit/browsers/cri-client_spec.ts @@ -11,39 +11,32 @@ describe('lib/browsers/cri-client', function () { create: typeof create } let send: sinon.SinonStub - let sendRaw: sinon.SinonStub - let criStub: any let criImport: sinon.SinonStub let onError: sinon.SinonStub - let getClient: (opts?: any) => ReturnType + let getClient: () => ReturnType beforeEach(function () { sinon.stub(Bluebird, 'promisify').returnsArg(0) send = sinon.stub() - sendRaw = sinon.stub() onError = sinon.stub() - criStub = { - send, - sendRaw, - on: sinon.stub(), - close: sinon.stub(), - _notifier: new EventEmitter(), - } - criImport = sinon.stub() .withArgs({ target: DEBUGGER_URL, local: true, }) - .resolves(criStub) + .resolves({ + send, + close: sinon.stub(), + _notifier: new EventEmitter(), + }) criClient = proxyquire('../lib/browsers/cri-client', { 'chrome-remote-interface': criImport, }) - getClient = (opts = { target: DEBUGGER_URL }) => criClient.create(opts, onError) + getClient = () => criClient.create(DEBUGGER_URL, onError) }) context('.create', function () { @@ -53,65 +46,19 @@ describe('lib/browsers/cri-client', function () { expect(client.send).to.be.instanceOf(Function) }) - context('with process', function () { - let process: any - - beforeEach(function () { - process = { /** stubbed */} - - criImport.withArgs({ - process, - local: true, - }) - .resolves(criStub) - }) - - it('finds and attaches to target and persists sessionId', async function () { - const target = { - targetId: 'good', - type: 'page', - url: 'about:blank', - } - - const otherTarget = { - targetId: 'bad', - } - - send - .withArgs('Target.setDiscoverTargets').resolves() - .withArgs('Target.getTargets').resolves({ targetInfos: [otherTarget, target] }) - .withArgs('Target.attachToTarget', { targetId: 'good', flatten: true }).resolves({ sessionId: 'session-1' }) - - sendRaw.resolves() - - const client = await getClient({ process }) - - await client.send('Browser.getVersion') - - expect(sendRaw).to.be.calledWith({ - method: 'Browser.getVersion', - params: undefined, - sessionId: 'session-1', - }) - }) - }) - context('#send', function () { - it('calls cri.sendRaw with command and data', async function () { - sendRaw.resolves() + it('calls cri.send with command and data', async function () { + send.resolves() const client = await getClient() client.send('Browser.getVersion', { baz: 'quux' }) - expect(sendRaw).to.be.calledWith({ - method: 'Browser.getVersion', - params: { baz: 'quux' }, - }) + expect(send).to.be.calledWith('Browser.getVersion', { baz: 'quux' }) }) - it('rejects if cri.sendRaw rejects', async function () { + it('rejects if cri.send rejects', async function () { const err = new Error - sendRaw.rejects(err) + send.rejects(err) const client = await getClient() await expect(client.send('Browser.getVersion', { baz: 'quux' })) @@ -127,14 +74,14 @@ describe('lib/browsers/cri-client', function () { it(`with '${msg}'`, async function () { const err = new Error(msg) - sendRaw.onFirstCall().rejects(err) - sendRaw.onSecondCall().resolves() + send.onFirstCall().rejects(err) + send.onSecondCall().resolves() const client = await getClient() await client.send('Browser.getVersion', { baz: 'quux' }) - expect(sendRaw).to.be.calledTwice + expect(send).to.be.calledTwice }) }) }) @@ -143,10 +90,7 @@ describe('lib/browsers/cri-client', function () { context('#ensureMinimumProtocolVersion', function () { function withProtocolVersion (actual, test) { if (actual) { - sendRaw.withArgs({ - method: 'Browser.getVersion', - params: undefined, - }) + send.withArgs('Browser.getVersion') .resolves({ protocolVersion: actual }) } diff --git a/yarn.lock b/yarn.lock index 495c690e3f53..df920f173ef5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10415,6 +10415,14 @@ chrome-har-capturer@0.13.4: chrome-remote-interface "^0.25.7" commander "2.x.x" +chrome-remote-interface@0.28.2: + version "0.28.2" + resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.28.2.tgz#6be3554d2c227ff07eb74baa7e5d4911da12a5a6" + integrity sha512-F7mjof7rWvRNsJqhVXuiFU/HWySCxTA9tzpLxUJxVfdLkljwFJ1aMp08AnwXRmmP7r12/doTDOMwaNhFCJsacw== + dependencies: + commander "2.11.x" + ws "^7.2.0" + chrome-remote-interface@^0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.25.7.tgz#827e85fbef3cc561a9ef2404eb7eee355968c5bc" @@ -10423,13 +10431,6 @@ chrome-remote-interface@^0.25.7: commander "2.11.x" ws "3.3.x" -chrome-remote-interface@cypress-io/chrome-remote-interface#147192810f29951cd96c5e406495e9b4d740ba95: - version "0.28.2" - resolved "https://codeload.github.com/cypress-io/chrome-remote-interface/tar.gz/147192810f29951cd96c5e406495e9b4d740ba95" - dependencies: - commander "2.11.x" - ws "^7.2.0" - chrome-trace-event@^1.0.0, chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"