mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-07 23:40:21 -05:00
fix: use stdio for CDP instead of TCP (#14348)
This commit is contained in:
@@ -97,6 +97,7 @@ export function launch (
|
||||
browser: FoundBrowser,
|
||||
url: string,
|
||||
args: string[] = [],
|
||||
opts: { pipeStdio?: boolean } = {},
|
||||
) {
|
||||
log('launching browser %o', { browser, url })
|
||||
|
||||
@@ -110,7 +111,15 @@ export function launch (
|
||||
|
||||
log('spawning browser with args %o', { args })
|
||||
|
||||
const proc = cp.spawn(browser.path, args, { stdio: ['ignore', 'pipe', 'pipe'] })
|
||||
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 })
|
||||
|
||||
proc.stdout.on('data', (buf) => {
|
||||
log('%s stdout: %s', browser.name, String(buf).trim())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
exports['e2e cdp / handles disconnections as expected'] = `
|
||||
exports['e2e cdp / with TCP transport / handles disconnections as expected'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
@@ -59,4 +59,67 @@ 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 - - -
|
||||
|
||||
|
||||
`
|
||||
|
||||
@@ -13,6 +13,7 @@ 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
|
||||
@@ -35,6 +36,9 @@ 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()
|
||||
|
||||
@@ -171,9 +175,7 @@ const _writeChromePreferences = (userDir: string, originalPrefs: ChromePreferenc
|
||||
}
|
||||
|
||||
const getRemoteDebuggingPort = async () => {
|
||||
const port = Number(process.env.CYPRESS_REMOTE_DEBUGGING_PORT)
|
||||
|
||||
return port || utils.getPort()
|
||||
return staticCdpPort || utils.getPort()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,19 +243,47 @@ 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 (port, onError) {
|
||||
// @ts-ignore
|
||||
la(check.userPort(port), 'expected port number to connect CRI to', port)
|
||||
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)
|
||||
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 protocol.getWsTargetFor(port)
|
||||
.then((wsUrl) => {
|
||||
debug('received wsUrl %s for port %d', wsUrl, port)
|
||||
|
||||
return CriClient.create(wsUrl, onError)
|
||||
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 client = await connectTcp()
|
||||
|
||||
errors.warning('CDP_FALLBACK_SUCCEEDED', browser.displayName)
|
||||
|
||||
return client
|
||||
})
|
||||
}
|
||||
|
||||
@@ -405,6 +435,10 @@ 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
|
||||
},
|
||||
|
||||
@@ -460,14 +494,16 @@ 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)
|
||||
const launchedBrowser = await utils.launch(browser, 'about:blank', args, {
|
||||
pipeStdio: useStdioCdp(browser),
|
||||
})
|
||||
|
||||
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(port, options.onError)
|
||||
const criClient = await this._connectToChromeRemoteInterface(browser, launchedBrowser, port, options.onError)
|
||||
|
||||
la(criClient, 'expected Chrome remote interface reference', criClient)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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')
|
||||
@@ -82,41 +83,40 @@ const getMajorMinorVersion = (version: string): Version => {
|
||||
|
||||
const maybeDebugCdpMessages = (cri) => {
|
||||
if (debugVerboseReceive.enabled) {
|
||||
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)
|
||||
const handleMessage = cri._handleMessage
|
||||
|
||||
if (!_.isString(str)) {
|
||||
return
|
||||
}
|
||||
cri._handleMessage = (message) => {
|
||||
const formatted = _.cloneDeep(message)
|
||||
|
||||
_.set(data, truncatablePath, _.truncate(str, {
|
||||
length: 100,
|
||||
omission: `... [truncated string of total bytes: ${str.length}]`,
|
||||
}))
|
||||
})
|
||||
;([
|
||||
'params.data', // screencast frame data
|
||||
'result.data', // screenshot data
|
||||
]).forEach((truncatablePath) => {
|
||||
const str = _.get(formatted, truncatablePath)
|
||||
|
||||
return data
|
||||
if (!_.isString(str)) {
|
||||
return
|
||||
}
|
||||
|
||||
_.set(formatted, truncatablePath, _.truncate(str, {
|
||||
length: 100,
|
||||
omission: `... [truncated string of total bytes: ${str.length}]`,
|
||||
}))
|
||||
})
|
||||
.value()
|
||||
|
||||
debugVerboseReceive('received CDP message %o', data)
|
||||
})
|
||||
debugVerboseReceive('received CDP message %o', formatted)
|
||||
|
||||
return handleMessage.call(cri, message)
|
||||
}
|
||||
}
|
||||
|
||||
if (debugVerboseSend.enabled) {
|
||||
const send = cri._ws.send
|
||||
const send = cri._send
|
||||
|
||||
cri._ws.send = (data, callback) => {
|
||||
cri._send = (data, callback) => {
|
||||
debugVerboseSend('sending CDP command %o', JSON.parse(data))
|
||||
|
||||
return send.call(cri._ws, data, callback)
|
||||
return send.call(cri, data, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,17 +132,36 @@ export { chromeRemoteInterface }
|
||||
|
||||
type DeferredPromise = { resolve: Function, reject: Function }
|
||||
|
||||
export const create = Bluebird.method((target: websocketUrl, onAsynchronousError: Function): Bluebird<CRIWrapper> => {
|
||||
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<CRIWrapper> => {
|
||||
const subscriptions: {eventName: CRI.EventName, cb: Function}[] = []
|
||||
let enqueuedCommands: {command: CRI.Command, params: any, p: DeferredPromise }[] = []
|
||||
let enqueuedCommands: {message: Message, 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
|
||||
@@ -159,7 +178,7 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
|
||||
})
|
||||
|
||||
enqueuedCommands.forEach((cmd) => {
|
||||
cri.send(cmd.command, cmd.params)
|
||||
cri.sendRaw(cmd.message)
|
||||
.then(cmd.p.resolve, cmd.p.reject)
|
||||
})
|
||||
|
||||
@@ -173,10 +192,10 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
|
||||
const connect = () => {
|
||||
cri?.close()
|
||||
|
||||
debug('connecting %o', { target })
|
||||
debug('connecting %o', opts)
|
||||
|
||||
return chromeRemoteInterface({
|
||||
target,
|
||||
...opts,
|
||||
local: true,
|
||||
})
|
||||
.then((newCri) => {
|
||||
@@ -190,6 +209,46 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
|
||||
|
||||
// @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<void>((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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -219,14 +278,23 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
|
||||
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({ command, params, p: { resolve, reject } })
|
||||
enqueuedCommands.push({ message, params, p: { resolve, reject } })
|
||||
})
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
return cri.send(command, params)
|
||||
return cri.sendRaw(message)
|
||||
.catch((err) => {
|
||||
if (!WEBSOCKET_NOT_OPEN_RE.test(err.message)) {
|
||||
throw err
|
||||
|
||||
@@ -5,6 +5,7 @@ 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
|
||||
|
||||
@@ -851,6 +852,12 @@ 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':
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"chalk": "2.4.2",
|
||||
"check-more-types": "2.24.0",
|
||||
"chokidar": "3.2.2",
|
||||
"chrome-remote-interface": "0.28.2",
|
||||
"chrome-remote-interface": "cypress-io/chrome-remote-interface#147192810f29951cd96c5e406495e9b4d740ba95",
|
||||
"cli-table3": "0.5.1",
|
||||
"coffeescript": "1.12.7",
|
||||
"color-string": "1.5.4",
|
||||
|
||||
@@ -4,36 +4,61 @@ import Fixtures from '../support/helpers/fixtures'
|
||||
|
||||
describe('e2e cdp', function () {
|
||||
e2e.setup()
|
||||
let restoreEnv: Function
|
||||
|
||||
beforeEach(() => {
|
||||
restoreEnv = mockedEnv({
|
||||
CYPRESS_REMOTE_DEBUGGING_PORT: '7777',
|
||||
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,
|
||||
})
|
||||
|
||||
// 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,
|
||||
})
|
||||
|
||||
// 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', '')
|
||||
},
|
||||
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,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+4
-2
@@ -4,8 +4,10 @@ module.exports = (on) => {
|
||||
on('before:browser:launch', (browser = {}, options) => {
|
||||
la(browser.family === 'chromium', 'this test can only be run with a chromium-family browser')
|
||||
|
||||
// remove debugging port so that the browser connection fails
|
||||
const newArgs = options.args.filter((arg) => !arg.startsWith('--remote-debugging-port='))
|
||||
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))
|
||||
|
||||
la(newArgs.length === options.args.length - 1, 'exactly one argument should have been removed')
|
||||
|
||||
|
||||
@@ -11,32 +11,39 @@ 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: () => ReturnType<typeof create>
|
||||
let getClient: (opts?: any) => ReturnType<typeof create>
|
||||
|
||||
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({
|
||||
send,
|
||||
close: sinon.stub(),
|
||||
_notifier: new EventEmitter(),
|
||||
})
|
||||
.resolves(criStub)
|
||||
|
||||
criClient = proxyquire('../lib/browsers/cri-client', {
|
||||
'chrome-remote-interface': criImport,
|
||||
})
|
||||
|
||||
getClient = () => criClient.create(DEBUGGER_URL, onError)
|
||||
getClient = (opts = { target: DEBUGGER_URL }) => criClient.create(opts, onError)
|
||||
})
|
||||
|
||||
context('.create', function () {
|
||||
@@ -46,19 +53,65 @@ 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.send with command and data', async function () {
|
||||
send.resolves()
|
||||
it('calls cri.sendRaw with command and data', async function () {
|
||||
sendRaw.resolves()
|
||||
const client = await getClient()
|
||||
|
||||
client.send('Browser.getVersion', { baz: 'quux' })
|
||||
expect(send).to.be.calledWith('Browser.getVersion', { baz: 'quux' })
|
||||
expect(sendRaw).to.be.calledWith({
|
||||
method: 'Browser.getVersion',
|
||||
params: { baz: 'quux' },
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects if cri.send rejects', async function () {
|
||||
it('rejects if cri.sendRaw rejects', async function () {
|
||||
const err = new Error
|
||||
|
||||
send.rejects(err)
|
||||
sendRaw.rejects(err)
|
||||
const client = await getClient()
|
||||
|
||||
await expect(client.send('Browser.getVersion', { baz: 'quux' }))
|
||||
@@ -74,14 +127,14 @@ describe('lib/browsers/cri-client', function () {
|
||||
it(`with '${msg}'`, async function () {
|
||||
const err = new Error(msg)
|
||||
|
||||
send.onFirstCall().rejects(err)
|
||||
send.onSecondCall().resolves()
|
||||
sendRaw.onFirstCall().rejects(err)
|
||||
sendRaw.onSecondCall().resolves()
|
||||
|
||||
const client = await getClient()
|
||||
|
||||
await client.send('Browser.getVersion', { baz: 'quux' })
|
||||
|
||||
expect(send).to.be.calledTwice
|
||||
expect(sendRaw).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -90,7 +143,10 @@ describe('lib/browsers/cri-client', function () {
|
||||
context('#ensureMinimumProtocolVersion', function () {
|
||||
function withProtocolVersion (actual, test) {
|
||||
if (actual) {
|
||||
send.withArgs('Browser.getVersion')
|
||||
sendRaw.withArgs({
|
||||
method: 'Browser.getVersion',
|
||||
params: undefined,
|
||||
})
|
||||
.resolves({ protocolVersion: actual })
|
||||
}
|
||||
|
||||
|
||||
@@ -10514,14 +10514,6 @@ 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"
|
||||
@@ -10530,6 +10522,13 @@ 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"
|
||||
|
||||
Reference in New Issue
Block a user