Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to zoom in / out in Electron browser #4728

Merged
merged 9 commits into from
Jul 18, 2019
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@
"autoFix": false
},
],
"eslint.enable": true,
}
27 changes: 24 additions & 3 deletions packages/server/lib/gui/menu.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const _ = require('lodash')
const os = require('os')
const { Menu, shell } = require('electron')
const { Menu } = require('electron')
const { shell } = require('electron')

const appData = require('../util/app_data')
const open = require('../util/open')
Expand All @@ -13,8 +14,8 @@ module.exports = {
withDevTools: false,
})

//# this set by modes/interactive.coffee and needs to be preserved if the menu
//# is set again by launcher.coffee when the Electron browser is run
// this set by modes/interactive.coffee and needs to be preserved if the menu
// is set again by launcher.coffee when the Electron browser is run
if (options.onLogOutClicked) {
({ onLogOutClicked } = options)
}
Expand Down Expand Up @@ -99,6 +100,26 @@ module.exports = {
},
],
},
{
label: 'View',
submenu: [
{
label: 'Actual Size',
accelerator: 'CmdOrCtrl+0',
role: 'resetzoom',
},
{
label: 'Zoom In',
accelerator: 'CmdOrCtrl+Plus',
role: 'zoomin',
},
{
label: 'Zoom Out',
accelerator: 'CmdOrCtrl+-',
role: 'zoomout',
},
],
},
{
label: 'Window',
role: 'window',
Expand Down
9 changes: 7 additions & 2 deletions packages/server/test/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{
"globals": {
"root": true,
"sinon": true
"expect": "readonly",
"mockery": "readonly",
"nock": "readonly",
"proxyquire": "readonly",
"root": "readonly",
"sinon": "readonly",
"supertest": "readonly"
},
"extends": [
"plugin:@cypress/dev/tests"
Expand Down
1 change: 0 additions & 1 deletion packages/server/test/integration/cli_spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ R = require("ramda")
cp = require("child_process")
pr = require("../support/helpers/process")
pkg = require("../../package.json")
root = require("@packages/root")
execa = require("execa")
semver = require("semver")

Expand Down
138 changes: 68 additions & 70 deletions packages/server/test/unit/gui/menu_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const appData = require(`${root}../lib/util/app_data`)
const open = require(`${root}../lib/util/open`)
const menu = require(`${root}../lib/gui/menu`)

const getMenuItem = (label) => {
const getMenuItem = function (label) {
return _.find(electron.Menu.buildFromTemplate.lastCall.args[0], { label })
}

Expand All @@ -32,17 +32,16 @@ describe('gui/menu', function () {
menu.set()

expect(electron.Menu.buildFromTemplate).to.be.called

return expect(electron.Menu.setApplicationMenu).to.be.calledWith('menu')
expect(electron.Menu.setApplicationMenu).to.be.calledWith('menu')
})

context('Cypress', () => {
describe('on macOS', () => {
context('Cypress', function () {
describe('on macOS', function () {
it('contains about, services, hide, hide others, show all, quit', () => {
menu.set()
const labels = getLabels(getMenuItem('Cypress').submenu)

return expect(labels).to.eql([
expect(labels).to.eql([
'About Cypress',
'Services',
'Hide Cypress',
Expand All @@ -63,35 +62,32 @@ describe('gui/menu', function () {
expect(getSubMenuItem(cyMenu, 'Hide Others').role).to.equal('hideothers')
expect(getSubMenuItem(cyMenu, 'Hide Others').accelerator).to.equal('Command+Shift+H')
expect(getSubMenuItem(cyMenu, 'Show All').role).to.equal('unhide')

return expect(getSubMenuItem(cyMenu, 'Quit').accelerator).to.equal('Command+Q')
expect(getSubMenuItem(cyMenu, 'Quit').accelerator).to.equal('Command+Q')
})

return it('exits process when Quit is clicked', () => {
it('exits process when Quit is clicked', () => {
sinon.stub(process, 'exit')
menu.set()
getSubMenuItem(getMenuItem('Cypress'), 'Quit').click()

return expect(process.exit).to.be.calledWith(0)
expect(process.exit).to.be.calledWith(0)
})
})

return describe('other OS', () => {
return it('does not exist', () => {
describe('other OS', () => {
it('does not exist', () => {
os.platform.returns('linux')
menu.set()

return expect(getMenuItem('Cypress')).to.be.undefined
expect(getMenuItem('Cypress')).to.be.undefined
})
})
})

context('File', () => {
context('File', function () {
it('contains changelog, logout, close window', () => {
menu.set()
const labels = getLabels(getMenuItem('File').submenu)

return expect(labels).to.eql([
expect(labels).to.eql([
'Changelog',
'Manage Account',
'Log Out',
Expand All @@ -103,32 +99,28 @@ describe('gui/menu', function () {
it('opens changelog when Changelog is clicked', () => {
menu.set()
getSubMenuItem(getMenuItem('File'), 'Changelog').click()

return expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/changelog')
expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/changelog')
})

it('opens dashboard when Manage Account is clicked', () => {
menu.set()
getSubMenuItem(getMenuItem('File'), 'Manage Account').click()

return expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/dashboard')
expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/dashboard')
})

it('opens app data directory when View App Data is clicked', () => {
sinon.stub(open, 'opn')
menu.set()
getSubMenuItem(getMenuItem('File'), 'View App Data').click()

return expect(open.opn).to.be.calledWith(appData.path())
expect(open.opn).to.be.calledWith(appData.path())
})

it('calls logout callback when Log Out is clicked', () => {
const onLogOutClicked = sinon.stub()

menu.set({ onLogOutClicked })
getSubMenuItem(getMenuItem('File'), 'Log Out').click()

return expect(onLogOutClicked).to.be.called
expect(onLogOutClicked).to.be.called
})

it('calls original logout callback when menu is reset without new callback', () => {
Expand All @@ -137,22 +129,17 @@ describe('gui/menu', function () {
menu.set({ onLogOutClicked })
menu.set()
getSubMenuItem(getMenuItem('File'), 'Log Out').click()

return expect(onLogOutClicked).to.be.called
expect(onLogOutClicked).to.be.called
})

it('is noop when Log Out is clicked with no callback', () => {
menu.set()

return expect(() => {
return getSubMenuItem(getMenuItem('File'), 'Log Out').click()
}).not.to.throw()
expect(() => getSubMenuItem(getMenuItem('File'), 'Log Out').click()).not.to.throw()
})

return it('binds Close Window to shortcut', () => {
it('binds Close Window to shortcut', () => {
menu.set()

return expect(getSubMenuItem(getMenuItem('File'), 'Close Window')).to.eql({
expect(getSubMenuItem(getMenuItem('File'), 'Close Window')).to.eql({
label: 'Close Window',
accelerator: 'CmdOrCtrl+W',
role: 'close',
Expand All @@ -161,10 +148,10 @@ describe('gui/menu', function () {
})

context('Edit', () => {
return it('contains undo, redo, cut, copy, paste, selectall', () => {
it('contains undo, redo, cut, copy, paste, selectall', () => {
menu.set()

return expect(getMenuItem('Edit').submenu).to.eql([
expect(getMenuItem('Edit').submenu).to.eql([
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
Expand Down Expand Up @@ -202,11 +189,35 @@ describe('gui/menu', function () {
})
})

context('View', () => {
it('contains zoom actions', () => {
menu.set()

expect(getMenuItem('View').submenu).to.eql([
{
label: 'Actual Size',
accelerator: 'CmdOrCtrl+0',
role: 'resetzoom',
},
{
label: 'Zoom In',
accelerator: 'CmdOrCtrl+Plus',
role: 'zoomin',
},
{
label: 'Zoom Out',
accelerator: 'CmdOrCtrl+-',
role: 'zoomout',
},
])
})
})

context('Window', () => {
return it('contains minimize', () => {
it('contains minimize', () => {
menu.set()

return expect(getMenuItem('Window')).to.eql({
expect(getMenuItem('Window')).to.eql({
label: 'Window',
role: 'window',
submenu: [
Expand All @@ -225,7 +236,7 @@ describe('gui/menu', function () {
menu.set()
const labels = getLabels(getMenuItem('Help').submenu)

return expect(labels).to.eql([
expect(labels).to.eql([
'Support',
'Documentation',
'Download Chromium',
Expand All @@ -236,46 +247,40 @@ describe('gui/menu', function () {
it('opens chat when Support is clicked', () => {
menu.set()
getMenuItem('Help').submenu[0].click()

return expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/support')
expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/support')
})

it('opens docs when Documentation is clicked', () => {
menu.set()
getMenuItem('Help').submenu[1].click()

return expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io')
expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io')
})

it('opens chromium downloads when Download Chromium is clicked', () => {
menu.set()
getMenuItem('Help').submenu[2].click()

return expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/chromium-downloads')
expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/chromium-downloads')
})

return it('opens new issue when Report an Issue is clicked', () => {
it('opens new issue when Report an Issue is clicked', () => {
menu.set()
getMenuItem('Help').submenu[3].click()

return expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/new-issue')
expect(electron.shell.openExternal).to.be.calledWith('https://on.cypress.io/new-issue')
})
})

return context('Developer Tools', function () {
context('Developer Tools', () => {
it('does not exist by default', () => {
menu.set()

return expect(getMenuItem('Developer Tools')).to.be.undefined
expect(getMenuItem('Developer Tools')).to.be.undefined
})

it('does not exist by when withDevTools is false', () => {
menu.set({ withDevTools: false })

return expect(getMenuItem('Developer Tools')).to.be.undefined
expect(getMenuItem('Developer Tools')).to.be.undefined
})

return describe('when withDevTools is true', function () {
describe('when withDevTools is true', () => {
beforeEach(function () {
menu.set({ withDevTools: true })
this.devSubmenu = getMenuItem('Developer Tools').submenu
Expand All @@ -284,53 +289,46 @@ describe('gui/menu', function () {
it('exists and contains reload, toggle', function () {
const labels = getLabels(this.devSubmenu)

return expect(labels).to.eql([
expect(labels).to.eql([
'Reload',
'Toggle Developer Tools',
])
})

it('sets shortcut for Reload', function () {
return expect(this.devSubmenu[0].accelerator).to.equal('CmdOrCtrl+R')
expect(this.devSubmenu[0].accelerator).to.equal('CmdOrCtrl+R')
})

it('reloads focused window when Reload is clicked', function () {
const reload = sinon.stub()

this.devSubmenu[0].click(null, { reload })

return expect(reload).to.be.called
expect(reload).to.be.called
})

it('is noop if no focused window when Reload is clicked', function () {
return expect(() => {
return this.devSubmenu[0].click()
}).not.to.throw()
expect(() => this.devSubmenu[0].click()).not.to.throw()
})

it('sets shortcut for Toggle Developer Tools when macOS', function () {
return expect(this.devSubmenu[1].accelerator).to.equal('Alt+Command+I')
expect(this.devSubmenu[1].accelerator).to.equal('Alt+Command+I')
})

it('sets shortcut for Toggle Developer Tools when not macOS', () => {
os.platform.returns('linux')
menu.set({ withDevTools: true })

return expect(getMenuItem('Developer Tools').submenu[1].accelerator).to.equal('Ctrl+Shift+I')
expect(getMenuItem('Developer Tools').submenu[1].accelerator).to.equal('Ctrl+Shift+I')
})

it('toggles dev tools on focused window when Toggle Developer Tools is clicked', function () {
const toggleDevTools = sinon.stub()

this.devSubmenu[1].click(null, { toggleDevTools })

return expect(toggleDevTools).to.be.called
expect(toggleDevTools).to.be.called
})

return it('is noop if no focused window when Toggle Developer Tools is clicked', function () {
return expect(() => {
return this.devSubmenu[1].click()
}).not.to.throw()
it('is noop if no focused window when Toggle Developer Tools is clicked', function () {
expect(() => this.devSubmenu[1].click()).not.to.throw()
})
})
})
Expand Down