From 51bf569fce840b751e29aab1ef974325ec272f98 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Fri, 28 Apr 2017 19:38:12 -0400 Subject: [PATCH] Allow devtools close via keyboard shortcut Fix #45 --- app/browser/menu.js | 15 +- app/browser/reducers/tabsReducer.js | 24 +- app/browser/tabs.js | 28 +- app/common/state/tabState.js | 6 +- js/actions/appActions.js | 9 + js/constants/appConstants.js | 1 + .../app/browser/reducers/tabsReducerTest.js | 166 ++++---- test/unit/app/browser/tabsTest.js | 370 ++++++++++++++++++ test/unit/app/common/state/tabStateTest.js | 12 +- test/unit/lib/fakeElectron.js | 11 +- 10 files changed, 515 insertions(+), 127 deletions(-) create mode 100644 test/unit/app/browser/tabsTest.js diff --git a/app/browser/menu.js b/app/browser/menu.js index b5dfe45878..442b3964b1 100644 --- a/app/browser/menu.js +++ b/app/browser/menu.js @@ -27,6 +27,7 @@ const {getByTabId} = require('../common/state/tabState') const getSetting = require('../../js/settings').getSetting const locale = require('../locale') const {isSiteBookmarked, siteSort} = require('../../js/state/siteUtil') +const tabState = require('../../app/common/state/tabState') const isDarwin = process.platform === 'darwin' const isLinux = process.platform === 'linux' @@ -70,16 +71,14 @@ const createFileSubmenu = () => { }, CommonMenu.separatorMenuItem, { - // this should be disabled when - // no windows are active + // This should be disabled when no windows are active. label: locale.translation('closeTab'), accelerator: 'CmdOrCtrl+W', click: function (item, focusedWindow) { - CommonMenu.sendToFocusedWindow(focusedWindow, [messages.SHORTCUT_CLOSE_FRAME]) + appActions.activeWebContentsClosed() } }, { - // this should be disabled when - // no windows are active + // This should be disabled when no windows are active. label: locale.translation('closeWindow'), accelerator: 'CmdOrCtrl+Shift+W', click: function (item, focusedWindow) { @@ -260,8 +259,10 @@ const createViewSubmenu = () => { { label: locale.translation('toggleDeveloperTools'), accelerator: isDarwin ? 'Cmd+Alt+I' : 'Ctrl+Shift+I', - click: function (item, focusedWindow) { - CommonMenu.sendToFocusedWindow(focusedWindow, [messages.SHORTCUT_ACTIVE_FRAME_TOGGLE_DEV_TOOLS]) + click: function (item) { + const win = BrowserWindow.getActiveWindow() + const activeTab = tabState.getActiveTabValue(appStore.getState(), win.id) + appActions.toggleDevTools(activeTab.get('tabId')) } }, CommonMenu.separatorMenuItem, diff --git a/app/browser/reducers/tabsReducer.js b/app/browser/reducers/tabsReducer.js index e05ec82ab6..f6f3420607 100644 --- a/app/browser/reducers/tabsReducer.js +++ b/app/browser/reducers/tabsReducer.js @@ -17,6 +17,7 @@ const windows = require('../windows') const Immutable = require('immutable') const dragTypes = require('../../../js/constants/dragTypes') const {frameOptsFromFrame} = require('../../../js/state/frameStateUtil') +const {BrowserWindow} = require('electron') const tabsReducer = (state, action) => { action = makeImmutable(action) @@ -44,9 +45,26 @@ const tabsReducer = (state, action) => { case appConstants.APP_TAB_UPDATED: state = tabState.maybeCreateTab(state, action) break - case appConstants.APP_TAB_CLOSED: - state = tabs.removeTab(state, action) + case appConstants.APP_ACTIVE_WEB_CONTENTS_CLOSED: { + const tabValue = tabState.getActiveTabValue(state, BrowserWindow.getActiveWindow().id) + if (tabValue) { + const tabId = tabValue.get('tabId') + if (tabs.isDevToolsFocused(tabId)) { + state = tabs.toggleDevTools(state, tabId) + } else { + state = tabs.closeTab(state, tabId, false) + } + } + break + } + case appConstants.APP_TAB_CLOSED: { + const tabId = action.getIn(['tabValue', 'tabId']) + const forceClose = action.get('forceClose') + if (tabId) { + state = tabs.closeTab(state, tabId, forceClose) + } break + } case appConstants.APP_ALLOW_FLASH_ONCE: case appConstants.APP_ALLOW_FLASH_ALWAYS: { @@ -74,7 +92,7 @@ const tabsReducer = (state, action) => { state = tabs.setActive(state, action) break case appConstants.APP_TAB_TOGGLE_DEV_TOOLS: - state = tabs.toggleDevTools(state, action) + state = tabs.toggleDevTools(state, action.get('tabId')) break case appConstants.APP_LOAD_URL_REQUESTED: state = tabs.loadURL(state, action) diff --git a/app/browser/tabs.js b/app/browser/tabs.js index 5990a361f0..a0c32da5c5 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -99,7 +99,7 @@ ipcMain.on(messages.ABOUT_COMPONENT_INITIALIZED, (e) => { const listener = () => { if (!tab.isDestroyed()) { const tabValue = tabState.getByTabId(appStore.getState(), tab.getId()) - if (tabValue.get('active') === true) { + if (tabValue && tabValue.get('active') === true) { updateAboutDetails(tab, tabValue) } } else { @@ -387,9 +387,7 @@ const api = { } }, - toggleDevTools: (state, action) => { - action = makeImmutable(action) - const tabId = action.get('tabId') + toggleDevTools: (state, tabId) => { const tab = getWebContents(tabId) if (tab && !tab.isDestroyed()) { if (tab.isDevToolsOpened()) { @@ -502,18 +500,19 @@ const api = { return state }, - removeTab: (state, action) => { - action = makeImmutable(action) - const tabId = action.getIn(['tabValue', 'tabId']) - const forceClose = action.get('forceClose') - if (tabId) { - api.closeTab(tabId, forceClose) - return tabState.removeTab(state, action) - } - return state + isDevToolsFocused: (tabId) => { + const tab = getWebContents(tabId) + return tab && + !tab.isDestroyed() && + tab.isDevToolsOpened() && + tab.isDevToolsFocused() }, - closeTab: (tabId, forceClose) => { + closeTab: (state, tabId, forceClose) => { + const tabValue = getTabValue(tabId) + if (!tabValue) { + return state + } const tab = getWebContents(tabId) try { if (tab && !tab.isDestroyed()) { @@ -526,6 +525,7 @@ const api = { } catch (e) { // ignore } + return tabState.removeTab(state, tabValue) }, create: (createProperties, cb = null) => { diff --git a/app/common/state/tabState.js b/app/common/state/tabState.js index 98d9d99e38..52d0683b33 100644 --- a/app/common/state/tabState.js +++ b/app/common/state/tabState.js @@ -105,10 +105,10 @@ const tabState = { return state.set('tabs', state.get('tabs').delete(index)) }, - removeTab: (state, action) => { - action = validateAction(action) + removeTab: (state, tabValue) => { state = validateState(state) - let tabValue = validateTabValue(action.get('tabValue')) + tabValue = makeImmutable(tabValue) + tabValue = validateTabValue(tabValue) let tabId = validateId('tabId', tabValue.get('tabId')) return tabState.removeTabByTabId(state, tabId) }, diff --git a/js/actions/appActions.js b/js/actions/appActions.js index fcbcd6c31f..855f14bdba 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -926,6 +926,15 @@ const appActions = { }) }, + /** + * Dispatches a message to toogle the dev tools on/off or close the tab, depending on what's active. + */ + activeWebContentsClosed: function () { + AppDispatcher.dispatch({ + actionType: appConstants.APP_ACTIVE_WEB_CONTENTS_CLOSED + }) + }, + /** * Dispatches a message when a tab is being cloned * @param {number} tabId - The tabId of the tab to clone diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index c0ec32bc11..0c5206ae4f 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -97,6 +97,7 @@ const appConstants = { APP_SHUTTING_DOWN: _, APP_CLIPBOARD_TEXT_UPDATED: _, APP_TAB_TOGGLE_DEV_TOOLS: _, + APP_ACTIVE_WEB_CONTENTS_CLOSED: _, APP_TAB_CLONED: _, APP_SET_OBJECT_ID: _, APP_CREATE_SYNC_CACHE: _, diff --git a/test/unit/app/browser/reducers/tabsReducerTest.js b/test/unit/app/browser/reducers/tabsReducerTest.js index f95dee930b..a182327fd7 100644 --- a/test/unit/app/browser/reducers/tabsReducerTest.js +++ b/test/unit/app/browser/reducers/tabsReducerTest.js @@ -1,4 +1,4 @@ -/* global describe, it, before, after, beforeEach, afterEach */ +/* global describe, it, before, after, afterEach */ const Immutable = require('immutable') const assert = require('assert') const mockery = require('mockery') @@ -6,25 +6,23 @@ const sinon = require('sinon') const appConstants = require('../../../../../js/constants/appConstants') const dragTypes = require('../../../../../js/constants/dragTypes') const fakeElectron = require('../../../lib/fakeElectron') +const fakeAdBlock = require('../../../lib/fakeAdBlock') require('../../../braveUnit') describe('tabsReducer', function () { let tabsReducer - let appActions before(function () { mockery.enable({ warnOnReplace: false, warnOnUnregistered: false, useCleanCache: true }) - this.notPinnedTabIndex = 0 - this.pinnedTabIndex = 1 - this.singleTabWindowIndex = 2 this.state = Immutable.fromJS({ tabs: [{ tabId: 1, windowId: 1, - pinned: false + pinned: false, + active: true }, { tabId: 2, pinned: true, @@ -32,42 +30,32 @@ describe('tabsReducer', function () { }, { tabId: 3, pinned: false, - windowId: 2 + windowId: 2, + active: true }] }) mockery.registerMock('electron', fakeElectron) + mockery.registerMock('ad-block', fakeAdBlock) mockery.registerMock('leveldown', {}) - mockery.registerMock('./webContentsCache', { - getWebContents: (tabId) => ({ - canGoBack: () => true, - canGoForward: () => true, - session: { - partition: 'default' - }, - tabValue: () => - this.state.get('tabs').find((tab) => tab.get('tabId') === tabId), - isDestroyed: () => false, - detach: (cb) => cb() - }) - }) + + this.tabsAPI = { + isDevToolsFocused: (tabId) => { + return tabId === 1 + }, + toggleDevTools: sinon.mock(), + closeTab: sinon.mock(), + moveTo: sinon.mock() + } + + mockery.registerMock('tabs', this.tabsAPI) + mockery.registerMock('../tabs', this.tabsAPI) tabsReducer = require('../../../../../app/browser/reducers/tabsReducer') - appActions = require('../../../../../js/actions/appActions') }) after(function () { mockery.disable() }) - beforeEach(function () { - this.newWindowSpy = sinon.spy(appActions, 'newWindow') - this.newWebContentsAddedSpy = sinon.spy(appActions, 'newWebContentsAdded') - }) - - afterEach(function () { - this.newWindowSpy.restore() - this.newWebContentsAddedSpy.restore() - }) - describe.skip('APP_SET_STATE', function () { it('initializes a tab', function () { // TODO @@ -155,6 +143,30 @@ describe('tabsReducer', function () { }) }) + describe('APP_ACTIVE_WEB_CONTENTS_CLOSED', function () { + const action = { + actionType: appConstants.APP_ACTIVE_WEB_CONTENTS_CLOSED + } + afterEach(function () { + this.tabsAPI.toggleDevTools.reset() + this.tabsAPI.closeTab.reset() + this.tabsAPI.moveTo.reset() + this.tabsAPI.isDevToolsFocused.restore() + }) + it('closes devtools when opened and focused', function () { + this.isDevToolsFocused = sinon.stub(this.tabsAPI, 'isDevToolsFocused', () => true) + tabsReducer(this.state, action) + assert(this.tabsAPI.toggleDevTools.withArgs(this.state, 1).calledOnce) + assert(this.tabsAPI.closeTab.notCalled) + }) + it('closes tab when tab is focused with no devtools', function () { + this.isDevToolsFocused = sinon.stub(this.tabsAPI, 'isDevToolsFocused', () => false) + tabsReducer(this.state, action) + assert(this.tabsAPI.toggleDevTools.notCalled) + assert(this.tabsAPI.closeTab.withArgs(this.state, 1).calledOnce) + }) + }) + describe.skip('APP_LOAD_URL_REQUESTED', function () { it('loads the specified URL', function () { // TODO @@ -177,77 +189,49 @@ describe('tabsReducer', function () { const action = { actionType: appConstants.APP_DRAG_ENDED } - it('moves tab to a new window', function () { - const state = this.state.set('dragData', Immutable.fromJS({ - windowId: 1, - type: dragTypes.TAB, - data: this.state.getIn(['tabs', this.notPinnedTabIndex]), - dropWindowId: -1 - })) - const newState = tabsReducer(state, action) - assert.equal(this.newWindowSpy.calledOnce, true) - assert.equal(this.newWebContentsAddedSpy.notCalled, true) - assert(Immutable.is(newState, state)) + before(function () { + tabsReducer = require('../../../../../app/browser/reducers/tabsReducer') }) - it('moves tab to an existing window', function () { - const state = this.state.set('dragData', Immutable.fromJS({ - windowId: 1, - type: dragTypes.TAB, - data: this.state.getIn(['tabs', this.notPinnedTabIndex]), - dropWindowId: 11 - })) - const newState = tabsReducer(state, action) - assert.equal(this.newWindowSpy.notCalled, true) - assert.equal(this.newWebContentsAddedSpy.calledOnce, true) - assert(Immutable.is(newState, state)) + afterEach(function () { + this.tabsAPI.moveTo.reset() }) - it('does not move pinned tabs', function () { + + it('calls into tabs.moveTo for tabs', function () { const state = this.state.set('dragData', Immutable.fromJS({ - windowId: 2, + windowId: 1, type: dragTypes.TAB, - data: this.state.getIn(['tabs', this.pinnedTabIndex]), + data: this.state.getIn(['tabs', 0]), dropWindowId: -1 })) - const newState = tabsReducer(state, action) - assert.equal(this.newWindowSpy.notCalled, true) - assert.equal(this.newWebContentsAddedSpy.notCalled, true) - assert(Immutable.is(newState, state)) - }) - it('does not move pinned tabs to alt window', function () { - const state = this.state.set('dragData', Immutable.fromJS({ - windowId: 2, - type: dragTypes.TAB, - data: this.state.getIn(['tabs', this.pinnedTabIndex]), - dropWindowId: 89 - })) - const newState = tabsReducer(state, action) - assert.equal(this.newWindowSpy.notCalled, true) - assert.equal(this.newWebContentsAddedSpy.notCalled, true) - assert(Immutable.is(newState, state)) + tabsReducer(state, action) + const args = this.tabsAPI.moveTo.args[0] + assert.equal(args.length, 5) // Function signature has 5 args + assert.equal(args[0], state) // State is passed in as first arg + assert.equal(args[1], 1) // tabId is 1 for first tab + // frameOpts being dragged is for the first tab + assert.deepEqual(args[2], { tabId: 1, + windowId: 1, + pinned: false, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + }) + // Passes browser options for position by mouse cursor + assert.deepEqual(args[3], { + positionByMouseCursor: true + }) + // Dropping on window ID is -1 + assert.equal(args[4], -1) }) - it('does not move single tab windows into new window', function () { + it('does not call into tabs.moveTo for other drop types', function () { const state = this.state.set('dragData', Immutable.fromJS({ windowId: 1, - type: dragTypes.TAB, - data: this.state.getIn(['tabs', this.singleTabWindowIndex]), + type: dragTypes.BOOKMARK, + data: this.state.getIn(['tabs', 0]), dropWindowId: -1 })) - const newState = tabsReducer(state, action) - assert.equal(this.newWindowSpy.notCalled, true) - assert.equal(this.newWebContentsAddedSpy.notCalled, true) - assert(Immutable.is(newState, state)) - }) - it('allows combining single tab into alt window', function () { - const state = this.state.set('dragData', Immutable.fromJS({ - windowId: 2, - type: dragTypes.TAB, - data: this.state.getIn(['tabs', this.singleTabWindowIndex]), - dropWindowId: 41 - })) - const newState = tabsReducer(state, action) - assert.equal(this.newWindowSpy.notCalled, true) - assert.equal(this.newWebContentsAddedSpy.calledOnce, true) - assert(Immutable.is(newState, state)) + tabsReducer(state, action) + assert(this.tabsAPI.moveTo.notCalled) }) }) }) diff --git a/test/unit/app/browser/tabsTest.js b/test/unit/app/browser/tabsTest.js new file mode 100644 index 0000000000..38f9d6f453 --- /dev/null +++ b/test/unit/app/browser/tabsTest.js @@ -0,0 +1,370 @@ +/* global describe, it, before, beforeEach, after, afterEach */ +const mockery = require('mockery') +const sinon = require('sinon') +const Immutable = require('immutable') +const assert = require('assert') +const dragTypes = require('../../../../js/constants/dragTypes') +const fakeElectron = require('../../lib/fakeElectron') +const fakeAdBlock = require('../../lib/fakeAdBlock') + +require('../../braveUnit') + +describe('tabs API', function () { + let tabs, appActions + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + + this.tabWithDevToolsClosed = { + isDestroyed: () => false, + isDevToolsOpened: () => false, + openDevTools: sinon.mock(), + closeDevTools: sinon.mock() + } + + this.tabWithDevToolsOpened = { + isDestroyed: () => false, + isDevToolsOpened: () => true, + isDevToolsFocused: () => false, + openDevTools: sinon.mock(), + closeDevTools: sinon.mock() + } + + this.tabWithDevToolsOpenedAndFocused = { + isDestroyed: () => false, + isDevToolsOpened: () => true, + isDevToolsFocused: () => true, + openDevTools: sinon.mock(), + closeDevTools: sinon.mock() + } + + this.state = Immutable.fromJS({ + tabs: [{ + tabId: 1, + windowId: 1, + pinned: false, + active: true + }, { + tabId: 2, + pinned: true, + windowId: 1 + }, { + tabId: 3, + pinned: false, + windowId: 2, + active: true + }] + }) + + mockery.registerMock('electron', fakeElectron) + mockery.registerMock('ad-block', fakeAdBlock) + mockery.registerMock('leveldown', {}) + + mockery.registerMock('./webContentsCache', { + getWebContents: (tabId) => { + const webContents = { + canGoBack: () => true, + canGoForward: () => true, + session: { + partition: 'default' + }, + tabValue: () => + this.state.get('tabs').find((tab) => tab.get('tabId') === tabId), + isDestroyed: () => false, + detach: (cb) => cb() + } + if (tabId === 1) { + Object.assign(webContents, this.tabWithDevToolsClosed) + } else if (tabId === 2) { + Object.assign(webContents, this.tabWithDevToolsOpened) + } else if (tabId === 3) { + Object.assign(webContents, this.tabWithDevToolsOpenedAndFocused) + } + return webContents + } + }) + tabs = require('../../../../app/browser/tabs') + appActions = require('../../../../js/actions/appActions') + }) + + beforeEach(function () { + this.newWindowSpy = sinon.spy(appActions, 'newWindow') + this.newWebContentsAddedSpy = sinon.spy(appActions, 'newWebContentsAdded') + }) + + after(function () { + mockery.disable() + }) + + afterEach(function () { + this.tabWithDevToolsClosed.openDevTools.reset() + this.tabWithDevToolsClosed.closeDevTools.reset() + this.tabWithDevToolsOpened.openDevTools.reset() + this.tabWithDevToolsOpened.closeDevTools.reset() + this.newWindowSpy.restore() + this.newWebContentsAddedSpy.restore() + }) + + describe('toggleDevTools', function () { + it('opens dev tools if closed', function () { + tabs.toggleDevTools(Immutable.Map(), 1) + assert(this.tabWithDevToolsClosed.openDevTools.calledOnce) + assert(this.tabWithDevToolsClosed.closeDevTools.notCalled) + // Also check it leaves other tabs alone + assert(this.tabWithDevToolsOpened.openDevTools.notCalled) + assert(this.tabWithDevToolsOpened.closeDevTools.notCalled) + assert(this.tabWithDevToolsOpenedAndFocused.openDevTools.notCalled) + assert(this.tabWithDevToolsOpenedAndFocused.closeDevTools.notCalled) + }) + it('closes dev tools if opened', function () { + tabs.toggleDevTools(Immutable.Map(), 2) + assert(this.tabWithDevToolsOpened.openDevTools.notCalled) + assert(this.tabWithDevToolsOpened.closeDevTools.calledOnce) + // Also check it leaves other tabs alone + assert(this.tabWithDevToolsClosed.openDevTools.notCalled) + assert(this.tabWithDevToolsClosed.closeDevTools.notCalled) + assert(this.tabWithDevToolsOpenedAndFocused.openDevTools.notCalled) + assert(this.tabWithDevToolsOpenedAndFocused.closeDevTools.notCalled) + }) + it('does not modify state', function () { + const state = Immutable.Map() + assert.equal(state, tabs.toggleDevTools(state, 2)) + }) + }) + describe('isDevToolsFocused', function () { + it('returns false if devtools are opened but not focused', function () { + assert.equal(tabs.isDevToolsFocused(1), false) + }) + it('returns false if devtools are not opened', function () { + assert.equal(tabs.isDevToolsFocused(2), false) + }) + it('returns true if devtools are opened and focused', function () { + assert.equal(tabs.isDevToolsFocused(3), true) + }) + }) + describe('moveTo', function () { + before(function () { + this.browserOpts = { + positionByMouseCursor: true + } + }) + it('moves tab to a new window', function () { + const state = this.state.set('dragData', Immutable.fromJS({ + windowId: 1, + type: dragTypes.TAB, + data: this.state.getIn(['tabs', 0]), + dropWindowId: -1 + })) + const frameOpts = { + tabId: 1, + windowId: 1, + pinned: false, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + } + const newState = tabs.moveTo(state, frameOpts.tabId, frameOpts, this.browserOpts, state.getIn(['dragData', 'dropWindowId'])) + assert.equal(this.newWindowSpy.calledOnce, true) + assert.equal(this.newWebContentsAddedSpy.notCalled, true) + assert(Immutable.is(newState, state)) + }) + it('moves tab to an existing window', function () { + const state = this.state.set('dragData', Immutable.fromJS({ + windowId: 1, + type: dragTypes.TAB, + data: this.state.getIn(['tabs', 0]), + dropWindowId: 11 + })) + const frameOpts = { + tabId: 1, + windowId: 1, + pinned: false, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + } + const newState = tabs.moveTo(state, frameOpts.tabId, frameOpts, this.browserOpts, state.getIn(['dragData', 'dropWindowId'])) + assert.equal(this.newWindowSpy.notCalled, true) + assert.equal(this.newWebContentsAddedSpy.calledOnce, true) + assert(Immutable.is(newState, state)) + }) + it('does not move pinned tabs', function () { + const state = this.state.set('dragData', Immutable.fromJS({ + windowId: 2, + type: dragTypes.TAB, + data: this.state.getIn(['tabs', 1]), + dropWindowId: -1 + })) + const frameOpts = { + tabId: 2, + windowId: 1, + pinned: true, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + } + const newState = tabs.moveTo(state, frameOpts.tabId, frameOpts, this.browserOpts, state.getIn(['dragData', 'dropWindowId'])) + assert.equal(this.newWindowSpy.notCalled, true) + assert.equal(this.newWebContentsAddedSpy.notCalled, true) + assert(Immutable.is(newState, state)) + }) + it('does not move pinned tabs to alt window', function () { + const state = this.state.set('dragData', Immutable.fromJS({ + windowId: 2, + type: dragTypes.TAB, + data: this.state.getIn(['tabs', 1]), + dropWindowId: 89 + })) + const frameOpts = { + tabId: 2, + windowId: 1, + pinned: true, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + } + const newState = tabs.moveTo(state, frameOpts.tabId, frameOpts, this.browserOpts, state.getIn(['dragData', 'dropWindowId'])) + assert.equal(this.newWindowSpy.notCalled, true) + assert.equal(this.newWebContentsAddedSpy.notCalled, true) + assert(Immutable.is(newState, state)) + }) + it('does not move single tab windows into new window', function () { + const state = this.state.set('dragData', Immutable.fromJS({ + windowId: 1, + type: dragTypes.TAB, + data: this.state.getIn(['tabs', this.singleTabWindowIndex]), + dropWindowId: -1 + })) + const frameOpts = { + tabId: 3, + windowId: 1, + pinned: true, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + } + const newState = tabs.moveTo(state, frameOpts.tabId, frameOpts, this.browserOpts, state.getIn(['dragData', 'dropWindowId'])) + assert.equal(this.newWindowSpy.notCalled, true) + assert.equal(this.newWebContentsAddedSpy.notCalled, true) + assert(Immutable.is(newState, state)) + }) + it('allows combining single tab into alt window', function () { + const state = this.state.set('dragData', Immutable.fromJS({ + windowId: 2, + type: dragTypes.TAB, + data: this.state.getIn(['tabs', 2]), + dropWindowId: 41 + })) + const frameOpts = { + tabId: 3, + windowId: 1, + pinned: true, + active: true, + indexByFrameKey: undefined, + prependIndexByFrameKey: undefined + } + const newState = tabs.moveTo(state, frameOpts.tabId, frameOpts, this.browserOpts, state.getIn(['dragData', 'dropWindowId'])) + assert.equal(this.newWindowSpy.notCalled, true) + assert.equal(this.newWebContentsAddedSpy.calledOnce, true) + assert(Immutable.is(newState, state)) + }) + }) + + describe.skip('init', function () { + it('todo', function () { + }) + }) + + describe.skip('sendToAll', function () { + it('todo', function () { + }) + }) + + describe.skip('toggleDevTools', function () { + it('todo', function () { + }) + }) + + describe.skip('setActive', function () { + it('todo', function () { + }) + }) + + describe.skip('loadURL', function () { + it('todo', function () { + }) + }) + + describe.skip('loadURLInActiveTab', function () { + it('todo', function () { + }) + }) + + describe.skip('setAudioMuted', function () { + it('todo', function () { + }) + }) + + describe.skip('clone', function () { + it('todo', function () { + }) + }) + + describe.skip('pin', function () { + it('todo', function () { + }) + }) + + describe.skip('isDevToolsFocused', function () { + it('todo', function () { + }) + }) + + describe.skip('closeTab', function () { + it('todo', function () { + }) + }) + + describe.skip('create', function () { + it('todo', function () { + }) + }) + + describe.skip('executeScriptInBackground', function () { + it('todo', function () { + }) + }) + + describe.skip('createTab', function () { + it('todo', function () { + }) + }) + + describe.skip('maybeCreateTab', function () { + it('todo', function () { + }) + }) + + describe.skip('goBack', function () { + it('todo', function () { + }) + }) + + describe.skip('goForward', function () { + it('todo', function () { + }) + }) + + describe.skip('goToIndex', function () { + it('todo', function () { + }) + }) + + describe.skip('getHistoryEntries', function () { + it('todo', function () { + }) + }) +}) diff --git a/test/unit/app/common/state/tabStateTest.js b/test/unit/app/common/state/tabStateTest.js index 4c63a32262..97cf3bba44 100644 --- a/test/unit/app/common/state/tabStateTest.js +++ b/test/unit/app/common/state/tabStateTest.js @@ -326,24 +326,20 @@ describe('tabState unit tests', function () { it('returns a new immutable state with the tab removed by `tabId`', function () { assert.deepEqual( - tabState.removeTab(this.appState, { tabValue: { tabId: 2 } }).get('tabs').toJS(), + tabState.removeTab(this.appState, { tabId: 2 }).get('tabs').toJS(), [{ tabId: 1 }]) }) - shouldValidateAction((action) => { - tabState.removeTab(defaultAppState, action) - }) - shouldValidateTabValue((tabValue) => { - tabState.removeTab(defaultAppState, { tabValue }) + tabState.removeTab(defaultAppState, tabValue) }) shouldValidateId((tabId) => { - tabState.removeTab(defaultAppState, { tabValue: { tabId } }) + tabState.removeTab(defaultAppState, { tabId }) }) shouldValidateTabState((state) => { - tabState.removeTab(state, { tabValue: { tabId: 1 } }) + tabState.removeTab(state, { tabId: 1 }) }) }) diff --git a/test/unit/lib/fakeElectron.js b/test/unit/lib/fakeElectron.js index 8cdbe30241..a0df159f1d 100644 --- a/test/unit/lib/fakeElectron.js +++ b/test/unit/lib/fakeElectron.js @@ -1,6 +1,15 @@ const fakeElectron = { BrowserWindow: { - getFocusedWindow: function () {} + getFocusedWindow: function () { + return { + id: 1 + } + }, + getActiveWindow: function () { + return { + id: 1 + } + } }, ipcMain: { on: function () { },