Skip to content

Commit

Permalink
Merge branch 'develop' into fix/audit-and-update-readmes
Browse files Browse the repository at this point in the history
  • Loading branch information
Barthélémy Ledoux authored Apr 1, 2021
2 parents fa4c99c + 8ed9e99 commit 5028baf
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 56 deletions.
7 changes: 6 additions & 1 deletion packages/launcher/lib/browsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export function launch (
browser: FoundBrowser,
url: string,
args: string[] = [],
defaultBrowserEnv = {},
) {
log('launching browser %o', { browser, url })

Expand All @@ -110,7 +111,11 @@ export function launch (

log('spawning browser with args %o', { args })

const proc = cp.spawn(browser.path, args, { stdio: ['ignore', 'pipe', 'pipe'] })
// allow setting default env vars such as MOZ_HEADLESS_WIDTH
// but only if it's not already set by the environment
const env = Object.assign({}, defaultBrowserEnv, process.env)

const proc = cp.spawn(browser.path, args, { stdio: ['ignore', 'pipe', 'pipe'], env })

proc.stdout.on('data', (buf) => {
log('%s stdout: %s', browser.name, String(buf).trim())
Expand Down
2 changes: 1 addition & 1 deletion packages/server/__snapshots__/3_config_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ exports['e2e config applies defaultCommandTimeout globally 1'] = `
(Screenshots)
- /XXX/XXX/XXX/cypress/screenshots/dom_times_out_spec.js/short defaultCommandTimeo (1280x720)
- /XXX/XXX/XXX/cypress/screenshots/dom_times_out_spec.js/short defaultCommandTimeo (1920x1080)
ut -- times out looking for a missing element (failed).png
Expand Down
4 changes: 2 additions & 2 deletions packages/server/lib/browsers/chrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,9 @@ export = {
if (isHeadless) {
args.push('--headless')

// set the window size for headless to a better default
// set default headless size to 1920x1080
// https://github.com/cypress-io/cypress/issues/6210
args.push('--window-size=1280,720')
args.push('--window-size=1920,1080')
}

// force ipv4
Expand Down
15 changes: 15 additions & 0 deletions packages/server/lib/browsers/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ module.exports = {
},
}

if (options.browser.isHeadless) {
// prevents a tiny 1px padding around the window
// causing screenshots/videos to be off by 1px
options.resizable = false
}

return _.defaultsDeep({}, options, defaults)
},

Expand All @@ -161,6 +167,15 @@ module.exports = {
_render (url, projectRoot, automation, options = {}) {
const win = Windows.create(projectRoot, options)

if (options.browser.isHeadless) {
// seemingly the only way to force headless to a certain screen size
// electron BrowserWindow constructor is not respecting width/height options
win.setSize(options.width, options.height)
} else {
// we maximize in headed mode, this is consistent with chrome+firefox headed
win.maximize()
}

automation.use(_getAutomation(win, options))

return this._launch(win, url, automation, options)
Expand Down
61 changes: 53 additions & 8 deletions packages/server/lib/browsers/firefox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,37 @@ const defaultPreferences = {
'browser.helperApps.neverAsk.saveToDisk': downloadMimeTypes,
}

const FIREFOX_HEADED_USERCSS = `\
#urlbar:not(.megabar), #urlbar.megabar > #urlbar-background, #searchbar {
background: -moz-Field !important;
color: -moz-FieldText !important;
}`

const FIREFOX_HEADLESS_USERCSS = `\
#urlbar {
height: 0px !important;
min-height: 0px !important;
overflow: hidden !important;
}
#toolbar {
height: 0px !important;
min-height: 0px !important;
overflow: hidden !important;
}
toolbar {
height: 0px !important;
min-height: 0px !important;
overflow: hidden !important;
}
#titlebar {
height: 0px !important;
min-height: 0px !important;
overflow: hidden !important;
display: none;
}
`

export function _createDetachedInstance (browserInstance: BrowserInstance): BrowserInstance {
const detachedInstance: BrowserInstance = new EventEmitter() as BrowserInstance

Expand Down Expand Up @@ -339,6 +370,10 @@ export async function open (browser: Browser, url, options: any = {}): Promise<B

if (browser.isHeadless) {
defaultLaunchOptions.args.push('-headless')
// we don't need to specify width/height since MOZ_HEADLESS_ env vars will be set
// and the browser will spawn maximized. The user may still supply these args to override
// defaultLaunchOptions.args.push('--width=1920')
// defaultLaunchOptions.args.push('--height=1081')
}

debug('firefox open %o', options)
Expand Down Expand Up @@ -428,18 +463,23 @@ export async function open (browser: Browser, url, options: any = {}): Promise<B
const userCSSPath = path.join(profileDir, 'chrome')

if (!await fs.pathExists(path.join(userCSSPath, 'userChrome.css'))) {
const userCss = `
#urlbar:not(.megabar), #urlbar.megabar > #urlbar-background, #searchbar {
background: -moz-Field !important;
color: -moz-FieldText !important;
}
`

try {
await fs.mkdir(userCSSPath)
} catch {
// probably the folder already exists, this is fine
}

// if we're headed we change the yellow automation mode url bar back to a normal color
//
// if we're headless we use userCss to 'trick' the browser
// into having a consistent browser window size that's near-fullscreen
// however it unfortunately still leaves 1px of padding at the top)
// without this trick there would be ~74px of padding at the top instead of 1px.
//
// TODO: allow configuring userCss through launchOptions

const userCss = options.browser.isHeadless ? FIREFOX_HEADLESS_USERCSS : FIREFOX_HEADED_USERCSS

await fs.writeFile(path.join(profileDir, 'chrome', 'userChrome.css'), userCss)
}

Expand All @@ -450,7 +490,12 @@ export async function open (browser: Browser, url, options: any = {}): Promise<B

debug('launch in firefox', { url, args: launchOptions.args })

const browserInstance = await utils.launch(browser, 'about:blank', launchOptions.args)
const browserInstance = await utils.launch(browser, 'about:blank', launchOptions.args, {
// sets headless resolution to 1920x1080 by default
// user can overwrite this default with these env vars or --height, --width arguments
MOZ_HEADLESS_WIDTH: '1920',
MOZ_HEADLESS_HEIGHT: '1081',
})

await firefoxUtil.setup({ extensions: launchOptions.extensions, url, foxdriverPort, marionettePort })
.catch((err) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/server/lib/modes/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@ const getChromeProps = (writeVideoFrame) => {
const getElectronProps = (isHeaded, writeVideoFrame, onError) => {
return _
.chain({
width: 1280,
height: 720,
width: 1920,
height: 1080,
show: isHeaded,
onCrashed () {
const err = errors.get('RENDERER_CRASHED')
Expand Down
5 changes: 2 additions & 3 deletions packages/server/test/e2e/5_headless_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ describe('e2e headless', function () {
})
})

e2e.it('launches maximized by default in headless mode (1280x720)', {
browser: 'chrome',
e2e.it('launches maximized by default in headless mode (1920x1080)', {
headed: false,
project: Fixtures.projectPath('screen-size'),
spec: '720p.spec.js',
spec: 'default_size.spec.js',
})
})
3 changes: 3 additions & 0 deletions packages/server/test/integration/cypress_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,9 @@ describe('lib/cypress', () => {
},
}

ee.maximize = sinon.stub
ee.setSize = sinon.stub

sinon.stub(browserUtils, 'launch').resolves(ee)
sinon.stub(Windows, 'create').returns(ee)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const http = require('http')
const Jimp = require('jimp')
const path = require('path')
const Promise = require('bluebird')
const { useFixedFirefoxResolution } = require('../../../utils')
const { useFixedBrowserLaunchSize } = require('../../../utils')

/**
* @type {Cypress.PluginConfig}
Expand Down Expand Up @@ -53,7 +53,7 @@ module.exports = (on, config) => {
})

on('before:browser:launch', (browser, options) => {
useFixedFirefoxResolution(browser, options, config)
useFixedBrowserLaunchSize(browser, options, config)

if (browser.family === 'firefox' && process.env.FIREFOX_FORCE_STRICT_SAMESITE) {
// @see https://www.jardinesoftware.net/2019/10/28/samesite-by-default-in-2020/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="cypress" />

const { useFixedFirefoxResolution } = require('../../../utils')
const { useFixedBrowserLaunchSize } = require('../../../utils')

/**
* @type {Cypress.PluginConfig}
Expand All @@ -11,7 +11,7 @@ module.exports = (on, config) => {
}

on('before:browser:launch', (browser, options) => {
useFixedFirefoxResolution(browser, options, config)
useFixedBrowserLaunchSize(browser, options, config)

return options
})
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
describe('windowSize', () => {
it('spawns with correct default size', () => {
// assert the browser was spawned at 1920x1080 and is full size
// normally e2e tests spawn at fixed size, but this spec should be spawned without passing any width/height arguments in plugins file.
// TODO: look into fixing screen/available height and width
expect({
innerWidth: top.window.innerWidth,
innerHeight: top.window.innerHeight,
// screenWidth: top.screen.width,
// screenHeight: top.screen.height,
// availWidth: top.screen.availWidth,
// availHeight: top.screen.availHeight,
}).deep.eq({
innerWidth: 1920,
innerHeight: 1080,
// screenWidth: 1920,
// screenHeight: 1080,
// availWidth: 1920,
// availHeight: 1080,
})
})
})
18 changes: 13 additions & 5 deletions packages/server/test/support/fixtures/projects/utils.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
module.exports = {
useFixedFirefoxResolution (browser, options, config) {
if (browser.family === 'firefox' && !config.env['NO_RESIZE']) {
useFixedBrowserLaunchSize (browser, options, config) {
if (config.env['NO_RESIZE']) return

if (browser.family === 'firefox') {
// this is needed to ensure correct error screenshot / video recording
// resolution of exactly 1280x720 (height must account for firefox url bar)
options.args = options.args.concat(
['-width', '1280', '-height', '794'],
// resolution of exactly 1280x720
// (height must account for firefox url bar, which we can only shrink to 1px)
options.args.push(
'-width', '1280', '-height', '721',
)
} else if (browser.name === 'electron') {
options.preferences.width = 1280
options.preferences.height = 720
} else if (browser.family === 'chromium') {
options.args.push('--window-size=1280,720')
}
},
}
2 changes: 1 addition & 1 deletion packages/server/test/unit/browsers/chrome_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('lib/browsers/chrome', () => {

expect(args).to.include.members([
'--headless',
'--window-size=1280,720',
'--window-size=1920,1080',
])
})
})
Expand Down
28 changes: 22 additions & 6 deletions packages/server/test/unit/browsers/electron_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ describe('lib/browsers/electron', () => {
some: 'var',
projectRoot: '/foo/',
onWarning: sinon.stub().returns(),
browser: {
isHeadless: false,
},
}

this.automation = new Automation('foo', 'bar', 'baz')
Expand Down Expand Up @@ -278,33 +281,46 @@ describe('lib/browsers/electron', () => {

context('._render', () => {
beforeEach(function () {
this.newWin = {}
this.newWin = {
maximize: sinon.stub(),
setSize: sinon.stub(),
}

sinon.stub(menu, 'set')
sinon.stub(electron, '_setProxy').resolves()
sinon.stub(electron, '_launch').resolves()

return sinon.stub(Windows, 'create')
.withArgs(this.options.projectRoot, this.options)
.returns(this.newWin)
})

it('creates window instance and calls launch with window', function () {
return electron._render(this.url, this.options.projectRoot, this.automation, this.options)
.then(() => {
expect(Windows.create).to.be.calledWith(this.options.projectRoot, this.options)

expect(this.newWin.maximize).called
expect(this.newWin.setSize).not.called
expect(electron._launch).to.be.calledWith(this.newWin, this.url, this.automation, this.options)
})
})

it('calls setSize on electron window if headless', function () {
const options = { ...this.options, browser: { isHeadless: true }, width: 100, height: 200 }

return electron._render(this.url, this.options.projectRoot, this.automation, options)
.then(() => {
expect(this.newWin.maximize).not.called
expect(this.newWin.setSize).calledWith(100, 200)
})
})

it('registers onRequest automation middleware', function () {
sinon.spy(this.automation, 'use')

return electron._render(this.url, this.options.projectRoot, this.automation, this.options)
.then(() => {
expect(Windows.create).to.be.calledWith(this.options.projectRoot, this.options)
expect(this.automation.use).to.be.called

expect(this.automation.use.lastCall.args[0].onRequest).to.be.a('function')
})
})
Expand Down Expand Up @@ -366,14 +382,14 @@ describe('lib/browsers/electron', () => {
})

it('.onFocus', function () {
let opts = electron._defaultOptions('/foo', this.state, { show: true })
let opts = electron._defaultOptions('/foo', this.state, { show: true, browser: {} })

opts.onFocus()
expect(menu.set).to.be.calledWith({ withDevTools: true })

menu.set.reset()

opts = electron._defaultOptions('/foo', this.state, { show: false })
opts = electron._defaultOptions('/foo', this.state, { show: false, browser: {} })
opts.onFocus()

expect(menu.set).not.to.be.called
Expand Down
Loading

0 comments on commit 5028baf

Please sign in to comment.