mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-06 06:29:45 -06:00
feat(deps): electron@9.0.5 (#7791)
* chore(deps): electron@9.0.5 BREAKING CHANGE: libgbm is a requirement * update node, xcode, docker images * lockfile * chore(types): tsify lib/gui/windows and spec * fix Electron extension loading global extension loading was deprecated in 9, now has to be per-session * make windows fns stubbable * update electron_spec * tsify issue_173_spec * use upstream foxdriver to fix FF >= 75 see https://github.com/benmalka/foxdriver/issues/7 * update test * for now, install libgbm-dev at ci time see https://github.com/cypress-io/cypress-docker-images/pull/332 * fix open mode * remove devtools-ext dir
This commit is contained in:
@@ -1 +1 @@
|
||||
12.8.1
|
||||
12.14.1
|
||||
|
||||
@@ -7,7 +7,7 @@ branches:
|
||||
# https://www.appveyor.com/docs/lang/nodejs-iojs/
|
||||
environment:
|
||||
# use matching version of Node.js
|
||||
nodejs_version: "12.8.1"
|
||||
nodejs_version: "12.14.1"
|
||||
# encode secure variables which will NOT be used
|
||||
# in pull requests
|
||||
# https://www.appveyor.com/docs/build-configuration/#secure-variables
|
||||
|
||||
11
circle.yml
11
circle.yml
@@ -43,14 +43,14 @@ executors:
|
||||
# the Docker image with Cypress dependencies and Chrome browser
|
||||
cy-doc:
|
||||
docker:
|
||||
- image: cypress/browsers:node12.13.0-chrome80-ff74
|
||||
- image: cypress/browsers:node12.14.1-chrome83-ff77
|
||||
environment:
|
||||
PLATFORM: linux
|
||||
|
||||
# Docker image with non-root "node" user
|
||||
non-root-docker-user:
|
||||
docker:
|
||||
- image: cypress/browsers:node12.13.0-chrome80-ff74
|
||||
- image: cypress/browsers:node12.14.1-chrome83-ff77
|
||||
user: node
|
||||
environment:
|
||||
PLATFORM: linux
|
||||
@@ -60,8 +60,8 @@ executors:
|
||||
# https://circleci.com/docs/2.0/testing-ios/#supported-xcode-versions
|
||||
mac:
|
||||
macos:
|
||||
## Node 12.10.0 (yarn 1.17.3)
|
||||
xcode: "11.0.0"
|
||||
## Node 12.12.0 (yarn 1.19.1)
|
||||
xcode: "11.2.1"
|
||||
environment:
|
||||
PLATFORM: mac
|
||||
|
||||
@@ -1144,6 +1144,9 @@ jobs:
|
||||
- run: mkdir test-binary
|
||||
- run: node --version
|
||||
- run: npm --version
|
||||
# TODO: this can be removed as soon as the minimum Node version is bumped to 10
|
||||
# see https://github.com/cypress-io/cypress-docker-images/pull/332
|
||||
- run: apt-get update && apt-get install -y libgbm-dev
|
||||
- run:
|
||||
name: Create new NPM package
|
||||
working_directory: test-binary
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
"typescript": "3.7.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.8.1",
|
||||
"node": ">=12.14.1",
|
||||
"yarn": ">=1.17.3"
|
||||
},
|
||||
"productName": "Cypress",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"minimist": "1.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "8.3.1",
|
||||
"electron": "9.0.5",
|
||||
"mocha": "3.5.3"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -66,12 +66,12 @@ const _getAutomation = function (win, options) {
|
||||
return automation
|
||||
}
|
||||
|
||||
const _installExtensions = function (extensionPaths = [], options) {
|
||||
Windows.removeAllExtensions()
|
||||
const _installExtensions = function (win, extensionPaths = [], options) {
|
||||
Windows.removeAllExtensions(win)
|
||||
|
||||
return extensionPaths.forEach((path) => {
|
||||
return Bluebird.map(extensionPaths, (path) => {
|
||||
try {
|
||||
return Windows.installExtension(path)
|
||||
return Windows.installExtension(win, path)
|
||||
} catch (error) {
|
||||
return options.onWarning(errors.get('EXTENSION_NOT_LOADED', 'Electron', path))
|
||||
}
|
||||
@@ -349,10 +349,10 @@ module.exports = {
|
||||
|
||||
debug('launching browser window to url: %s', url)
|
||||
|
||||
_installExtensions(launchOptions.extensions, options)
|
||||
|
||||
return this._render(url, projectRoot, automation, preferences)
|
||||
.then((win) => {
|
||||
.then(async (win) => {
|
||||
await _installExtensions(win, launchOptions.extensions, options)
|
||||
|
||||
// cause the webview to receive focus so that
|
||||
// native browser focus + blur events fire correctly
|
||||
// https://github.com/cypress-io/cypress/issues/1939
|
||||
@@ -363,7 +363,7 @@ module.exports = {
|
||||
win.once('closed', () => {
|
||||
debug('closed event fired')
|
||||
|
||||
Windows.removeAllExtensions()
|
||||
Windows.removeAllExtensions(win)
|
||||
|
||||
return events.emit('exit')
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ import _ from 'lodash'
|
||||
import Marionette from 'marionette-client'
|
||||
import { Command } from 'marionette-client/lib/marionette/message.js'
|
||||
import util from 'util'
|
||||
import Foxdriver from '@benmalka/foxdriver'
|
||||
import Foxdriver from 'foxdriver'
|
||||
import * as protocol from './protocol'
|
||||
|
||||
const errors = require('../errors')
|
||||
|
||||
@@ -36,6 +36,11 @@ const nullifyUnserializableValues = (obj) => {
|
||||
const handleEvent = function (options, bus, event, id, type, arg) {
|
||||
debug('got request for event: %s, %o', type, arg)
|
||||
|
||||
_.defaults(options, {
|
||||
windowOpenFn: Windows.open,
|
||||
getWindowByWebContentsFn: Windows.getByWebContents,
|
||||
})
|
||||
|
||||
const sendResponse = function (originalData = {}) {
|
||||
try {
|
||||
const data = nullifyUnserializableValues(originalData)
|
||||
@@ -161,12 +166,12 @@ const handleEvent = function (options, bus, event, id, type, arg) {
|
||||
.catch(sendErr)
|
||||
|
||||
case 'window:open':
|
||||
return Windows.open(options.projectRoot, arg)
|
||||
return options.windowOpenFn(options.projectRoot, arg)
|
||||
.then(send)
|
||||
.catch(sendErr)
|
||||
|
||||
case 'window:close':
|
||||
return Windows.getByWebContents(event.sender).destroy()
|
||||
return options.getWindowByWebContentsFn(event.sender).destroy()
|
||||
|
||||
case 'open:file':
|
||||
return fileOpener.openFile(arg)
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
const _ = require('lodash')
|
||||
const Promise = require('bluebird')
|
||||
const cyDesktop = require('@packages/desktop-gui')
|
||||
const contextMenu = require('electron-context-menu')
|
||||
const { BrowserWindow } = require('electron')
|
||||
const debug = require('debug')('cypress:server:windows')
|
||||
const cwd = require('../cwd')
|
||||
const savedState = require('../saved_state')
|
||||
|
||||
let windows = {}
|
||||
let recentlyCreatedWindow = false
|
||||
|
||||
const getUrl = function (type) {
|
||||
switch (type) {
|
||||
case 'INDEX':
|
||||
return cyDesktop.getPathToIndex()
|
||||
default:
|
||||
throw new Error(`No acceptable window type found for: '${type}'`)
|
||||
}
|
||||
}
|
||||
|
||||
const getByType = (type) => {
|
||||
return windows[type]
|
||||
}
|
||||
|
||||
const setWindowProxy = function (win) {
|
||||
if (!process.env.HTTP_PROXY) {
|
||||
return
|
||||
}
|
||||
|
||||
return win.webContents.session.setProxy({
|
||||
proxyRules: process.env.HTTP_PROXY,
|
||||
proxyBypassRules: process.env.NO_PROXY,
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
installExtension (path) {
|
||||
// extensions can only be installed for all BrowserWindows
|
||||
const name = BrowserWindow.addExtension(path)
|
||||
|
||||
debug('electron extension installed %o', { success: !!name, name, path })
|
||||
|
||||
if (!name) {
|
||||
throw new Error('Extension could not be installed.')
|
||||
}
|
||||
},
|
||||
|
||||
removeAllExtensions () {
|
||||
const extensions = _.keys(BrowserWindow.getExtensions())
|
||||
|
||||
debug('removing all electron extensions %o', extensions)
|
||||
|
||||
return extensions.forEach(BrowserWindow.removeExtension)
|
||||
},
|
||||
|
||||
reset () {
|
||||
windows = {}
|
||||
},
|
||||
|
||||
destroy (type) {
|
||||
let win
|
||||
|
||||
if (type && (win = getByType(type))) {
|
||||
return win.destroy()
|
||||
}
|
||||
},
|
||||
|
||||
get (type) {
|
||||
return getByType(type) || (() => {
|
||||
throw new Error(`No window exists for: '${type}'`)
|
||||
})()
|
||||
},
|
||||
|
||||
showAll () {
|
||||
return _.invoke(windows, 'showInactive')
|
||||
},
|
||||
|
||||
hideAllUnlessAnotherWindowIsFocused () {
|
||||
// bail if we have another focused window
|
||||
// or we are in the middle of creating a new one
|
||||
if (BrowserWindow.getFocusedWindow() || recentlyCreatedWindow) {
|
||||
return
|
||||
}
|
||||
|
||||
// else hide all windows
|
||||
return _.invoke(windows, 'hide')
|
||||
},
|
||||
|
||||
focusMainWindow () {
|
||||
return getByType('INDEX').show()
|
||||
},
|
||||
|
||||
getByWebContents (webContents) {
|
||||
return BrowserWindow.fromWebContents(webContents)
|
||||
},
|
||||
|
||||
_newBrowserWindow (options) {
|
||||
return new BrowserWindow(options)
|
||||
},
|
||||
|
||||
defaults (options = {}) {
|
||||
return _.defaultsDeep(options, {
|
||||
x: null,
|
||||
y: null,
|
||||
show: true,
|
||||
frame: true,
|
||||
width: null,
|
||||
height: null,
|
||||
minWidth: null,
|
||||
minHeight: null,
|
||||
devTools: false,
|
||||
trackState: false,
|
||||
contextMenu: false,
|
||||
recordFrameRate: null,
|
||||
// extension: null ## TODO add these once we update electron
|
||||
// devToolsExtension: null ## since these API's were added in 1.7.6
|
||||
onFocus () {},
|
||||
onBlur () {},
|
||||
onClose () {},
|
||||
onCrashed () {},
|
||||
onNewWindow () {},
|
||||
webPreferences: {
|
||||
partition: null,
|
||||
webSecurity: true,
|
||||
nodeIntegration: false,
|
||||
backgroundThrottling: false,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
create (projectRoot, options = {}) {
|
||||
let ts
|
||||
|
||||
options = this.defaults(options)
|
||||
|
||||
if (options.show === false) {
|
||||
options.frame = false
|
||||
options.webPreferences.offscreen = true
|
||||
}
|
||||
|
||||
options.webPreferences.webSecurity = !!options.chromeWebSecurity
|
||||
|
||||
if (options.partition) {
|
||||
options.webPreferences.partition = options.partition
|
||||
}
|
||||
|
||||
const win = this._newBrowserWindow(options)
|
||||
|
||||
win.on('blur', function (...args) {
|
||||
return options.onBlur.apply(win, args)
|
||||
})
|
||||
|
||||
win.on('focus', function (...args) {
|
||||
return options.onFocus.apply(win, args)
|
||||
})
|
||||
|
||||
win.once('closed', function (...args) {
|
||||
win.removeAllListeners()
|
||||
|
||||
return options.onClose.apply(win, args)
|
||||
})
|
||||
|
||||
// the webview loses focus on navigation, so we
|
||||
// have to refocus it everytime top navigates in headless mode
|
||||
// https://github.com/cypress-io/cypress/issues/2190
|
||||
if (options.show === false) {
|
||||
win.webContents.on('did-start-loading', () => {
|
||||
if (!win.isDestroyed()) {
|
||||
return win.focusOnWebView()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
win.webContents.on('crashed', function (...args) {
|
||||
return options.onCrashed.apply(win, args)
|
||||
})
|
||||
|
||||
win.webContents.on('new-window', function (...args) {
|
||||
return options.onNewWindow.apply(win, args)
|
||||
})
|
||||
|
||||
ts = options.trackState
|
||||
|
||||
if (ts) {
|
||||
this.trackState(projectRoot, options.isTextTerminal, win, ts)
|
||||
}
|
||||
|
||||
// open dev tools if they're true
|
||||
if (options.devTools) {
|
||||
// and possibly detach dev tools if true
|
||||
win.webContents.openDevTools()
|
||||
}
|
||||
|
||||
if (options.contextMenu) {
|
||||
// adds context menu with copy, paste, inspect element, etc
|
||||
contextMenu({
|
||||
showInspectElement: true,
|
||||
window: win,
|
||||
})
|
||||
}
|
||||
|
||||
return win
|
||||
},
|
||||
|
||||
open (projectRoot, options = {}) {
|
||||
// if we already have a window open based
|
||||
// on that type then just show + focus it!
|
||||
let win
|
||||
|
||||
win = getByType(options.type)
|
||||
|
||||
if (win) {
|
||||
win.show()
|
||||
|
||||
return Promise.resolve(win)
|
||||
}
|
||||
|
||||
recentlyCreatedWindow = true
|
||||
|
||||
_.defaults(options, {
|
||||
width: 600,
|
||||
height: 500,
|
||||
show: true,
|
||||
webPreferences: {
|
||||
preload: cwd('lib', 'ipc', 'ipc.js'),
|
||||
},
|
||||
})
|
||||
|
||||
if (!options.url) {
|
||||
options.url = getUrl(options.type)
|
||||
}
|
||||
|
||||
win = this.create(projectRoot, options)
|
||||
|
||||
debug('creating electron window with options %o', options)
|
||||
|
||||
windows[options.type] = win
|
||||
|
||||
win.webContents.id = _.uniqueId('webContents')
|
||||
|
||||
win.once('closed', () => {
|
||||
delete windows[options.type]
|
||||
})
|
||||
|
||||
// enable our url to be a promise
|
||||
// and wait for this to be resolved
|
||||
return Promise.join(
|
||||
options.url,
|
||||
setWindowProxy(win),
|
||||
)
|
||||
.spread((url) => {
|
||||
// navigate the window here!
|
||||
win.loadURL(url)
|
||||
|
||||
recentlyCreatedWindow = false
|
||||
}).thenReturn(win)
|
||||
},
|
||||
|
||||
trackState (projectRoot, isTextTerminal, win, keys) {
|
||||
const isDestroyed = () => {
|
||||
return win.isDestroyed()
|
||||
}
|
||||
|
||||
win.on('resize', _.debounce(() => {
|
||||
if (isDestroyed()) {
|
||||
return
|
||||
}
|
||||
|
||||
const [width, height] = win.getSize()
|
||||
const [x, y] = win.getPosition()
|
||||
const newState = {}
|
||||
|
||||
newState[keys.width] = width
|
||||
newState[keys.height] = height
|
||||
newState[keys.x] = x
|
||||
newState[keys.y] = y
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
}
|
||||
, 500))
|
||||
|
||||
win.on('moved', _.debounce(() => {
|
||||
if (isDestroyed()) {
|
||||
return
|
||||
}
|
||||
|
||||
const [x, y] = win.getPosition()
|
||||
const newState = {}
|
||||
|
||||
newState[keys.x] = x
|
||||
newState[keys.y] = y
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
}
|
||||
, 500))
|
||||
|
||||
win.webContents.on('devtools-opened', () => {
|
||||
const newState = {}
|
||||
|
||||
newState[keys.devTools] = true
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
})
|
||||
|
||||
return win.webContents.on('devtools-closed', () => {
|
||||
const newState = {}
|
||||
|
||||
newState[keys.devTools] = false
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
332
packages/server/lib/gui/windows.ts
Normal file
332
packages/server/lib/gui/windows.ts
Normal file
@@ -0,0 +1,332 @@
|
||||
import _ from 'lodash'
|
||||
import Bluebird from 'bluebird'
|
||||
import contextMenu from 'electron-context-menu'
|
||||
import { BrowserWindow } from 'electron'
|
||||
import Debug from 'debug'
|
||||
import cwd from '../cwd'
|
||||
import savedState from '../saved_state'
|
||||
const cyDesktop = require('@packages/desktop-gui')
|
||||
|
||||
const debug = Debug('cypress:server:windows')
|
||||
|
||||
export type WindowOptions = Electron.BrowserWindowConstructorOptions & {
|
||||
type?: 'INDEX'
|
||||
url?: string
|
||||
devTools?: boolean
|
||||
}
|
||||
|
||||
let windows = {}
|
||||
let recentlyCreatedWindow = false
|
||||
|
||||
const getUrl = function (type) {
|
||||
switch (type) {
|
||||
case 'INDEX':
|
||||
return cyDesktop.getPathToIndex()
|
||||
default:
|
||||
throw new Error(`No acceptable window type found for: '${type}'`)
|
||||
}
|
||||
}
|
||||
|
||||
const getByType = (type) => {
|
||||
return windows[type]
|
||||
}
|
||||
|
||||
const setWindowProxy = function (win) {
|
||||
if (!process.env.HTTP_PROXY) {
|
||||
return
|
||||
}
|
||||
|
||||
return win.webContents.session.setProxy({
|
||||
proxyRules: process.env.HTTP_PROXY,
|
||||
proxyBypassRules: process.env.NO_PROXY,
|
||||
})
|
||||
}
|
||||
|
||||
export function installExtension (win: BrowserWindow, path) {
|
||||
return win.webContents.session.loadExtension(path)
|
||||
.then((data) => {
|
||||
debug('electron extension installed %o', { data, path })
|
||||
})
|
||||
.catch((err) => {
|
||||
debug('error installing electron extension %o', { err, path })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
export function removeAllExtensions (win: BrowserWindow) {
|
||||
let extensions
|
||||
|
||||
try {
|
||||
extensions = win.webContents.session.getAllExtensions()
|
||||
|
||||
extensions.forEach(({ id }) => {
|
||||
win.webContents.session.removeExtension(id)
|
||||
})
|
||||
} catch (err) {
|
||||
debug('error removing all extensions %o', { err, extensions })
|
||||
}
|
||||
}
|
||||
|
||||
export function reset () {
|
||||
windows = {}
|
||||
}
|
||||
|
||||
export function destroy (type) {
|
||||
let win
|
||||
|
||||
if (type && (win = getByType(type))) {
|
||||
return win.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
export function get (type) {
|
||||
return getByType(type) || (() => {
|
||||
throw new Error(`No window exists for: '${type}'`)
|
||||
})()
|
||||
}
|
||||
|
||||
export function showAll () {
|
||||
return _.invoke(windows, 'showInactive')
|
||||
}
|
||||
|
||||
export function hideAllUnlessAnotherWindowIsFocused () {
|
||||
// bail if we have another focused window
|
||||
// or we are in the middle of creating a new one
|
||||
if (BrowserWindow.getFocusedWindow() || recentlyCreatedWindow) {
|
||||
return
|
||||
}
|
||||
|
||||
// else hide all windows
|
||||
return _.invoke(windows, 'hide')
|
||||
}
|
||||
|
||||
export function focusMainWindow () {
|
||||
return getByType('INDEX').show()
|
||||
}
|
||||
|
||||
export function getByWebContents (webContents) {
|
||||
return BrowserWindow.fromWebContents(webContents)
|
||||
}
|
||||
|
||||
export function _newBrowserWindow (options) {
|
||||
return new BrowserWindow(options)
|
||||
}
|
||||
|
||||
export function defaults (options = {}) {
|
||||
return _.defaultsDeep(options, {
|
||||
x: null,
|
||||
y: null,
|
||||
show: true,
|
||||
frame: true,
|
||||
width: null,
|
||||
height: null,
|
||||
minWidth: null,
|
||||
minHeight: null,
|
||||
devTools: false,
|
||||
trackState: false,
|
||||
contextMenu: false,
|
||||
recordFrameRate: null,
|
||||
onFocus () {},
|
||||
onBlur () {},
|
||||
onClose () {},
|
||||
onCrashed () {},
|
||||
onNewWindow () {},
|
||||
webPreferences: {
|
||||
partition: null,
|
||||
webSecurity: true,
|
||||
nodeIntegration: false,
|
||||
backgroundThrottling: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function create (projectRoot, _options: WindowOptions = {}, newBrowserWindow = _newBrowserWindow) {
|
||||
const options = defaults(_options)
|
||||
|
||||
if (options.show === false) {
|
||||
options.frame = false
|
||||
options.webPreferences.offscreen = true
|
||||
}
|
||||
|
||||
options.webPreferences.webSecurity = !!options.chromeWebSecurity
|
||||
|
||||
if (options.partition) {
|
||||
options.webPreferences.partition = options.partition
|
||||
}
|
||||
|
||||
const win = newBrowserWindow(options)
|
||||
|
||||
win.on('blur', function (...args) {
|
||||
return options.onBlur.apply(win, args)
|
||||
})
|
||||
|
||||
win.on('focus', function (...args) {
|
||||
return options.onFocus.apply(win, args)
|
||||
})
|
||||
|
||||
win.once('closed', function (...args) {
|
||||
win.removeAllListeners()
|
||||
|
||||
return options.onClose.apply(win, args)
|
||||
})
|
||||
|
||||
// the webview loses focus on navigation, so we
|
||||
// have to refocus it everytime top navigates in headless mode
|
||||
// https://github.com/cypress-io/cypress/issues/2190
|
||||
if (options.show === false) {
|
||||
win.webContents.on('did-start-loading', () => {
|
||||
if (!win.isDestroyed()) {
|
||||
return win.focusOnWebView()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
win.webContents.on('crashed', function (...args) {
|
||||
return options.onCrashed.apply(win, args)
|
||||
})
|
||||
|
||||
win.webContents.on('new-window', function (...args) {
|
||||
return options.onNewWindow.apply(win, args)
|
||||
})
|
||||
|
||||
if (options.trackState) {
|
||||
trackState(projectRoot, options.isTextTerminal, win, options.trackState)
|
||||
}
|
||||
|
||||
// open dev tools if they're true
|
||||
if (options.devTools) {
|
||||
// and possibly detach dev tools if true
|
||||
win.webContents.openDevTools()
|
||||
}
|
||||
|
||||
if (options.contextMenu) {
|
||||
// adds context menu with copy, paste, inspect element, etc
|
||||
contextMenu({
|
||||
showInspectElement: true,
|
||||
window: win,
|
||||
})
|
||||
}
|
||||
|
||||
return win
|
||||
}
|
||||
|
||||
export function open (projectRoot, options: WindowOptions = {}, newBrowserWindow = _newBrowserWindow) {
|
||||
// if we already have a window open based
|
||||
// on that type then just show + focus it!
|
||||
let win
|
||||
|
||||
win = getByType(options.type)
|
||||
|
||||
if (win) {
|
||||
win.show()
|
||||
|
||||
return Bluebird.resolve(win)
|
||||
}
|
||||
|
||||
recentlyCreatedWindow = true
|
||||
|
||||
_.defaults(options, {
|
||||
width: 600,
|
||||
height: 500,
|
||||
show: true,
|
||||
webPreferences: {
|
||||
preload: cwd('lib', 'ipc', 'ipc.js'),
|
||||
},
|
||||
})
|
||||
|
||||
if (!options.url) {
|
||||
options.url = getUrl(options.type)
|
||||
}
|
||||
|
||||
win = create(projectRoot, options, newBrowserWindow)
|
||||
|
||||
debug('creating electron window with options %o', options)
|
||||
|
||||
if (options.type) {
|
||||
windows[options.type] = win
|
||||
|
||||
win.once('closed', () => {
|
||||
delete windows[options.type!]
|
||||
})
|
||||
}
|
||||
|
||||
// enable our url to be a promise
|
||||
// and wait for this to be resolved
|
||||
return Bluebird.join(
|
||||
options.url,
|
||||
setWindowProxy(win),
|
||||
)
|
||||
.spread((url) => {
|
||||
// navigate the window here!
|
||||
win.loadURL(url)
|
||||
|
||||
recentlyCreatedWindow = false
|
||||
}).thenReturn(win)
|
||||
}
|
||||
|
||||
export function trackState (projectRoot, isTextTerminal, win, keys) {
|
||||
const isDestroyed = () => {
|
||||
return win.isDestroyed()
|
||||
}
|
||||
|
||||
win.on('resize', _.debounce(() => {
|
||||
if (isDestroyed()) {
|
||||
return
|
||||
}
|
||||
|
||||
const [width, height] = win.getSize()
|
||||
const [x, y] = win.getPosition()
|
||||
const newState = {}
|
||||
|
||||
newState[keys.width] = width
|
||||
newState[keys.height] = height
|
||||
newState[keys.x] = x
|
||||
newState[keys.y] = y
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
}
|
||||
, 500))
|
||||
|
||||
win.on('moved', _.debounce(() => {
|
||||
if (isDestroyed()) {
|
||||
return
|
||||
}
|
||||
|
||||
const [x, y] = win.getPosition()
|
||||
const newState = {}
|
||||
|
||||
newState[keys.x] = x
|
||||
newState[keys.y] = y
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
}
|
||||
, 500))
|
||||
|
||||
win.webContents.on('devtools-opened', () => {
|
||||
const newState = {}
|
||||
|
||||
newState[keys.devTools] = true
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
})
|
||||
|
||||
return win.webContents.on('devtools-closed', () => {
|
||||
const newState = {}
|
||||
|
||||
newState[keys.devTools] = false
|
||||
|
||||
return savedState.create(projectRoot, isTextTerminal)
|
||||
.then((state) => {
|
||||
return state.set(newState)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
"test-watch": "./test/support/watch test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@benmalka/foxdriver": "0.4.0",
|
||||
"@cypress/browserify-preprocessor": "2.2.4",
|
||||
"@cypress/commit-info": "2.2.0",
|
||||
"@cypress/get-windows-proxy": "1.6.1",
|
||||
@@ -59,6 +58,7 @@
|
||||
"firefox-profile": "1.3.1",
|
||||
"fix-path": "2.1.0",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"foxdriver": "0.1.1",
|
||||
"fs-extra": "8.1.0",
|
||||
"get-port": "5.1.1",
|
||||
"getos": "3.2.1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const e2e = require('../support/helpers/e2e').default
|
||||
import e2e from '../support/helpers/e2e'
|
||||
|
||||
describe('e2e issue 173', () => {
|
||||
e2e.setup()
|
||||
@@ -1,11 +1,5 @@
|
||||
context('before:browser:launch extension e2e', () => {
|
||||
it('has the expected extension', () => {
|
||||
if (Cypress.browser.name === 'electron') {
|
||||
cy.wrap(window.top).its('theExtensionLoaded').should('be.true')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cy.visit('/index.html')
|
||||
.get('#extension')
|
||||
.should('contain', 'inserted from extension!')
|
||||
|
||||
@@ -2,16 +2,7 @@ const path = require('path')
|
||||
|
||||
module.exports = (on) => {
|
||||
on('before:browser:launch', (browser, options) => {
|
||||
const { extensions } = options
|
||||
|
||||
if (browser.name === 'electron') {
|
||||
// electron doesn't support background pages yet, so load a devtools extension
|
||||
// instead which will work
|
||||
extensions.push(path.join(__dirname, '../../devtools-ext'))
|
||||
} else {
|
||||
extensions.push(path.join(__dirname, '../../../plugin-extension/ext'))
|
||||
}
|
||||
|
||||
options.extensions.push(path.join(__dirname, '../../../plugin-extension/ext'))
|
||||
options.preferences.devTools = true
|
||||
|
||||
return options
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<script>
|
||||
function addProperty () {
|
||||
chrome.devtools.inspectedWindow.onResourceAdded.addListener(() => {
|
||||
chrome.devtools.inspectedWindow.eval('window.theExtensionLoaded = true')
|
||||
})
|
||||
}
|
||||
|
||||
// sometimes chrome.devtools is undefined, most likely bug in chromium :|
|
||||
// this was causing flake in our e2e tests
|
||||
if (chrome.devtools) {
|
||||
addProperty()
|
||||
} else {
|
||||
setTimeout(addProperty, 1000)
|
||||
}
|
||||
</script>
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "e2e devtools ext",
|
||||
"version": "0",
|
||||
"description": "tests adding devtools extension into Cypress",
|
||||
"permissions": [
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"<all_urls>"
|
||||
],
|
||||
"content_scripts": [],
|
||||
"devtools_page": "devtools.html",
|
||||
"manifest_version": 2
|
||||
}
|
||||
@@ -135,15 +135,15 @@ describe('lib/browsers/electron', () => {
|
||||
plugins.has.returns(true)
|
||||
plugins.execute.resolves({ extensions: ['foo', 'bar'] })
|
||||
|
||||
Windows.installExtension.withArgs('bar').throws()
|
||||
Windows.installExtension.withArgs(sinon.match.any, 'bar').throws()
|
||||
|
||||
return electron.open('electron', this.url, this.options, this.automation)
|
||||
.then(() => {
|
||||
expect(Windows.removeAllExtensions).to.be.calledOnce
|
||||
|
||||
expect(Windows.installExtension).to.be.calledTwice
|
||||
expect(Windows.installExtension).to.be.calledWith('foo')
|
||||
expect(Windows.installExtension).to.be.calledWith('bar')
|
||||
expect(Windows.installExtension).to.be.calledWith(sinon.match.any, 'foo')
|
||||
expect(Windows.installExtension).to.be.calledWith(sinon.match.any, 'bar')
|
||||
|
||||
expect(this.options.onWarning).to.be.calledOnce
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import firefoxUtil from '../../../lib/browsers/firefox-util'
|
||||
import * as firefox from '../../../lib/browsers/firefox'
|
||||
import { EventEmitter } from 'events'
|
||||
import Marionette from 'marionette-client'
|
||||
import Foxdriver from '@benmalka/foxdriver'
|
||||
import Foxdriver from 'foxdriver'
|
||||
const mockfs = require('mock-fs')
|
||||
const FirefoxProfile = require('firefox-profile')
|
||||
const utils = require('../../../lib/browsers/utils')
|
||||
|
||||
@@ -17,9 +17,8 @@ const openProject = require(`${root}../lib/open_project`)
|
||||
const open = require(`${root}../lib/util/open`)
|
||||
const auth = require(`${root}../lib/gui/auth`)
|
||||
const logs = require(`${root}../lib/gui/logs`)
|
||||
const events = require(`${root}../lib/gui/events`)
|
||||
const events = require(`../../../lib/gui/events`)
|
||||
const dialog = require(`${root}../lib/gui/dialog`)
|
||||
const Windows = require(`${root}../lib/gui/windows`)
|
||||
const ensureUrl = require(`${root}../lib/util/ensure-url`)
|
||||
const konfig = require(`${root}../lib/konfig`)
|
||||
|
||||
@@ -206,11 +205,11 @@ describe('lib/gui/events', () => {
|
||||
loadURL () {},
|
||||
webContents: {},
|
||||
})
|
||||
|
||||
return sinon.stub(Windows, 'create').withArgs(this.options.projectRoot).returns(this.win)
|
||||
})
|
||||
|
||||
it('calls Windows#open with args and resolves with return of Windows.open', function () {
|
||||
it('calls windowOpenFn with args and resolves with return', function () {
|
||||
this.options.windowOpenFn = sinon.stub().rejects().withArgs({ type: 'INDEX ' }).resolves(this.win)
|
||||
|
||||
return this.handleEvent('window:open', { type: 'INDEX' })
|
||||
.then((assert) => {
|
||||
return assert.sendCalledWith(events.nullifyUnserializableValues(this.win))
|
||||
@@ -220,7 +219,7 @@ describe('lib/gui/events', () => {
|
||||
it('catches errors', function () {
|
||||
const err = new Error('foo')
|
||||
|
||||
sinon.stub(Windows, 'open').withArgs(this.options.projectRoot, { foo: 'bar' }).rejects(err)
|
||||
this.options.windowOpenFn = sinon.stub().withArgs(this.options.projectRoot, { foo: 'bar' }).rejects(err)
|
||||
|
||||
return this.handleEvent('window:open', { foo: 'bar' }).then((assert) => {
|
||||
return assert.sendErrCalledWith(err)
|
||||
@@ -230,11 +229,14 @@ describe('lib/gui/events', () => {
|
||||
|
||||
describe('window:close', () => {
|
||||
it('calls destroy on Windows#getByWebContents', function () {
|
||||
this.destroy = sinon.stub()
|
||||
sinon.stub(Windows, 'getByWebContents').withArgs(this.event.sender).returns({ destroy: this.destroy })
|
||||
const win = {
|
||||
destroy: sinon.stub(),
|
||||
}
|
||||
|
||||
this.options.getWindowByWebContentsFn = sinon.stub().withArgs(this.event.sender).returns(win)
|
||||
this.handleEvent('window:close')
|
||||
|
||||
expect(this.destroy).to.be.calledOnce
|
||||
expect(win.destroy).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
require('../../spec_helper')
|
||||
import '../../spec_helper'
|
||||
|
||||
import { expect } from 'chai'
|
||||
import 'sinon-chai'
|
||||
|
||||
import _ from 'lodash'
|
||||
import path from 'path'
|
||||
import Promise from 'bluebird'
|
||||
import { EventEmitter } from 'events'
|
||||
import { BrowserWindow } from 'electron'
|
||||
import * as Windows from '../../../lib/gui/windows'
|
||||
import savedState from '../../../lib/saved_state'
|
||||
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const EE = require('events').EventEmitter
|
||||
const { BrowserWindow } = require('electron')
|
||||
const cyDesktop = require('@packages/desktop-gui')
|
||||
const Windows = require(`${root}../lib/gui/windows`)
|
||||
const savedState = require(`${root}../lib/saved_state`)
|
||||
|
||||
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Cypress/0.0.0 Chrome/59.0.3071.115 Electron/1.8.2 Safari/537.36'
|
||||
|
||||
@@ -15,17 +19,15 @@ describe('lib/gui/windows', () => {
|
||||
beforeEach(function () {
|
||||
Windows.reset()
|
||||
|
||||
this.win = new EE()
|
||||
this.win = new EventEmitter()
|
||||
this.win.loadURL = sinon.stub()
|
||||
this.win.destroy = sinon.stub()
|
||||
this.win.getSize = sinon.stub().returns([1, 2])
|
||||
this.win.getPosition = sinon.stub().returns([3, 4])
|
||||
this.win.webContents = new EE()
|
||||
this.win.webContents = new EventEmitter()
|
||||
this.win.webContents.openDevTools = sinon.stub()
|
||||
this.win.webContents.userAgent = DEFAULT_USER_AGENT
|
||||
this.win.isDestroyed = sinon.stub().returns(false)
|
||||
|
||||
return sinon.stub(Windows, '_newBrowserWindow').returns(this.win)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -33,38 +35,31 @@ describe('lib/gui/windows', () => {
|
||||
})
|
||||
|
||||
context('.getByWebContents', () => {
|
||||
beforeEach(() => {
|
||||
return sinon.stub(BrowserWindow, 'fromWebContents')
|
||||
})
|
||||
|
||||
it('calls BrowserWindow.fromWebContents', () => {
|
||||
BrowserWindow.fromWebContents.withArgs('foo').returns('bar')
|
||||
sinon.stub(BrowserWindow, 'fromWebContents').withArgs('foo' as any).returns('bar' as any)
|
||||
|
||||
expect(Windows.getByWebContents('foo')).to.eq('bar')
|
||||
})
|
||||
})
|
||||
|
||||
context('.open', () => {
|
||||
beforeEach(function () {
|
||||
return sinon.stub(Windows, 'create').returns(this.win)
|
||||
})
|
||||
|
||||
it('sets default options', () => {
|
||||
const options = {
|
||||
it('sets default options', function () {
|
||||
const options: Windows.WindowOptions = {
|
||||
type: 'INDEX',
|
||||
}
|
||||
|
||||
return Windows.open('/path/to/project', options)
|
||||
return Windows.open('/path/to/project', options, () => this.win)
|
||||
.then((win) => {
|
||||
expect(options).to.deep.eq({
|
||||
expect(options).to.include({
|
||||
height: 500,
|
||||
width: 600,
|
||||
type: 'INDEX',
|
||||
show: true,
|
||||
url: cyDesktop.getPathToIndex(),
|
||||
webPreferences: {
|
||||
preload: path.resolve('lib', 'ipc', 'ipc.js'),
|
||||
},
|
||||
})
|
||||
|
||||
expect(options.webPreferences).to.include({
|
||||
preload: path.resolve('lib', 'ipc', 'ipc.js'),
|
||||
})
|
||||
|
||||
expect(win.loadURL).to.be.calledWith(cyDesktop.getPathToIndex())
|
||||
@@ -74,10 +69,10 @@ describe('lib/gui/windows', () => {
|
||||
|
||||
context('.create', () => {
|
||||
it('opens dev tools if saved state is open', function () {
|
||||
Windows.create('/foo/', { devTools: true })
|
||||
Windows.create('/foo/', { devTools: true }, () => this.win)
|
||||
expect(this.win.webContents.openDevTools).to.be.called
|
||||
|
||||
Windows.create('/foo/', {})
|
||||
Windows.create('/foo/', {}, () => this.win)
|
||||
|
||||
expect(this.win.webContents.openDevTools).not.to.be.calledTwice
|
||||
})
|
||||
@@ -3,7 +3,7 @@ set e+x
|
||||
|
||||
echo "This script should be run from cypress's root"
|
||||
|
||||
name=cypress/browsers:node12.13.0-chrome80-ff74
|
||||
name=cypress/browsers:node12.14.1-chrome83-ff77
|
||||
echo "Pulling CI container $name"
|
||||
|
||||
docker pull $name
|
||||
|
||||
32
yarn.lock
32
yarn.lock
@@ -1427,18 +1427,6 @@
|
||||
jsonpointer "^4.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
"@benmalka/foxdriver@0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@benmalka/foxdriver/-/foxdriver-0.4.0.tgz#aecd158a785a09e104da036efe7611a13af4ed11"
|
||||
integrity sha512-Uc9n5TTRV2AhfYaqkaDc5k72pfKxyd6LDVrQJyNLZ7uY4ThgEcQMjpVRkB8C7v16gKhubH4gmD0lad5pGvDUBg==
|
||||
dependencies:
|
||||
fs-extra "^4.0.1"
|
||||
get-port "^3.2.0"
|
||||
npmlog "^4.1.2"
|
||||
safe-buffer "^5.1.1"
|
||||
tcp-port-used "^1.0.1"
|
||||
tmp "0.0.33"
|
||||
|
||||
"@chromaui/localtunnel@1.10.1":
|
||||
version "1.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@chromaui/localtunnel/-/localtunnel-1.10.1.tgz#34da7dab7055a16b1b9034a9eb7e3054ebec4b98"
|
||||
@@ -10597,10 +10585,10 @@ electron-to-chromium@^1.3.413:
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.441.tgz#094f71b992dca5bc96b798cfbaf37dc76302015a"
|
||||
integrity sha512-leBfJwLuyGs1jEei2QioI+PjVMavmUIvPYidE8dCCYWLAq0uefhN3NYgDNb8WxD3uiUNnJ3ScMXg0upSlwySzQ==
|
||||
|
||||
electron@8.3.1:
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-8.3.1.tgz#79e98c4d5b8e7c09a8a811f1aa78903f0c692721"
|
||||
integrity sha512-VZpgLVFyD2SwFDkO9rwUcNgrAMah+g38FEtALGxli8bRVTbcHl8bt21szfa0YUWpc6hWcaf6JdZjqDS5q73Bsg==
|
||||
electron@9.0.5:
|
||||
version "9.0.5"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-9.0.5.tgz#189ee117cc2a2777cccf40fae0766acec5faae57"
|
||||
integrity sha512-bnL9H48LuQ250DML8xUscsKiuSu+xv5umXbpBXYJ0BfvYVmFfNbG3jCfhrsH7aP6UcQKVxOG1R/oQExd0EFneQ==
|
||||
dependencies:
|
||||
"@electron/get" "^1.0.1"
|
||||
"@types/node" "^12.0.12"
|
||||
@@ -12426,6 +12414,18 @@ forwarded@~0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
|
||||
|
||||
foxdriver@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/foxdriver/-/foxdriver-0.1.1.tgz#b66e0fb1f495b0139c7a0a5a5f31541b2adf0b23"
|
||||
integrity sha512-ZJ6u9kzCkmDo7OVIzqF+KlMRLc+W53GCzglaLhFG1ixMliEC7o6TeucYd1XpSacpmZnPRVQE+byyR7LXC84htA==
|
||||
dependencies:
|
||||
fs-extra "^4.0.1"
|
||||
get-port "^3.2.0"
|
||||
npmlog "^4.1.2"
|
||||
safe-buffer "^5.1.1"
|
||||
tcp-port-used "^1.0.1"
|
||||
tmp "0.0.33"
|
||||
|
||||
fragment-cache@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
|
||||
|
||||
Reference in New Issue
Block a user