mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-25 01:49:06 -05:00
refactor(server): migrate electron-app to TypeScript (#33699)
- Convert lib/util/electron-app.js to electron-app.ts with ES module exports, static electron import, and typed opts for isRunningAsElectronProcess. - Replace dynamic requires in cypress.ts and run.ts with static imports. - Update start-cypress.js to destructure isRunning from the compiled module. - Rename electron_spec.js to electron_spec.ts and align browser unit tests with ESM imports and Automation setup. - Migrate electron-app_spec to TypeScript; import setRemoteDebuggingPort and electron app directly instead of require. - Add @ts-expect-error in electron_spec where tests still rely on untyped sinon stubs, legacy string browser arguments, and partial launch options. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,12 +1,23 @@
|
||||
const runChildProcess = async (entryPoint) => {
|
||||
// FIXME: use a bridge here to import TypeScript into a CommonJS context
|
||||
// Once everything is converted to ESM, we can remove this and use import() directly at the top of the file.
|
||||
require('tsx/cjs')
|
||||
require(entryPoint)
|
||||
}
|
||||
|
||||
const startCypress = async () => {
|
||||
try {
|
||||
const tsx = require('tsx/cjs/api')
|
||||
|
||||
// @see https://tsx.hirok.io/dev-api/register-cjs
|
||||
const unregister = tsx.register()
|
||||
// load these files in one by one as we aren't sure if its source TypeScript (development mode) or transpiled JavaScript (production mode).
|
||||
// once the file is converted to TypeScript, we can remove these one-off tsx.require calls.
|
||||
// One off require calls to tsx are needed for now to prevent side effects when building the binary.
|
||||
const { initializeStartTime } = require('./lib/util/performance_benchmark')
|
||||
|
||||
unregister()
|
||||
|
||||
initializeStartTime()
|
||||
|
||||
// No typescript requires before this point please
|
||||
|
||||
@@ -53,13 +53,13 @@ const tryToCall = function (win, method) {
|
||||
const _getAutomation = async function (win, options: BrowserLaunchOpts, parent) {
|
||||
if (!options.onError) throw new Error('Missing onError in electron#_launch')
|
||||
|
||||
const port = getRemoteDebuggingPort()
|
||||
const port = await getRemoteDebuggingPort()
|
||||
|
||||
if (!browserCriClient) {
|
||||
debug(`browser CRI is not set. Creating...`)
|
||||
browserCriClient = await BrowserCriClient.create({
|
||||
hosts: ['127.0.0.1'],
|
||||
port,
|
||||
port: Number(port),
|
||||
browserName: 'electron',
|
||||
onAsynchronousError: options.onError,
|
||||
onReconnect: () => {},
|
||||
|
||||
@@ -19,6 +19,7 @@ import { toNumber } from 'lodash'
|
||||
import { GracefulExit } from './util/graceful-exit'
|
||||
import type { BrowserWindow } from 'electron'
|
||||
import type { CypressRunResult } from './modes/results'
|
||||
import { isRunning, scale, setRemoteDebuggingPort } from './util/electron-app'
|
||||
const debug = Debug('cypress:server:cypress')
|
||||
|
||||
type Mode = 'exit' | 'info' | 'interactive' | 'pkg' | 'record' | 'results' | 'run' | 'smokeTest' | 'version' | 'returnPkg' | 'exitWithCode'
|
||||
@@ -85,7 +86,7 @@ async function exitErr (err: unknown, posixExitCodes?: boolean) {
|
||||
|
||||
export = {
|
||||
isCurrentlyRunningElectron () {
|
||||
return require('./util/electron-app').isRunning()
|
||||
return isRunning()
|
||||
},
|
||||
|
||||
runElectron (mode: Mode, options: any): Promise<RunElectronResult> {
|
||||
@@ -136,7 +137,7 @@ export = {
|
||||
})
|
||||
},
|
||||
|
||||
start (argv: any = []) {
|
||||
async start (argv: any = []) {
|
||||
debug('starting cypress with argv %o', argv)
|
||||
|
||||
// if the CLI passed "--" somewhere, we need to remove it
|
||||
@@ -176,36 +177,35 @@ export = {
|
||||
// to force retina screens to not
|
||||
// upsample their images when offscreen
|
||||
// rendering
|
||||
require('./util/electron-app').scale()
|
||||
await scale()
|
||||
}
|
||||
|
||||
// make sure we have the appData folder
|
||||
return Promise.all([
|
||||
await Promise.all([
|
||||
require('./util/app_data').ensure(),
|
||||
require('./util/electron-app').setRemoteDebuggingPort(),
|
||||
setRemoteDebuggingPort(),
|
||||
])
|
||||
.then(() => {
|
||||
// else determine the mode by
|
||||
// the passed in arguments / options
|
||||
// and normalize this mode
|
||||
let mode = options.mode || 'interactive'
|
||||
|
||||
if (options.version) {
|
||||
mode = 'version'
|
||||
} else if (options.smokeTest) {
|
||||
mode = 'smokeTest'
|
||||
} else if (options.returnPkg) {
|
||||
mode = 'returnPkg'
|
||||
} else if (!(options.exitWithCode == null)) {
|
||||
mode = 'exitWithCode'
|
||||
} else if (options.runProject) {
|
||||
// go into headless mode when running
|
||||
// until completion + exit
|
||||
mode = 'run'
|
||||
}
|
||||
// else determine the mode by
|
||||
// the passed in arguments / options
|
||||
// and normalize this mode
|
||||
let mode = options.mode || 'interactive'
|
||||
|
||||
return this.startInMode(mode, options)
|
||||
})
|
||||
if (options.version) {
|
||||
mode = 'version'
|
||||
} else if (options.smokeTest) {
|
||||
mode = 'smokeTest'
|
||||
} else if (options.returnPkg) {
|
||||
mode = 'returnPkg'
|
||||
} else if (!(options.exitWithCode == null)) {
|
||||
mode = 'exitWithCode'
|
||||
} else if (options.runProject) {
|
||||
// go into headless mode when running
|
||||
// until completion + exit
|
||||
mode = 'run'
|
||||
}
|
||||
|
||||
return this.startInMode(mode, options)
|
||||
},
|
||||
|
||||
async startInMode (mode: Mode, options: any) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import { EarlyExitTerminator } from '../util/graceful_crash_handling'
|
||||
import { passWithNoTests } from './pass-with-no-tests'
|
||||
import type { EmptyRunOptions } from './pass-with-no-tests'
|
||||
import type { CypressError } from '@packages/errors'
|
||||
import { isRunningAsElectronProcess } from '../util/electron-app'
|
||||
|
||||
type SetScreenshotMetadata = (data: TakeScreenshotProps) => void
|
||||
export type ScreenshotMetadata = ReturnType<typeof screenshotMetadata>
|
||||
@@ -1232,7 +1233,7 @@ async function ready (options: ReadyOptions) {
|
||||
export async function run (options, loading: Promise<void>) {
|
||||
debug('run start')
|
||||
// Check if running as electron process
|
||||
if (require('../util/electron-app').isRunningAsElectronProcess({ debug })) {
|
||||
if (isRunningAsElectronProcess({ debug })) {
|
||||
// tslint:disable-next-line no-implicit-dependencies - electron dep needs to be defined
|
||||
const app = require('electron').app
|
||||
|
||||
|
||||
+13
-21
@@ -1,8 +1,8 @@
|
||||
const getPort = require('get-port')
|
||||
import getPort from 'get-port'
|
||||
|
||||
const scale = () => {
|
||||
export const scale = async () => {
|
||||
try {
|
||||
const { app } = require('electron')
|
||||
const { app } = await import('electron')
|
||||
|
||||
return app.commandLine.appendSwitch('force-device-scale-factor', '1')
|
||||
} catch (err) {
|
||||
@@ -11,9 +11,9 @@ const scale = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const getRemoteDebuggingPort = () => {
|
||||
export const getRemoteDebuggingPort = async () => {
|
||||
try {
|
||||
const { app } = require('electron')
|
||||
const { app } = await import('electron')
|
||||
|
||||
return app.commandLine.getSwitchValue('remote-debugging-port')
|
||||
} catch (err) {
|
||||
@@ -22,9 +22,9 @@ const getRemoteDebuggingPort = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const setRemoteDebuggingPort = async () => {
|
||||
export const setRemoteDebuggingPort = async () => {
|
||||
try {
|
||||
const { app } = require('electron')
|
||||
const { app } = await import('electron')
|
||||
|
||||
// if port was already set via passing from environment variable ELECTRON_EXTRA_LAUNCH_ARGS,
|
||||
// then just keep the supplied value
|
||||
@@ -42,12 +42,16 @@ const setRemoteDebuggingPort = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const isRunning = () => {
|
||||
export const isRunning = () => {
|
||||
// are we in the electron or the node process?
|
||||
return Boolean(process.env.ELECTRON_RUN_AS_NODE || process.versions && process.versions.electron)
|
||||
}
|
||||
|
||||
const isRunningAsElectronProcess = ({ debug } = {}) => {
|
||||
type IsRunningAsElectronProcessOpts = {
|
||||
debug?: (message: string) => void
|
||||
}
|
||||
|
||||
export const isRunningAsElectronProcess = ({ debug }: IsRunningAsElectronProcessOpts = {}) => {
|
||||
const isElectronProcess = !process.env.ELECTRON_RUN_AS_NODE
|
||||
|
||||
if (!isElectronProcess && debug) {
|
||||
@@ -56,15 +60,3 @@ const isRunningAsElectronProcess = ({ debug } = {}) => {
|
||||
|
||||
return isElectronProcess
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
scale,
|
||||
|
||||
getRemoteDebuggingPort,
|
||||
|
||||
setRemoteDebuggingPort,
|
||||
|
||||
isRunning,
|
||||
|
||||
isRunningAsElectronProcess,
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
const { performance } = require('perf_hooks')
|
||||
const { isRunning } = require('./electron-app')
|
||||
|
||||
function threeDecimals (n) {
|
||||
return Math.round(n * 1000) / 1000
|
||||
}
|
||||
|
||||
const initializeStartTime = () => {
|
||||
if (!isRunning()) {
|
||||
return
|
||||
}
|
||||
|
||||
// This needs to be a global since this file is included inside of and outside of the v8 snapshot
|
||||
global.cypressBinaryStartTime = performance.timeOrigin
|
||||
global.cypressServerStartTime = performance.now()
|
||||
}
|
||||
|
||||
const debugElapsedTime = (event) => {
|
||||
const Debug = require('debug')
|
||||
const debug = Debug('cypress:server:performance-benchmark')
|
||||
|
||||
const now = performance.now()
|
||||
const delta = now - global.cypressServerStartTime
|
||||
|
||||
debug(`elapsed time at ${event}: ${threeDecimals(delta)}ms`)
|
||||
|
||||
return delta
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initializeStartTime,
|
||||
debugElapsedTime,
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { performance } from 'perf_hooks'
|
||||
import { isRunning } from './electron-app'
|
||||
|
||||
function threeDecimals (n: number): number {
|
||||
return Math.round(n * 1000) / 1000
|
||||
}
|
||||
|
||||
declare global {
|
||||
var cypressBinaryStartTime: number | undefined
|
||||
var cypressServerStartTime: number | undefined
|
||||
}
|
||||
|
||||
export const initializeStartTime = (): void => {
|
||||
if (!isRunning()) {
|
||||
return
|
||||
}
|
||||
|
||||
// This needs to be a global since this file is included inside of and outside of the v8 snapshot
|
||||
global.cypressBinaryStartTime = performance.timeOrigin
|
||||
global.cypressServerStartTime = performance.now()
|
||||
}
|
||||
|
||||
export const debugElapsedTime = (event: string): number => {
|
||||
const Debug = require('debug')
|
||||
const debug = Debug('cypress:server:performance-benchmark')
|
||||
|
||||
const now = performance.now()
|
||||
const serverStart = global.cypressServerStartTime
|
||||
// Match legacy JS when uninitialized: `now - undefined` is `NaN`.
|
||||
const delta = serverStart === undefined ? NaN : now - serverStart
|
||||
|
||||
debug(`elapsed time at ${event}: ${threeDecimals(delta)}ms`)
|
||||
|
||||
return delta
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
const Debug = require('debug')
|
||||
const electronApp = require('./lib/util/electron-app')
|
||||
const { isRunning: isElectronRunning } = require('./lib/util/electron-app')
|
||||
const { telemetry, OTLPTraceExporterCloud } = require('@packages/telemetry')
|
||||
const { apiRoutes } = require('./lib/cloud/routes')
|
||||
const encryption = require('./lib/cloud/encryption')
|
||||
const { override: overrideTty } = require('./lib/util/tty')
|
||||
const { GracefulExit } = require('./lib/util/graceful-exit')
|
||||
const { NetProfiler } = require('./lib/util/net_profiler')
|
||||
const { debugElapsedTime } = require('./lib/util/performance_benchmark')
|
||||
|
||||
const { calculateCypressInternalEnv, configureLongStackTraces } = require('./lib/environment')
|
||||
|
||||
@@ -16,7 +17,7 @@ configureLongStackTraces(process.env['CYPRESS_INTERNAL_ENV'])
|
||||
process.env['CYPRESS'] = 'true'
|
||||
|
||||
// are we in the main node process or the electron process?
|
||||
const isRunningElectron = electronApp.isRunning()
|
||||
const isRunningElectron = isElectronRunning()
|
||||
|
||||
const pkg = require('@packages/root')
|
||||
|
||||
@@ -49,8 +50,6 @@ if (isRunningElectron) {
|
||||
exporter,
|
||||
})
|
||||
|
||||
const { debugElapsedTime } = require('./lib/util/performance_benchmark')
|
||||
|
||||
const v8SnapshotStartupTime = debugElapsedTime('v8-snapshot-startup-time')
|
||||
const endTime = v8SnapshotStartupTime + global.cypressServerStartTime
|
||||
|
||||
|
||||
@@ -461,10 +461,10 @@ describe('lib/cypress', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('throws an error if both --headed and --headless are true', function () {
|
||||
// error is thrown synchronously
|
||||
expect(() => cypress.start([`--run-project=${this.todosPath}`, '--headless', '--headed']))
|
||||
.to.throw('Impossible options: both headless and headed are true')
|
||||
it('rejects if both --headed and --headless are true', function () {
|
||||
return expect(
|
||||
cypress.start([`--run-project=${this.todosPath}`, '--headless', '--headed']),
|
||||
).to.be.rejectedWith('Impossible options: both headless and headed are true')
|
||||
})
|
||||
|
||||
describe('strips --', () => {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const systemTests = require('@tooling/system-tests/lib/system-tests').default
|
||||
import systemTests from '@tooling/system-tests/lib/system-tests'
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/4313
|
||||
context('cy.visit performance tests', function () {
|
||||
+78
-21
@@ -1,20 +1,19 @@
|
||||
require('../../spec_helper')
|
||||
|
||||
const _ = require('lodash')
|
||||
const EE = require('events')
|
||||
const la = require('lazy-ass')
|
||||
|
||||
const menu = require(`../../../lib/gui/menu`)
|
||||
const plugins = require(`../../../lib/plugins`)
|
||||
const Windows = require(`../../../lib/gui/windows`)
|
||||
const electron = require(`../../../lib/browsers/electron`)
|
||||
const savedState = require(`../../../lib/saved_state`)
|
||||
const { Automation } = require(`../../../lib/automation`)
|
||||
const { BrowserCriClient } = require('../../../lib/browsers/browser-cri-client')
|
||||
const electronApp = require('../../../lib/util/electron-app')
|
||||
const utils = require('../../../lib/browsers/utils').default
|
||||
const { screencastOpts } = require('../../../lib/browsers/cdp_automation')
|
||||
|
||||
import '../../spec_helper'
|
||||
import _ from 'lodash'
|
||||
import EE from 'events'
|
||||
import la from 'lazy-ass'
|
||||
import sinon from 'sinon'
|
||||
import { Automation } from '../../../lib/automation'
|
||||
import { BrowserCriClient } from '../../../lib/browsers/browser-cri-client'
|
||||
import * as electronApp from '../../../lib/util/electron-app'
|
||||
import utils from '../../../lib/browsers/utils'
|
||||
import { screencastOpts } from '../../../lib/browsers/cdp_automation'
|
||||
import menu from '../../../lib/gui/menu'
|
||||
import * as plugins from '../../../lib/plugins'
|
||||
import * as Windows from '../../../lib/gui/windows'
|
||||
import electron from '../../../lib/browsers/electron'
|
||||
import * as savedState from '../../../lib/saved_state'
|
||||
import type { BrowserLaunchOpts } from '@packages/types'
|
||||
const ELECTRON_PID = 10001
|
||||
|
||||
describe('lib/browsers/electron', () => {
|
||||
@@ -37,17 +36,18 @@ describe('lib/browsers/electron', () => {
|
||||
isTextTerminal: false,
|
||||
some: 'var',
|
||||
projectRoot: '/foo/',
|
||||
onWarning: sinon.stub().returns(),
|
||||
onWarning: sinon.stub().returns(undefined),
|
||||
browser: {
|
||||
isHeadless: false,
|
||||
},
|
||||
onError: () => {},
|
||||
}
|
||||
} as unknown as BrowserLaunchOpts & { some: string }
|
||||
|
||||
this.automation = new Automation({
|
||||
cyNamespace: 'foo',
|
||||
cookieNamespace: 'bar',
|
||||
screenshotsFolder: 'baz',
|
||||
onServiceWorkerClientEvent: sinon.stub(),
|
||||
})
|
||||
|
||||
this.win = _.extend(new EE(), {
|
||||
@@ -80,7 +80,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
sinon.stub(Windows, 'installExtension').returns()
|
||||
sinon.stub(Windows, 'removeAllExtensions').returns()
|
||||
sinon.stub(electronApp, 'getRemoteDebuggingPort').resolves(1234)
|
||||
sinon.stub(electronApp, 'getRemoteDebuggingPort').resolves('1234')
|
||||
sinon.stub(utils, 'initializeCDP').resolves()
|
||||
|
||||
// mock CRI client during testing
|
||||
@@ -120,6 +120,7 @@ describe('lib/browsers/electron', () => {
|
||||
context('.connectToNewSpec', () => {
|
||||
it('throws an error', async function () {
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
electron.connectToNewSpec({ isHeaded: true }, { url: 'http://www.example.com' }, this.automation)
|
||||
}).to.throw('Attempting to connect to a new spec is not supported for electron, use open instead')
|
||||
})
|
||||
@@ -128,22 +129,27 @@ describe('lib/browsers/electron', () => {
|
||||
context('.open', () => {
|
||||
beforeEach(async function () {
|
||||
// shortcut to set the browserCriClient singleton variable
|
||||
// @ts-expect-error
|
||||
await electron._getAutomation({}, { onError: () => {} }, {})
|
||||
|
||||
await this.stubForOpen()
|
||||
})
|
||||
|
||||
it('calls render with url, state, and options', function () {
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
let options = electron._defaultOptions(this.options.projectRoot, this.state, this.options)
|
||||
|
||||
options = Windows.defaults(options)
|
||||
|
||||
// @ts-expect-error
|
||||
const preferencesKeys = _.keys(electron._render.firstCall.args[2])
|
||||
|
||||
expect(_.keys(options)).to.deep.eq(preferencesKeys)
|
||||
|
||||
// @ts-expect-error
|
||||
const electronOptionsArg = electron._render.firstCall.args[3]
|
||||
|
||||
expect(electronOptionsArg.projectRoot).to.eq(this.options.projectRoot)
|
||||
@@ -157,8 +163,10 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('returns custom object emitter interface', function () {
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then((obj) => {
|
||||
// @ts-expect-error
|
||||
expect(obj.browserWindow).to.eq(this.win)
|
||||
expect(obj.kill).to.be.a('function')
|
||||
expect(obj.removeAllListeners).to.be.a('function')
|
||||
@@ -171,11 +179,15 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('executeBeforeBrowserLaunch is noop when before:browser:launch yields null', function () {
|
||||
// @ts-expect-error
|
||||
plugins.has.returns(true)
|
||||
// @ts-expect-error
|
||||
plugins.execute.resolves(null)
|
||||
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
const options = electron._render.firstCall.args[2]
|
||||
|
||||
expect(options).to.include.keys('onFocus', 'onNewWindow', 'onCrashed')
|
||||
@@ -184,15 +196,19 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/1992
|
||||
it('it merges in user preferences without removing essential options', function () {
|
||||
// @ts-expect-error
|
||||
plugins.has.returns(true)
|
||||
// @ts-expect-error
|
||||
plugins.execute.withArgs('before:browser:launch').resolves({
|
||||
preferences: {
|
||||
foo: 'bar',
|
||||
},
|
||||
})
|
||||
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
const options = electron._render.firstCall.args[2]
|
||||
|
||||
expect(options).to.include.keys('foo', 'onFocus', 'onNewWindow', 'onCrashed')
|
||||
@@ -200,11 +216,15 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('installs supplied extensions from before:browser:launch and warns on failure', function () {
|
||||
// @ts-expect-error
|
||||
plugins.has.returns(true)
|
||||
// @ts-expect-error
|
||||
plugins.execute.resolves({ extensions: ['foo', 'bar'] })
|
||||
|
||||
// @ts-expect-error
|
||||
Windows.installExtension.withArgs(sinon.match.any, 'bar').throws()
|
||||
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
expect(Windows.removeAllExtensions).to.be.calledOnce
|
||||
@@ -227,9 +247,12 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('sends after:browser:launch with debugger url', function () {
|
||||
// @ts-expect-error
|
||||
plugins.has.returns(true)
|
||||
// @ts-expect-error
|
||||
plugins.execute.resolves(null)
|
||||
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
expect(plugins.execute).to.be.calledWith('after:browser:launch', 'electron', {
|
||||
@@ -239,6 +262,7 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('executeAfterBrowserLaunch is noop if after:browser:launch is not registered', function () {
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
expect(plugins.execute).not.to.be.calledWith('after:browser:launch')
|
||||
@@ -379,6 +403,7 @@ describe('lib/browsers/electron', () => {
|
||||
currentlyAttachedProtocolTarget: mockCurrentlyAttachedProtocolTarget,
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
sinon.stub(electron, '_getBrowserCriClient').returns(browserCriClient)
|
||||
|
||||
await electron.closeProtocolConnection()
|
||||
@@ -390,6 +415,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
context('.kill', () => {
|
||||
beforeEach(async function () {
|
||||
// @ts-expect-error
|
||||
await electron._getAutomation({}, { onError: () => {} }, {})
|
||||
|
||||
await this.stubForOpen()
|
||||
@@ -398,6 +424,7 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('does not terminate the browserCriClient if the instance is an orphaned process', async function () {
|
||||
// @ts-expect-error
|
||||
const instance = await electron.open('electron', this.url, this.options, this.automation)
|
||||
|
||||
instance.isOrphanedBrowserProcess = true
|
||||
@@ -407,6 +434,7 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('terminates the browserCriClient otherwise', async function () {
|
||||
// @ts-expect-error
|
||||
const instance = await electron.open('electron', this.url, this.options, this.automation)
|
||||
|
||||
instance.kill()
|
||||
@@ -425,12 +453,15 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('sets menu.set whether or not its in headless mode', function () {
|
||||
// @ts-expect-error
|
||||
return electron._launch(this.win, this.url, this.automation, { show: true, onError: () => {} }, undefined, undefined, { attachCDPClient: sinon.stub() })
|
||||
.then(() => {
|
||||
expect(menu.set).to.be.calledWith({ withInternalDevTools: true })
|
||||
}).then(() => {
|
||||
// @ts-expect-error
|
||||
menu.set.reset()
|
||||
|
||||
// @ts-expect-error
|
||||
return electron._launch(this.win, this.url, this.automation, { show: false, onError: () => {} })
|
||||
}).then(() => {
|
||||
expect(menu.set).not.to.be.called
|
||||
@@ -442,6 +473,7 @@ describe('lib/browsers/electron', () => {
|
||||
.then(() => {
|
||||
expect(electron._setUserAgent).not.to.be.called
|
||||
}).then(() => {
|
||||
// @ts-expect-error
|
||||
return electron._launch(this.win, this.url, this.automation, { userAgent: 'foo', onError: () => {} }, undefined, undefined, { attachCDPClient: sinon.stub() })
|
||||
}).then(() => {
|
||||
expect(electron._setUserAgent).to.be.calledWith(this.win.webContents, 'foo')
|
||||
@@ -453,6 +485,7 @@ describe('lib/browsers/electron', () => {
|
||||
.then(() => {
|
||||
expect(electron._setProxy).not.to.be.called
|
||||
}).then(() => {
|
||||
// @ts-expect-error
|
||||
return electron._launch(this.win, this.url, this.automation, { proxyServer: 'foo', onError: () => {} }, undefined, undefined, { attachCDPClient: sinon.stub() })
|
||||
}).then(() => {
|
||||
expect(electron._setProxy).to.be.calledWith(this.win.webContents, 'foo')
|
||||
@@ -960,42 +993,49 @@ describe('lib/browsers/electron', () => {
|
||||
})
|
||||
|
||||
it('uses default width if there isn\'t one saved', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', this.state, this.options)
|
||||
|
||||
expect(opts.width).to.eq(1280)
|
||||
})
|
||||
|
||||
it('uses saved width if there is one', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', { browserWidth: 1024 }, this.options)
|
||||
|
||||
expect(opts.width).to.eq(1024)
|
||||
})
|
||||
|
||||
it('uses default height if there isn\'t one saved', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', this.state, this.options)
|
||||
|
||||
expect(opts.height).to.eq(720)
|
||||
})
|
||||
|
||||
it('uses saved height if there is one', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', { browserHeight: 768 }, this.options)
|
||||
|
||||
expect(opts.height).to.eq(768)
|
||||
})
|
||||
|
||||
it('uses saved x if there is one', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', { browserX: 200 }, this.options)
|
||||
|
||||
expect(opts.x).to.eq(200)
|
||||
})
|
||||
|
||||
it('uses saved y if there is one', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', { browserY: 300 }, this.options)
|
||||
|
||||
expect(opts.y).to.eq(300)
|
||||
})
|
||||
|
||||
it('tracks browser state', function () {
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions('/foo', { browserY: 300 }, this.options)
|
||||
|
||||
const args = _.pick(opts.trackState, 'width', 'height', 'x', 'y', 'devTools')
|
||||
@@ -1015,6 +1055,7 @@ describe('lib/browsers/electron', () => {
|
||||
headlessOpts.onFocus()
|
||||
expect(menu.set).to.be.calledWith({ withInternalDevTools: true })
|
||||
|
||||
// @ts-expect-error
|
||||
menu.set.reset()
|
||||
|
||||
const headedOpts = electron._defaultOptions('/foo', this.state, { browser: { isHeadless: true } }, undefined, undefined, { attachCDPClient: sinon.stub() })
|
||||
@@ -1043,8 +1084,10 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
it('adds pid of new BrowserWindow to allPids list', async function () {
|
||||
// shortcut to set the browserCriClient singleton variable
|
||||
// @ts-expect-error
|
||||
await electron._getAutomation({}, { onError: () => {} }, {})
|
||||
|
||||
// @ts-expect-error
|
||||
const opts = electron._defaultOptions(this.options.projectRoot, this.state, this.options)
|
||||
|
||||
const NEW_WINDOW_PID = ELECTRON_PID * 2
|
||||
@@ -1053,10 +1096,12 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
child.webContents.getOSProcessId = sinon.stub().returns(NEW_WINDOW_PID)
|
||||
|
||||
// @ts-expect-error
|
||||
electron._launchChild.resolves(child)
|
||||
|
||||
return this.stubForOpen()
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
return electron.open('electron', this.url, opts, this.automation)
|
||||
}).then((instance) => {
|
||||
return opts.onNewWindow.call(this.win, {}, this.url)
|
||||
@@ -1077,6 +1122,7 @@ describe('lib/browsers/electron', () => {
|
||||
webContents: new EE(),
|
||||
})
|
||||
|
||||
// @ts-expect-error
|
||||
Windows.create.onCall(1).resolves(this.childWin)
|
||||
|
||||
this.event = { preventDefault: sinon.stub() }
|
||||
@@ -1085,7 +1131,7 @@ describe('lib/browsers/electron', () => {
|
||||
}
|
||||
|
||||
this.openNewWindow = (options) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-expect-error
|
||||
return launcher.launch('electron', this.url, options).then(() => {
|
||||
return this.win.webContents.emit('new-window', this.event, 'some://other.url')
|
||||
})
|
||||
@@ -1100,6 +1146,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
it('creates child window', function () {
|
||||
return this.openNewWindow().then(() => {
|
||||
// @ts-expect-error
|
||||
const args = Windows.create.lastCall.args[0]
|
||||
|
||||
expect(Windows.create).to.be.calledTwice
|
||||
@@ -1112,6 +1159,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
it('offsets it from parent by 100px', function () {
|
||||
return this.openNewWindow().then(() => {
|
||||
// @ts-expect-error
|
||||
const args = Windows.create.lastCall.args[0]
|
||||
|
||||
expect(args.x).to.equal(104)
|
||||
@@ -1122,6 +1170,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
it('passes along web security', function () {
|
||||
return this.openNewWindow({ chromeWebSecurity: false }).then(() => {
|
||||
// @ts-expect-error
|
||||
const args = Windows.create.lastCall.args[0]
|
||||
|
||||
expect(args.chromeWebSecurity).to.be.false
|
||||
@@ -1130,10 +1179,12 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
it('sets unique PROJECT type on each new window', function () {
|
||||
return this.openNewWindow().then(() => {
|
||||
// @ts-expect-error
|
||||
const firstArgs = Windows.create.lastCall.args[0]
|
||||
|
||||
expect(firstArgs.type).to.match(/^PROJECT-CHILD-\d/)
|
||||
this.win.webContents.emit('new-window', this.event, 'yet://another.url')
|
||||
// @ts-expect-error
|
||||
const secondArgs = Windows.create.lastCall.args[0]
|
||||
|
||||
expect(secondArgs.type).to.match(/^PROJECT-CHILD-\d/)
|
||||
@@ -1145,6 +1196,7 @@ describe('lib/browsers/electron', () => {
|
||||
it('set newGuest on child window', function () {
|
||||
return this.openNewWindow()
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
return Promise.delay(1)
|
||||
}).then(() => {
|
||||
expect(this.event.newGuest).to.equal(this.childWin)
|
||||
@@ -1162,6 +1214,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
it('sets menu with dev tools on focus', function () {
|
||||
return this.openNewWindow().then(() => {
|
||||
// @ts-expect-error
|
||||
Windows.create.lastCall.args[0].onFocus()
|
||||
// once for main window, once for child, once for focus
|
||||
expect(menu.set).to.be.calledThrice
|
||||
@@ -1173,6 +1226,7 @@ describe('lib/browsers/electron', () => {
|
||||
it('it closes the child window when the parent window is closed', function () {
|
||||
return this.openNewWindow()
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
return Promise.delay(1)
|
||||
}).then(() => {
|
||||
this.win.emit('close')
|
||||
@@ -1184,6 +1238,7 @@ describe('lib/browsers/electron', () => {
|
||||
it('does not close the child window when it is already destroyed', function () {
|
||||
return this.openNewWindow()
|
||||
.then(() => {
|
||||
// @ts-expect-error
|
||||
return Promise.delay(1)
|
||||
}).then(() => {
|
||||
this.childWin.isDestroyed.returns(true)
|
||||
@@ -1200,6 +1255,7 @@ describe('lib/browsers/electron', () => {
|
||||
webContents: new EE(),
|
||||
})
|
||||
|
||||
// @ts-expect-error
|
||||
Windows.create.onCall(2).resolves(this.grandchildWin)
|
||||
this.childWin.getPosition = () => {
|
||||
return [104, 102]
|
||||
@@ -1207,6 +1263,7 @@ describe('lib/browsers/electron', () => {
|
||||
|
||||
return this.openNewWindow().then(() => {
|
||||
this.childWin.webContents.emit('new-window', this.event, 'yet://another.url')
|
||||
// @ts-expect-error
|
||||
const args = Windows.create.lastCall.args[0]
|
||||
|
||||
expect(Windows.create).to.be.calledThrice
|
||||
+4
-7
@@ -1,4 +1,5 @@
|
||||
const electronApp = require('../../../lib/util/electron-app')
|
||||
import { setRemoteDebuggingPort } from '../../../lib/util/electron-app'
|
||||
import { app } from 'electron'
|
||||
|
||||
describe('/lib/util/electron-app', () => {
|
||||
context('remote debugging port', () => {
|
||||
@@ -7,28 +8,24 @@ describe('/lib/util/electron-app', () => {
|
||||
})
|
||||
|
||||
it('should not override port if previously set', async () => {
|
||||
const { app } = require('electron')
|
||||
|
||||
sinon.stub(app.commandLine, 'appendSwitch')
|
||||
sinon.stub(app.commandLine, 'getSwitchValue').callsFake((args) => {
|
||||
return '4567'
|
||||
})
|
||||
|
||||
await electronApp.setRemoteDebuggingPort()
|
||||
await setRemoteDebuggingPort()
|
||||
|
||||
expect(app.commandLine.appendSwitch).to.not.have.been.called
|
||||
})
|
||||
|
||||
it('should assign random port if not previously set', async () => {
|
||||
const { app } = require('electron')
|
||||
|
||||
sinon.stub(app.commandLine, 'appendSwitch')
|
||||
|
||||
sinon.stub(app.commandLine, 'getSwitchValue').callsFake((args) => {
|
||||
return undefined
|
||||
})
|
||||
|
||||
await electronApp.setRemoteDebuggingPort()
|
||||
await setRemoteDebuggingPort()
|
||||
|
||||
expect(app.commandLine.appendSwitch).to.have.been.calledWith('remote-debugging-port', sinon.match.string)
|
||||
})
|
||||
@@ -91,6 +91,9 @@ const getDependencyPathsToKeep = async (buildAppDir) => {
|
||||
external: [
|
||||
'./transpile-ts',
|
||||
'./start-cypress',
|
||||
// TypeScript lowers `import('electron')` to `require('electron')`; esbuild must not
|
||||
// try to bundle it (electron is not installed under the packed app tree).
|
||||
'electron',
|
||||
'fsevents',
|
||||
'pnpapi',
|
||||
'@swc/core',
|
||||
@@ -143,6 +146,7 @@ const createServerEntryPointBundle = async (buildAppDir) => {
|
||||
external: [
|
||||
'./transpile-ts',
|
||||
'./start-cypress',
|
||||
'electron',
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user