@@ -1012,6 +1013,7 @@ class Main extends ImmutableComponent {
menubarVisible={customTitlebar.menubarVisible}
siteSettings={this.props.appState.get('siteSettings')}
synopsis={this.props.appState.getIn(['publisherInfo', 'synopsis']) || new Immutable.Map()}
+ activeTabShowingMessageBox={activeTabShowingMessageBox}
/>
{
- this.extensionButtons
+ activeTabShowingMessageBox
+ ? null
+ : this.extensionButtons
}
{
customTitlebar.captionButtonsVisible && !customTitlebar.menubarVisible
diff --git a/js/components/navigationBar.js b/js/components/navigationBar.js
index 46be3ef9b20..4f1ec7ccaee 100644
--- a/js/components/navigationBar.js
+++ b/js/components/navigationBar.js
@@ -102,14 +102,17 @@ class NavigationBar extends ImmutableComponent {
}
get titleMode () {
- return this.props.mouseInTitlebar === false &&
- !this.props.bookmarkDetail &&
- this.props.title &&
- !['about:blank', 'about:newtab'].includes(this.props.location) &&
- !this.loading &&
- !this.props.navbar.getIn(['urlbar', 'focused']) &&
- !this.props.navbar.getIn(['urlbar', 'active']) &&
- getSetting(settings.DISABLE_TITLE_MODE) === false
+ return this.props.activeTabShowingMessageBox ||
+ (
+ this.props.mouseInTitlebar === false &&
+ !this.props.bookmarkDetail &&
+ this.props.title &&
+ !['about:blank', 'about:newtab'].includes(this.props.location) &&
+ !this.loading &&
+ !this.props.navbar.getIn(['urlbar', 'focused']) &&
+ !this.props.navbar.getIn(['urlbar', 'active']) &&
+ getSetting(settings.DISABLE_TITLE_MODE) === false
+ )
}
get isPublisherButtonEnabled () {
@@ -226,6 +229,7 @@ class NavigationBar extends ImmutableComponent {
onStop={this.onStop}
menubarVisible={this.props.menubarVisible}
noBorderRadius={this.isPublisherButtonEnabled}
+ activeTabShowingMessageBox={this.props.activeTabShowingMessageBox}
/>
{
isSourceAboutUrl(this.props.location)
diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js
index 3f084308082..713dd534b5a 100644
--- a/js/constants/appConstants.js
+++ b/js/constants/appConstants.js
@@ -43,9 +43,9 @@ const appConstants = {
APP_UPDATE_LEDGER_INFO: _,
APP_LEDGER_RECOVERY_STATUS_CHANGED: _,
APP_UPDATE_PUBLISHER_INFO: _,
- APP_SHOW_MESSAGE_BOX: _, /** @param {Object} detail */
- APP_HIDE_MESSAGE_BOX: _, /** @param {string} message */
- APP_CLEAR_MESSAGE_BOXES: _, /** @param {string} origin */
+ APP_SHOW_NOTIFICATION: _, /** @param {Object} detail */
+ APP_HIDE_NOTIFICATION: _, /** @param {string} message */
+ APP_CLEAR_NOTIFICATIONS: _, /** @param {string} origin */
APP_ADD_WORD: _, /** @param {string} word, @param {boolean} learn */
APP_SET_DICTIONARY: _, /** @param {string} locale */
APP_BACKUP_KEYS: _,
@@ -91,7 +91,10 @@ const appConstants = {
APP_SET_OBJECT_ID: _,
APP_SAVE_SYNC_INIT_DATA: _,
APP_RESET_SYNC_DATA: _,
- APP_ADD_NOSCRIPT_EXCEPTIONS: _
+ APP_ADD_NOSCRIPT_EXCEPTIONS: _,
+ APP_TAB_MESSAGE_BOX_SHOWN: _,
+ APP_TAB_MESSAGE_BOX_DISMISSED: _,
+ APP_TAB_MESSAGE_BOX_UPDATED: _
}
module.exports = mapValuesByKeys(appConstants)
diff --git a/js/flash.js b/js/flash.js
index 102e2cf7589..54f3f2e3f10 100644
--- a/js/flash.js
+++ b/js/flash.js
@@ -55,7 +55,7 @@ module.exports.showFlashMessageBox = (location, tabId) => {
// This is bad, we shouldn't be calling actions from actions
// so we need to refactor notifications into a state helper
- appActions.showMessageBox({
+ appActions.showNotification({
buttons: [
{text: locale.translation('deny')},
{text: locale.translation('allow')}
@@ -69,7 +69,7 @@ module.exports.showFlashMessageBox = (location, tabId) => {
ipcMain.once(messages.NOTIFICATION_RESPONSE, (e, msg, buttonIndex, persist) => {
if (msg === message) {
- appActions.hideMessageBox(message)
+ appActions.hideNotification(message)
if (buttonIndex === 1) {
if (persist) {
appActions.changeSiteSetting(origin, 'flash', Date.now() + 7 * 24 * 1000 * 3600)
diff --git a/js/stores/appStore.js b/js/stores/appStore.js
index 4d0052e5173..4e6af56a2b7 100644
--- a/js/stores/appStore.js
+++ b/js/stores/appStore.js
@@ -36,6 +36,7 @@ const autofill = require('../../app/autofill')
const nativeImage = require('../../app/nativeImage')
const Filtering = require('../../app/filtering')
const basicAuth = require('../../app/browser/basicAuth')
+const webtorrent = require('../../app/browser/webtorrent')
const windows = require('../../app/browser/windows')
const assert = require('assert')
@@ -46,8 +47,6 @@ const aboutNewTabState = require('../../app/common/state/aboutNewTabState')
const aboutHistoryState = require('../../app/common/state/aboutHistoryState')
const windowState = require('../../app/common/state/windowState')
-const webtorrent = require('../../app/browser/webtorrent')
-
const isDarwin = process.platform === 'darwin'
const isWindows = process.platform === 'win32'
@@ -360,7 +359,8 @@ const applyReducers = (state, action) => [
require('../../app/browser/reducers/tabsReducer'),
require('../../app/browser/reducers/spellCheckReducer'),
require('../../app/browser/reducers/clipboardReducer'),
- require('../../app/browser/reducers/passwordManagerReducer')
+ require('../../app/browser/reducers/passwordManagerReducer'),
+ require('../../app/browser/reducers/tabMessageBoxReducer')
].reduce(
(appState, reducer) => {
const newState = reducer(appState, action)
@@ -438,12 +438,12 @@ const handleAppAction = (action) => {
ipcMain.on(messages.NOTIFICATION_RESPONSE, function notificationResponseCallback (e, message, buttonIndex, persist) {
if (message === locale.translation('unexpectedErrorWindowReload')) {
- appActions.hideMessageBox(message)
+ appActions.hideNotification(message)
ipcMain.removeListener(messages.NOTIFICATION_RESPONSE, notificationResponseCallback)
}
})
- appActions.showMessageBox({
+ appActions.showNotification({
buttons: [
{text: locale.translation('ok')}
],
@@ -709,7 +709,7 @@ const handleAppAction = (action) => {
case appConstants.APP_UPDATE_PUBLISHER_INFO:
appState = appState.set('publisherInfo', Immutable.fromJS(action.publisherInfo))
break
- case appConstants.APP_SHOW_MESSAGE_BOX:
+ case appConstants.APP_SHOW_NOTIFICATION:
let notifications = appState.get('notifications')
notifications = notifications.filterNot((notification) => {
let message = notification.get('message')
@@ -740,12 +740,12 @@ const handleAppAction = (action) => {
notifications = notifications.insert(insertIndex, Immutable.fromJS(action.detail))
appState = appState.set('notifications', notifications)
break
- case appConstants.APP_HIDE_MESSAGE_BOX:
+ case appConstants.APP_HIDE_NOTIFICATION:
appState = appState.set('notifications', appState.get('notifications').filterNot((notification) => {
return notification.get('message') === action.message
}))
break
- case appConstants.APP_CLEAR_MESSAGE_BOXES:
+ case appConstants.APP_CLEAR_NOTIFICATIONS:
appState = appState.set('notifications', appState.get('notifications').filterNot((notification) => {
return notification.get('frameOrigin') === action.origin
}))
diff --git a/test/app/renderer/components/messageBoxTest.js b/test/app/renderer/components/messageBoxTest.js
new file mode 100644
index 00000000000..5e321b74a9b
--- /dev/null
+++ b/test/app/renderer/components/messageBoxTest.js
@@ -0,0 +1,298 @@
+/* global describe, beforeEach, it */
+
+const Brave = require('../../../lib/brave')
+const messages = require('../../../../js/constants/messages')
+const {
+ urlInput, backButton, forwardButton,
+ msgBoxSuppress, msgBoxSuppressTrue, msgBoxMessage, msgBoxTitle
+} = require('../../../lib/selectors')
+const assert = require('assert')
+
+const getActiveTabState = (appState) => {
+ const tabs = appState.tabs
+ const activeTab = tabs.find((tab) => {
+ return tab.active
+ })
+ return activeTab
+}
+
+const getBackgroundTabState = (appState) => {
+ const tabs = appState.tabs
+ const nonActiveTab = tabs.find((tab) => {
+ return !tab.active && tab.messageBoxDetail
+ })
+ return nonActiveTab
+}
+
+let modalAlert
+let alertText
+
+describe('MessageBox component tests', function () {
+ function * setup (client) {
+ yield client
+ .waitForUrl(Brave.newTabUrl)
+ .waitForBrowserWindow()
+ .waitForEnabled(urlInput)
+ }
+
+ function * showsExpectedMessage (client) {
+ yield client
+ .getText(msgBoxMessage).then((val) => {
+ // console.log('expected: ' + alertText + '; actual: ' + val)
+ assert(val === alertText)
+ })
+ }
+
+ function * storesDetailsInTabState (client) {
+ let alertTitle
+ let alertMessage
+
+ yield client
+ .getText(msgBoxTitle).then((val) => {
+ alertTitle = val
+ })
+ .getText(msgBoxMessage).then((val) => {
+ alertMessage = val
+ })
+ .getAppState().then((val) => {
+ const tabState = getActiveTabState(val.value)
+ assert(tabState.messageBoxDetail.title === alertTitle)
+ assert(tabState.messageBoxDetail.message === alertMessage)
+ })
+ }
+
+ Brave.beforeEach(this)
+
+ describe('alert', function () {
+ beforeEach(function * () {
+ alertText = undefined
+ modalAlert = Brave.server.url('modal_alert.html')
+
+ yield setup(this.app.client)
+
+ yield this.app.client
+ .tabByUrl(Brave.newTabUrl)
+ .url(modalAlert)
+ .waitForUrl(modalAlert)
+ .waitForVisible('#trigger')
+ .leftClick('#trigger')
+ .waitUntil(function () {
+ return this.alertText().then((response) => {
+ alertText = response
+ return response
+ }, () => {
+ return false
+ })
+ })
+ .windowByUrl(Brave.browserWindowUrl)
+ .waitForVisible(msgBoxMessage)
+ })
+
+ it('shows the expected message', function * () {
+ yield showsExpectedMessage(this.app.client)
+ })
+
+ it('stores the message box details in the tabState', function * () {
+ yield storesDetailsInTabState(this.app.client)
+ })
+
+ it('closes the alert when you press enter', function * () {
+ yield this.app.client
+ .keys(Brave.keys.ENTER)
+ .waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const tabState = getActiveTabState(val.value)
+ return tabState.messageBoxDetail === undefined
+ })
+ })
+ })
+
+ it('closes the alert when you press escape', function * () {
+ yield this.app.client
+ .keys(Brave.keys.ESCAPE)
+ .waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const tabState = getActiveTabState(val.value)
+ return tabState.messageBoxDetail === undefined
+ })
+ })
+ })
+
+ describe('when showing an alerts multiple times', function () {
+ beforeEach(function * () {
+ yield this.app.client
+ .keys(Brave.keys.ENTER)
+ .waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const tabState = getActiveTabState(val.value)
+ return tabState.messageBoxDetail === undefined
+ })
+ })
+ // Show modal a 2nd time
+ .tabByUrl(modalAlert)
+ .leftClick('#trigger')
+ .waitUntil(function () {
+ return this.alertText().then((response) => {
+ alertText = response
+ return response
+ }, () => {
+ return false
+ })
+ })
+ // 2nd time an alert from this source is shown,
+ // we display a "suppress" switch
+ .windowByUrl(Brave.browserWindowUrl)
+ })
+
+ it('shows a suppress switch', function * () {
+ yield this.app.client
+ .waitForVisible(msgBoxSuppress)
+ })
+
+ it('lets you suppress future notifications', function * () {
+ yield this.app.client
+ // click to set Suppress = true
+ .click(msgBoxSuppress)
+ .waitForVisible(msgBoxSuppressTrue)
+ // Close alert again
+ .keys(Brave.keys.ENTER)
+ .waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const tabState = getActiveTabState(val.value)
+ return tabState.messageBoxDetail === undefined
+ })
+ })
+ // Try to show modal a 3rd time
+ .tabByUrl(modalAlert)
+ .leftClick('#trigger')
+ .windowByUrl(Brave.browserWindowUrl)
+ .pause(2000)
+ .waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const tabState = getActiveTabState(val.value)
+ return tabState.messageBoxDetail === undefined
+ })
+ })
+ })
+ })
+
+ describe('when opening a new tab (while alert is showing)', function () {
+ beforeEach(function * () {
+ const page1 = Brave.server.url('page1.html')
+ const page2 = Brave.server.url('page2.html')
+ // open a new tab
+ yield this.app.client
+ .ipcSend(messages.SHORTCUT_NEW_FRAME, page1)
+ .waitForTabCount(2)
+ .waitForVisible('#thelink[href="page2.html"]', 1000)
+
+ // load a basic history for this tab
+ yield this.app.client
+ .url(page2)
+ .waitForVisible('#thelink[href="page1.html"]', 1000)
+ .url(page1)
+ .waitForVisible('#thelink[href="page2.html"]', 1000)
+ })
+
+ it('lets you follow links in the tab', function * () {
+ // click link
+ yield this.app.client
+ .leftClick('#thelink')
+
+ // verify link was followed
+ yield this.app.client
+ .windowByUrl(Brave.browserWindowUrl)
+ .waitUntil(function () {
+ return this.getText('[data-test-id="tab"][data-test-active-tab="true"] [data-test-id="tabTitle"]')
+ .then((title) => {
+ return title === 'Page 2'
+ })
+ })
+ })
+
+ it('lets you use the back button', function * () {
+ // click back button
+ yield this.app.client
+ .windowByUrl(Brave.browserWindowUrl)
+ .leftClick(backButton)
+
+ // verify page is previous
+ yield this.app.client
+ .waitUntil(function () {
+ return this.getText('[data-test-id="tab"][data-test-active-tab="true"] [data-test-id="tabTitle"]')
+ .then((title) => {
+ return title === 'Page 2'
+ })
+ })
+ })
+
+ it('lets you use the forward button', function * () {
+ // click back button
+ yield this.app.client
+ .windowByUrl(Brave.browserWindowUrl)
+ .leftClick(backButton)
+ .waitForVisible(forwardButton + '[disabled]', 1000, true)
+
+ // click forward button
+ yield this.app.client
+ .leftClick(forwardButton)
+
+ // verify page is previous
+ yield this.app.client
+ .waitUntil(function () {
+ return this.getText('[data-test-id="tab"][data-test-active-tab="true"] [data-test-id="tabTitle"]')
+ .then((title) => {
+ return title === 'Page 1'
+ })
+ })
+ })
+
+ it('original tab does not respond to escape or enter being pressed', function * () {
+ yield this.app.client
+ .windowByUrl(Brave.browserWindowUrl)
+ .keys(Brave.keys.ENTER)
+ .pause(250)
+ .keys(Brave.keys.ESCAPE)
+ .pause(250)
+ .getAppState().then((val) => {
+ const detail = getBackgroundTabState(val.value)
+ assert(detail)
+ })
+ })
+ })
+ })
+
+ describe('confirm', function () {
+ beforeEach(function * () {
+ alertText = undefined
+ modalAlert = Brave.server.url('modal_confirm.html')
+
+ yield setup(this.app.client)
+
+ yield this.app.client
+ .tabByUrl(Brave.newTabUrl)
+ .url(modalAlert)
+ .waitForUrl(modalAlert)
+ .waitForVisible('#trigger')
+ .leftClick('#trigger')
+ .waitUntil(function () {
+ return this.alertText().then((response) => {
+ alertText = response
+ return response
+ }, () => {
+ return false
+ })
+ })
+ .windowByUrl(Brave.browserWindowUrl)
+ .waitForVisible(msgBoxMessage)
+ })
+
+ it('shows the expected message', function * () {
+ yield showsExpectedMessage(this.app.client)
+ })
+
+ it('stores the message box details in the tabState', function * () {
+ yield storesDetailsInTabState(this.app.client)
+ })
+ })
+})
diff --git a/test/lib/brave.js b/test/lib/brave.js
index 1af2521ae74..5c67b58503d 100644
--- a/test/lib/brave.js
+++ b/test/lib/brave.js
@@ -209,7 +209,10 @@ var exports = {
.then(function (response) {
var handles = response.value
return promiseMapSeries(handles, (handle) => {
- return this.window(handle).getUrl()
+ return this.window(handle).getUrl().catch((err) => {
+ console.error('Error retrieving window handle ' + handle, err)
+ return ''
+ })
}).then((urls) => {
var newHandles = []
for (var i = 0; i < urls.length; i++) {
diff --git a/test/lib/selectors.js b/test/lib/selectors.js
index ddca436fb3c..e0c0db8641d 100644
--- a/test/lib/selectors.js
+++ b/test/lib/selectors.js
@@ -98,5 +98,10 @@ module.exports = {
hamburgerMenu: '.menuButton',
contextMenu: '.contextMenu',
okButton: '[data-l10n-id="ok"]',
- customFiltersInput: '[data-test-id="customFiltersInput"]'
+ customFiltersInput: '[data-test-id="customFiltersInput"]',
+ // used by the MessageBox control
+ msgBoxSuppress: '[data-test-id^="msgBoxTab_"] .switchMiddle',
+ msgBoxSuppressTrue: '[data-test-id^="msgBoxTab_"] .switchMiddle .switchBackground.switchedOn',
+ msgBoxMessage: '[data-test-id="msgBoxMessage"]',
+ msgBoxTitle: '[data-test-id="msgBoxTitle"]'
}
diff --git a/test/unit/app/browser/tabMessageBoxTest.js b/test/unit/app/browser/tabMessageBoxTest.js
new file mode 100644
index 00000000000..17d405c8842
--- /dev/null
+++ b/test/unit/app/browser/tabMessageBoxTest.js
@@ -0,0 +1,227 @@
+/* global describe, before, after, beforeEach, afterEach, it */
+const mockery = require('mockery')
+const sinon = require('sinon')
+const assert = require('assert')
+const Immutable = require('immutable')
+let tabMessageBox, appActions, tabMessageBoxShownStub
+require('../../braveUnit')
+
+const exampleCallback = (result, text, suppress) => {}
+const exampleTabId = 1
+
+const defaultAppState = Immutable.fromJS({
+ windows: [{
+ windowId: 1,
+ windowUUID: 'uuid'
+ }],
+ tabs: []
+})
+
+const exampleMessageBox = Immutable.fromJS({
+ message: 'example message',
+ title: 'example title',
+ buttons: ['OK'],
+ suppress: false,
+ showSuppress: false
+})
+
+const fakeMessageBoxState = {
+ getDetail: (state, tabId) => {},
+ removeDetail: (state, action) => {}
+}
+
+describe('tabMessageBox unit tests', function () {
+ before(function () {
+ mockery.enable({
+ warnOnReplace: false,
+ warnOnUnregistered: false,
+ useCleanCache: true
+ })
+
+ mockery.registerMock('electron', require('../../lib/fakeElectron'))
+ mockery.registerMock('../common/state/tabMessageBoxState', fakeMessageBoxState)
+ tabMessageBox = require('../../../../app/browser/tabMessageBox')
+ appActions = require('../../../../js/actions/appActions')
+
+ tabMessageBoxShownStub = sinon.stub(appActions, 'tabMessageBoxShown')
+ })
+
+ after(function () {
+ mockery.disable()
+ tabMessageBoxShownStub.restore()
+ })
+
+ describe('show', function () {
+ let callCount
+
+ before(function () {
+ callCount = tabMessageBoxShownStub.withArgs(exampleTabId, exampleMessageBox).callCount
+ tabMessageBox.show(exampleTabId, exampleMessageBox, exampleCallback)
+ })
+
+ it('registers a callback', function () {
+ const callbacks = tabMessageBox.getCallbacks()
+ assert(callbacks[exampleTabId] && callbacks[exampleTabId] === exampleCallback)
+ })
+
+ it('calls appActions.tabMessageBoxShown', function () {
+ assert.equal(tabMessageBoxShownStub.withArgs(exampleTabId, exampleMessageBox).callCount, callCount + 1)
+ })
+ })
+
+ describe('close', function () {
+ let removeSpy
+ let callbackSpy
+ let newAppState
+ let action
+
+ beforeEach(function () {
+ newAppState = defaultAppState.setIn(['messageBoxDetail', exampleTabId], exampleMessageBox)
+ action = Immutable.fromJS({
+ tabId: exampleTabId,
+ detail: exampleMessageBox
+ })
+ removeSpy = sinon.spy(fakeMessageBoxState, 'removeDetail')
+ callbackSpy = sinon.spy()
+ tabMessageBox.show(exampleTabId, {}, callbackSpy)
+ })
+
+ afterEach(function () {
+ removeSpy.restore()
+ })
+
+ it('calls `tabMessageBoxState.removeDetail` to remove the detail record', function () {
+ tabMessageBox.close(newAppState, action)
+ assert.equal(removeSpy.withArgs(newAppState, action).calledOnce, true)
+ })
+
+ describe('when calling the callback', function () {
+ it('defaults `result` to true and `suppress` to false', function () {
+ tabMessageBox.close(newAppState, action)
+ assert.equal(callbackSpy.withArgs(true, '', false).calledOnce, true)
+ })
+
+ it('reads `result` from detail object', function () {
+ action = action.setIn(['detail', 'result'], false)
+ action = action.setIn(['detail', 'suppress'], false)
+ tabMessageBox.close(newAppState, action)
+ assert.equal(callbackSpy.withArgs(false, '', false).calledOnce, true)
+ })
+
+ it('reads `suppress` from detail object', function () {
+ action = action.setIn(['detail', 'suppress'], true)
+ action = action.setIn(['detail', 'result'], true)
+ tabMessageBox.close(newAppState, action)
+ assert.equal(callbackSpy.withArgs(true, '', true).calledOnce, true)
+ })
+
+ describe('when detail is falsey', function () {
+ it('defaults `result` to false and `suppress` to false', function () {
+ action = Immutable.fromJS({tabId: exampleTabId})
+ tabMessageBox.close(newAppState, action)
+ assert.equal(callbackSpy.withArgs(false, '', false).calledOnce, true)
+ })
+ })
+ })
+
+ it('unregisters the callback', function () {
+ tabMessageBox.close(newAppState, action)
+ const callbacks = tabMessageBox.getCallbacks()
+ assert.equal(callbacks[exampleTabId], undefined)
+ })
+ })
+
+ describe('onTabUpdated', function () {
+ let removeSpy
+ let getDetailStub
+ let callbackSpy
+ let newAppState
+ let action
+
+ beforeEach(function () {
+ const exampleMessageBox2 = exampleMessageBox.set('opener', 'https://twitter.com/brave')
+ newAppState = defaultAppState.setIn(['messageBoxDetail', exampleTabId], exampleMessageBox2)
+ action = Immutable.fromJS({
+ actionType: 'app-tab-updated',
+ tabValue: {
+ audible: false,
+ active: true,
+ autoDiscardable: false,
+ windowId: 2,
+ incognito: false,
+ canGoForward: false,
+ url: 'https://twitter.com/brave',
+ tabId: exampleTabId,
+ index: 0,
+ status: 'complete',
+ highlighted: true,
+ title: 'Brave Software (@brave) | Twitter',
+ pinned: false,
+ id: exampleTabId,
+ selected: true,
+ discarded: false,
+ canGoBack: true
+ }
+ })
+ getDetailStub = sinon.stub(fakeMessageBoxState, 'getDetail').returns(exampleMessageBox2)
+ removeSpy = sinon.spy(fakeMessageBoxState, 'removeDetail')
+ callbackSpy = sinon.spy()
+ tabMessageBox.show(exampleTabId, {}, callbackSpy)
+ })
+
+ afterEach(function () {
+ getDetailStub.restore()
+ removeSpy.restore()
+ })
+
+ it('calls `tabMessageBoxState.getDetail` to get the detail record', function () {
+ tabMessageBox.onTabUpdated(newAppState, action)
+ assert.equal(getDetailStub.withArgs(newAppState, exampleTabId).calledOnce, true)
+ })
+
+ describe('when tab url matches `opener` in detail object', function () {
+ it('does NOT call `tabMessageBoxState.removeDetail`', function () {
+ tabMessageBox.onTabUpdated(newAppState, action)
+ assert.equal(removeSpy.called, false)
+ })
+
+ it('does NOT call the callback', function () {
+ tabMessageBox.onTabUpdated(newAppState, action)
+ assert.equal(callbackSpy.called, false)
+ })
+
+ it('does NOT unregister the callback', function () {
+ tabMessageBox.onTabUpdated(newAppState, action)
+ const callbacks = tabMessageBox.getCallbacks()
+ assert.equal(callbacks[exampleTabId], callbackSpy)
+ })
+ })
+
+ describe('when tab url does not match `opener` in detail object', function () {
+ beforeEach(function () {
+ const exampleMessageBox2 = exampleMessageBox.set('opener', 'https://brave.com')
+ newAppState = defaultAppState.setIn(['messageBoxDetail', exampleTabId], exampleMessageBox2)
+ // redo stub to return new opener
+ getDetailStub.restore()
+ getDetailStub = sinon.stub(fakeMessageBoxState, 'getDetail').returns(exampleMessageBox2)
+ })
+
+ it('calls `tabMessageBoxState.removeDetail` to remove the detail record', function () {
+ const removeAction = Immutable.fromJS({tabId: exampleTabId})
+ tabMessageBox.onTabUpdated(newAppState, action)
+ assert.equal(removeSpy.withArgs(newAppState, removeAction).calledOnce, true)
+ })
+
+ it('calls the callback with default params (false, \'\', false)', function () {
+ tabMessageBox.onTabUpdated(newAppState, action)
+ assert.equal(callbackSpy.withArgs(false, '', false).calledOnce, true)
+ })
+
+ it('unregisters the callback', function () {
+ tabMessageBox.onTabUpdated(newAppState, action)
+ const callbacks = tabMessageBox.getCallbacks()
+ assert.equal(callbacks[exampleTabId], undefined)
+ })
+ })
+ })
+})
diff --git a/test/unit/app/common/state/tabMessageBoxStateTest.js b/test/unit/app/common/state/tabMessageBoxStateTest.js
new file mode 100644
index 00000000000..c660db07ee7
--- /dev/null
+++ b/test/unit/app/common/state/tabMessageBoxStateTest.js
@@ -0,0 +1,182 @@
+/* global describe, it, before, after */
+const tabMessageBoxState = require('../../../../../app/common/state/tabMessageBoxState')
+const tabState = require('../../../../../app/common/state/tabState')
+const sinon = require('sinon')
+const Immutable = require('immutable')
+const assert = require('assert')
+
+const defaultAppState = Immutable.fromJS({
+ windows: [{
+ windowId: 1,
+ windowUUID: 'uuid'
+ }],
+ tabs: []
+})
+
+const exampleMessageBox = Immutable.fromJS({
+ message: 'example message',
+ title: 'example title',
+ buttons: ['OK'],
+ suppress: false,
+ showSuppress: false
+})
+
+const defaultTabId = 1
+
+const defaultTab = Immutable.fromJS({
+ tabId: defaultTabId,
+ windowId: 1,
+ windowUUID: 'uuid',
+ url: 'https://brave.com',
+ messageBoxDetail: exampleMessageBox
+})
+
+describe('tabMessageBoxState unit tests', function () {
+ describe('show', function () {
+ describe('when a detail object does not exist', function () {
+ before(function () {
+ const tab = defaultTab.delete('messageBoxDetail')
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([tab]))
+ })
+
+ it('creates the detail record (including setting opener)', function () {
+ const newAppState = tabMessageBoxState.show(this.appState, {tabId: defaultTabId, detail: exampleMessageBox})
+ const tab = tabState.getByTabId(newAppState, defaultTabId)
+ assert(tab)
+ const expectedMessageBox = exampleMessageBox.set('opener', defaultTab.get('url'))
+ assert.deepEqual(expectedMessageBox, tab.get('messageBoxDetail'))
+ })
+ })
+
+ describe('when a detail object exists', function () {
+ before(function () {
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab]))
+ })
+
+ it('removes the detail if null', function () {
+ const newAppState = tabMessageBoxState.show(this.appState, {tabId: defaultTabId})
+ let tab = tabState.getByTabId(newAppState, defaultTabId)
+ assert(tab)
+ assert.equal(undefined, tab.get('messageBoxDetail'))
+ })
+
+ it('removes the detail if empty', function () {
+ const newAppState = tabMessageBoxState.show(this.appState, {tabId: defaultTabId, detail: {}})
+ let tab = tabState.getByTabId(newAppState, defaultTabId)
+ assert(tab)
+ assert.equal(undefined, tab.get('messageBoxDetail'))
+ })
+
+ it('overwrites the existing record', function () {
+ const exampleMessageBox2 = exampleMessageBox.set('message', 'example message 2')
+ const newAppState = tabMessageBoxState.show(this.appState, {tabId: defaultTabId, detail: exampleMessageBox2})
+ let tab = tabState.getByTabId(newAppState, defaultTabId)
+ assert(tab)
+ const expectedMessageBox = exampleMessageBox2.set('opener', defaultTab.get('url'))
+ assert.deepEqual(expectedMessageBox, tab.get('messageBoxDetail'))
+ })
+ })
+
+ describe('when data is missing', function () {
+ it('does nothing when tabId is missing', function () {
+ const newAppState = tabMessageBoxState.show(defaultAppState, {})
+ assert.equal(newAppState, defaultAppState)
+ })
+
+ it('does nothing when tab value is not found', function () {
+ const newAppState = tabMessageBoxState.show(defaultAppState, {tabId: defaultTabId})
+ assert.equal(newAppState, defaultAppState)
+ })
+ })
+ })
+
+ describe('getDetail', function () {
+ it('returns null if tabId is falsey', function () {
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState))
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState, undefined))
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState, null))
+ })
+
+ it('returns null if tabId is not a number', function () {
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState, 'testing'))
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState, true))
+ })
+
+ it('returns detail object from tab value (if found)', function () {
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab]))
+ const detail = tabMessageBoxState.getDetail(this.appState, defaultTabId)
+ assert.deepEqual(exampleMessageBox, detail)
+ })
+
+ it('returns null if detail object does not exist in tab value', function () {
+ const tab = defaultTab.delete('messageBoxDetail')
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([tab]))
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState, defaultTabId))
+ })
+
+ it('returns null if tab value is not found', function () {
+ assert.equal(null, tabMessageBoxState.getDetail(defaultAppState, defaultTabId))
+ })
+ })
+
+ describe('update', function () {
+ let showSpy
+
+ before(function () {
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab]))
+ showSpy = sinon.spy(tabMessageBoxState, 'show')
+ })
+
+ after(function () {
+ showSpy.restore()
+ })
+
+ it('calls show', function () {
+ const state = this.appState
+ const action = {tabId: defaultTabId, detail: exampleMessageBox}
+ tabMessageBoxState.update(state, action)
+ assert.equal(showSpy.withArgs(state, action).calledOnce, true)
+ })
+ })
+
+ describe('removeDetail', function () {
+ describe('when a detail object exists', function () {
+ before(function () {
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([defaultTab]))
+ this.appState = tabMessageBoxState.removeDetail(this.appState, {tabId: defaultTabId})
+ this.tabState = tabState.getByTabId(this.appState, defaultTabId)
+ assert(this.tabState)
+ })
+
+ it('removes the detail', function () {
+ assert.equal(undefined, this.tabState.get('messageBoxDetail'))
+ })
+ })
+
+ describe('when a detail object does not exist', function () {
+ before(function () {
+ const tab = defaultTab.delete('messageBoxDetail')
+ this.appState = defaultAppState.set('tabs', Immutable.fromJS([tab]))
+ this.appState = tabMessageBoxState.removeDetail(this.appState, {tabId: defaultTabId})
+ this.tabState = tabState.getByTabId(this.appState, defaultTabId)
+ assert(this.tabState)
+ })
+
+ it('does nothing (does not crash)', function () {
+ assert.equal(undefined, this.tabState.get('messageBoxDetail'))
+ })
+ })
+
+ describe('when data is missing', function () {
+ it('does nothing when tabId is missing', function () {
+ const newAppState = tabMessageBoxState.removeDetail(defaultAppState, {})
+ assert.equal(newAppState, defaultAppState)
+ })
+
+ it('does nothing when tab value is not found', function () {
+ const newAppState = tabMessageBoxState.removeDetail(defaultAppState, {tabId: defaultTabId})
+ assert.equal(newAppState, defaultAppState)
+ })
+ })
+ })
+})
diff --git a/test/unit/app/common/state/tabStateTest.js b/test/unit/app/common/state/tabStateTest.js
index 8e8baced634..6f0f4480e89 100644
--- a/test/unit/app/common/state/tabStateTest.js
+++ b/test/unit/app/common/state/tabStateTest.js
@@ -1,6 +1,7 @@
-/* global describe, it, before */
+/* global describe, it, before, after */
const tabState = require('../../../../../app/common/state/tabState')
const Immutable = require('immutable')
+const sinon = require('sinon')
const assert = require('chai').assert
const AssertionError = require('assert').AssertionError
@@ -172,7 +173,7 @@ const shouldValidateAction = function (cb) {
})
}
-describe('tabState', function () {
+describe('tabState unit tests', function () {
describe('getTabIndexByTabId', function () {
before(function () {
this.appState = defaultAppState.set('tabs', Immutable.fromJS([
@@ -465,9 +466,31 @@ describe('tabState', function () {
})
})
+ describe('removeTabField', function () {
+ it('removes the field specified', function () {
+ const tab = Immutable.fromJS({
+ windowId: 1,
+ frameKey: 1,
+ tabId: 2,
+ loginRequiredDetail: {
+ request: { url: 'someurl' },
+ authInfo: { authInfoProp: 'value' }
+ }
+ })
+ const tabs = Immutable.fromJS([tab])
+ const tabsWithoutField = Immutable.fromJS([tab.delete('loginRequiredDetail')])
+ const newAppState = tabState.removeTabField(defaultAppState.set('tabs', tabs), 'loginRequiredDetail')
+ const expectedAppState = defaultAppState.set('tabs', tabsWithoutField)
+ assert.deepEqual(newAppState, expectedAppState)
+ })
+ })
+
describe('getPersistentState', function () {
+ let appState
+ let removeTabFieldSpy
+
before(function () {
- this.tabs = Immutable.fromJS([{
+ const tabs = Immutable.fromJS([{
windowId: 1,
frameKey: 1,
tabId: 2,
@@ -476,7 +499,17 @@ describe('tabState', function () {
authInfo: { authInfoProp: 'value' }
}
}])
- this.tabs = tabState.getPersistentState(this.tabs)
+ appState = defaultAppState.set('tabs', tabs)
+ removeTabFieldSpy = sinon.spy(tabState, 'removeTabField')
+ tabState.getPersistentState(appState)
+ })
+
+ after(function () {
+ removeTabFieldSpy.restore()
+ })
+
+ it('removes message box data', function () {
+ assert.equal(removeTabFieldSpy.withArgs(appState, 'messageBoxDetail').calledOnce, true)
})
})
diff --git a/test/unit/app/renderer/components/messageBoxTest.js b/test/unit/app/renderer/components/messageBoxTest.js
new file mode 100644
index 00000000000..b14091bd4dc
--- /dev/null
+++ b/test/unit/app/renderer/components/messageBoxTest.js
@@ -0,0 +1,338 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* global describe, before, after, it */
+
+const mockery = require('mockery')
+const {mount, shallow} = require('enzyme')
+const sinon = require('sinon')
+const assert = require('assert')
+const Immutable = require('immutable')
+const config = require('../../../../../js/constants/config')
+let MessageBox, appActions
+require('../../../braveUnit')
+
+describe('MessageBox component unit tests', function () {
+ before(function () {
+ mockery.enable({
+ warnOnReplace: false,
+ warnOnUnregistered: false,
+ useCleanCache: true
+ })
+ mockery.registerMock('electron', require('../../../lib/fakeElectron'))
+ MessageBox = require('../../../../../app/renderer/components/messageBox')
+ appActions = require('../../../../../js/actions/appActions')
+ })
+ after(function () {
+ mockery.disable()
+ })
+
+ const tabId = 1
+ const detail1 = {
+ title: 'An embedded page at brave.com says:',
+ message: 'Example message',
+ buttons: ['OK', 'Cancel'],
+ cancelId: 1,
+ suppress: true,
+ showSuppress: true
+ }
+
+ describe('Object properties', function () {
+ describe('tabId', function () {
+ it('binds the text from the detail object', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.tabId, tabId)
+ })
+
+ it('defaults to "" if detail has falsey value', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.tabId, '')
+ })
+ })
+
+ describe('title', function () {
+ it('binds the text from the detail object', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.title = 'example title'
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.title, detail2.title)
+ })
+
+ it('defaults to "" if detail has falsey value', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.title = undefined
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.title, '')
+ })
+
+ it('replaces the Brave extensionId with "Brave"', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.title = config.braveExtensionId + ' says:'
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.title, 'Brave says:')
+ })
+ })
+
+ describe('message', function () {
+ it('binds the text from the detail object', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.message, detail1.message)
+ })
+
+ it('defaults to "" if detail has falsey value', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.message = undefined
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.message, '')
+ })
+ })
+
+ describe('buttons', function () {
+ it('binds the buttons from the detail object', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.deepEqual(instance.buttons.toJS(), detail1.buttons)
+ })
+
+ it('defaults to "[OK]" if detail has falsey value', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.buttons = undefined
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.deepEqual(instance.buttons.toJS(), ['OK'])
+ })
+ })
+
+ describe('cancelId', function () {
+ it('binds the cancelId from the detail object', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.cancelId, detail1.cancelId)
+ })
+
+ it('does not have a default if value is falsey', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.cancelId = undefined
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.cancelId, undefined)
+ })
+ })
+
+ describe('suppress', function () {
+ it('binds the suppress from the detail object', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.suppress, detail1.suppress)
+ })
+
+ it('defaults to false if detail has falsey value', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.suppress = undefined
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.suppress, false)
+ })
+ })
+
+ describe('showSuppress', function () {
+ it('binds the showSuppress from the detail object', function () {
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.showSuppress, detail1.showSuppress)
+ })
+
+ it('defaults to false if detail has falsey value', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.showSuppress = undefined
+ const wrapper = shallow(
+
+ )
+ const instance = wrapper.instance()
+ assert.equal(instance.showSuppress, false)
+ })
+ })
+ })
+
+ describe('Rendering', function () {
+ it('renders itself inside a dialog component', function () {
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('div.dialog').length, 1)
+ })
+
+ it('renders the suppress checkbox if showSuppress is true', function () {
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('div.switchControl').length, 1)
+ })
+
+ it('hides the suppress checkbox if showSuppress is false', function () {
+ const detail2 = Object.assign({}, detail1)
+ detail2.showSuppress = false
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('div.switchControl').length, 0)
+ })
+
+ it('renders the button index 0 as primaryButton', function () {
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('button[data-l10n-id="OK"].primaryButton').length, 1)
+ })
+
+ it('renders the button index 1 as whiteButton', function () {
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('button[data-l10n-id="Cancel"].whiteButton').length, 1)
+ })
+ })
+
+ describe('Events', function () {
+ it('calls appActions.tabMessageBoxUpdated when SwitchControl is toggled', function () {
+ const spy = sinon.spy(appActions, 'tabMessageBoxUpdated')
+ const wrapper = mount(
+
+ )
+ wrapper.find('.switchBackground').simulate('click')
+ assert.equal(spy.calledOnce, true)
+ appActions.tabMessageBoxUpdated.restore()
+ })
+
+ it('calls appActions.tabMessageBoxDismissed with result=true when OK is clicked', function () {
+ const spy = sinon.spy(appActions, 'tabMessageBoxDismissed')
+ const wrapper = mount(
+
+ )
+ const response = {
+ suppress: detail1.suppress,
+ result: true
+ }
+ wrapper.find('button[data-l10n-id="OK"].primaryButton').simulate('click')
+ assert.equal(spy.withArgs(tabId, response).calledOnce, true)
+ appActions.tabMessageBoxDismissed.restore()
+ })
+
+ it('calls appActions.tabMessageBoxDismissed with result=false when cancel is clicked', function () {
+ const spy = sinon.spy(appActions, 'tabMessageBoxDismissed')
+ const wrapper = mount(
+
+ )
+ const response = {
+ suppress: detail1.suppress,
+ result: false
+ }
+ wrapper.find('button[data-l10n-id="Cancel"].whiteButton').simulate('click')
+ assert.equal(spy.withArgs(tabId, response).calledOnce, true)
+ appActions.tabMessageBoxDismissed.restore()
+ })
+ })
+})
diff --git a/test/unit/app/renderer/components/urlBarIconTest.js b/test/unit/app/renderer/components/urlBarIconTest.js
new file mode 100644
index 00000000000..298d308d812
--- /dev/null
+++ b/test/unit/app/renderer/components/urlBarIconTest.js
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* global describe, before, after, it */
+
+const React = require('react')
+const mockery = require('mockery')
+const {mount} = require('enzyme')
+const sinon = require('sinon')
+const assert = require('assert')
+let UrlBarIcon, windowActions
+require('../../../braveUnit')
+
+describe('UrlBarIcon component unit tests', function () {
+ before(function () {
+ mockery.enable({
+ warnOnReplace: false,
+ warnOnUnregistered: false,
+ useCleanCache: true
+ })
+ mockery.registerMock('electron', require('../../../lib/fakeElectron'))
+ UrlBarIcon = require('../../../../../app/renderer/components/urlBarIcon')
+ windowActions = require('../../../../../js/actions/windowActions')
+ })
+
+ after(function () {
+ mockery.disable()
+ })
+
+ const props = {
+ activateSearchEngine: false,
+ active: false,
+ isSecure: true,
+ isHTTPPage: true,
+ loading: false,
+ location: 'https://brave.com/',
+ title: 'UrlBarIcon unit test',
+ titleMode: true,
+ isSearching: false,
+ activeTabShowingMessageBox: false
+ }
+
+ it('sets element as draggable', function () {
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('span[draggable]').length, 1)
+ })
+
+ it('shows site information when clicked', function () {
+ const spy = sinon.spy(windowActions, 'setSiteInfoVisible')
+ const wrapper = mount(
+
+ )
+ wrapper.find('span').simulate('click')
+ assert.equal(spy.calledOnce, true)
+ windowActions.setSiteInfoVisible.restore()
+ })
+
+ describe('when active tab is showing a message box', function () {
+ const props2 = Object.assign({}, props)
+
+ before(function () {
+ props2.activeTabShowingMessageBox = true
+ })
+
+ it('does not set element as draggable', function () {
+ const wrapper = mount(
+
+ )
+ assert.equal(wrapper.find('span[draggable]').length, 0)
+ })
+
+ it('does not respond to clicks', function () {
+ const spy = sinon.spy(windowActions, 'setSiteInfoVisible')
+ const wrapper = mount(
+
+ )
+ wrapper.find('span').simulate('click')
+ assert.equal(spy.notCalled, true)
+ windowActions.setSiteInfoVisible.restore()
+ })
+ })
+})
diff --git a/test/unit/app/renderer/components/urlBarTest.js b/test/unit/app/renderer/components/urlBarTest.js
new file mode 100644
index 00000000000..fa5ea526d5b
--- /dev/null
+++ b/test/unit/app/renderer/components/urlBarTest.js
@@ -0,0 +1,86 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* global describe, before, after, it */
+
+const React = require('react')
+const mockery = require('mockery')
+const {shallow} = require('enzyme')
+const assert = require('assert')
+const Immutable = require('immutable')
+let UrlBar, UrlBarIcon
+require('../../../braveUnit')
+
+describe('UrlBar component unit tests', function () {
+ before(function () {
+ mockery.enable({
+ warnOnReplace: false,
+ warnOnUnregistered: false,
+ useCleanCache: true
+ })
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_no_verified.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_yes_verified.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_no.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_yes.svg', {})
+ mockery.registerMock('electron', require('../../../lib/fakeElectron'))
+ UrlBar = require('../../../../../app/renderer/components/urlBar')
+ UrlBarIcon = require('../../../../../app/renderer/components/urlBarIcon')
+ })
+
+ after(function () {
+ mockery.disable()
+ })
+
+ const props = {
+ activeFrameKey: 1,
+ canGoForward: false,
+ searchDetail: undefined,
+ loading: false,
+ location: 'https://brave.com',
+ title: 'UrlBar unit test',
+ history: undefined,
+ isSecure: true,
+ hasLocationValueSuffix: undefined,
+ startLoadTime: undefined,
+ endLoadTime: undefined,
+ titleMode: true,
+ urlbar: Immutable.fromJS({
+ active: true
+ }),
+ onStop: undefined,
+ menubarVisible: false,
+ noBorderRadius: undefined,
+ activeTabShowingMessageBox: false
+ }
+
+ describe('passing properties through (without changing them) to UrlBarIcon', function () {
+ let urlBarIcon
+
+ before(function () {
+ const wrapper = shallow(
+
+ )
+ urlBarIcon = wrapper.find(UrlBarIcon).node
+ })
+
+ it('passes isSecure', function () {
+ assert.equal(urlBarIcon.props.isSecure, props.isSecure)
+ })
+
+ it('passes loading', function () {
+ assert.equal(urlBarIcon.props.loading, props.loading)
+ })
+
+ it('passes title', function () {
+ assert.equal(urlBarIcon.props.title, props.title)
+ })
+
+ it('passes titleMode', function () {
+ assert.equal(urlBarIcon.props.titleMode, props.titleMode)
+ })
+
+ it('passes activeTabShowingMessageBox', function () {
+ assert.equal(urlBarIcon.props.activeTabShowingMessageBox, props.activeTabShowingMessageBox)
+ })
+ })
+})
diff --git a/test/unit/js/mainTest.js b/test/unit/js/mainTest.js
new file mode 100644
index 00000000000..bf811cc98cb
--- /dev/null
+++ b/test/unit/js/mainTest.js
@@ -0,0 +1,125 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* global describe, before, after, it */
+
+const mockery = require('mockery')
+const {shallow} = require('enzyme')
+const assert = require('assert')
+const Immutable = require('immutable')
+let Main, NavigationBar
+require('../braveUnit')
+
+describe('Main component unit tests', function () {
+ before(function () {
+ mockery.enable({
+ warnOnReplace: false,
+ warnOnUnregistered: false,
+ useCleanCache: true
+ })
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_no_verified.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_yes_verified.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_no.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_yes.svg', {})
+ mockery.registerMock('../../extensions/brave/img/caret_down_grey.svg', 'caret_down_grey.svg')
+ mockery.registerMock('electron', require('../lib/fakeElectron'))
+ Main = require('../../../js/components/main')
+ NavigationBar = require('../../../js/components/navigationBar')
+ })
+
+ after(function () {
+ mockery.disable()
+ })
+
+ const windowState = Immutable.fromJS({
+ activeFrameKey: 0,
+ frames: [{
+ key: 0,
+ tabId: 1,
+ location: 'http://brave.com'
+ }],
+ tabs: []
+ })
+
+ const appState = Immutable.fromJS({
+ extensions: {
+ },
+ settings: {
+ },
+ siteSettings: {
+ 'https?://brave.com': {
+ example3: true
+ }
+ },
+ tabs: [{
+ tabId: 1,
+ canGoBack: true,
+ canGoForward: true
+ }]
+ })
+
+ describe('when user has history going forwards and backwards', function () {
+ let wrapper
+
+ before(function () {
+ wrapper = shallow(
+
+ )
+ })
+
+ it('both back/forward navigationButtonContainers are enabled', function () {
+ assert.equal(wrapper.find('div.backforward > div.navigationButtonContainer.disabled').length, 0)
+ })
+
+ it('back navigation button is enabled', function () {
+ const node = wrapper.find('div.backforward > div.navigationButtonContainer > .backButton').node
+ assert.equal(node.props.disabled, false)
+ })
+
+ it('forward navigation button is enabled', function () {
+ const node = wrapper.find('div.backforward > div.navigationButtonContainer > .forwardButton').node
+ assert.equal(node.props.disabled, false)
+ })
+ })
+
+ describe('when active tab is showing a message box', function () {
+ let wrapper
+
+ before(function () {
+ const appState2 = appState.mergeIn(['tabs', 0], {
+ messageBoxDetail: {
+ message: 'sample message',
+ title: 'sample title'
+ }
+ })
+
+ wrapper = shallow(
+
+ )
+ })
+
+ it('passes activeTabShowingMessageBox to NavigationBar', function () {
+ const navigationBar = wrapper.find(NavigationBar).node
+ assert.equal(navigationBar.props.activeTabShowingMessageBox, true)
+ })
+
+ it('disables both back/forward navigationButtonContainers', function () {
+ assert.equal(wrapper.find('div.backforward > div.navigationButtonContainer.disabled').length, 2)
+ })
+
+ it('disables the back navigation button', function () {
+ const node = wrapper.find('div.backforward > div.navigationButtonContainer > .backButton').node
+ assert.equal(node.props.disabled, true)
+ })
+
+ it('disables the forward navigation button', function () {
+ const node = wrapper.find('div.backforward > div.navigationButtonContainer > .forwardButton').node
+ assert.equal(node.props.disabled, true)
+ })
+
+ it('disables the lion icon', function () {
+ const node = wrapper.find('[data-test-id="braveShieldButton"]').node
+ assert.equal(node.props.disabled, true)
+ })
+ })
+})
diff --git a/test/unit/js/navigationBarTest.js b/test/unit/js/navigationBarTest.js
new file mode 100644
index 00000000000..24f01310e03
--- /dev/null
+++ b/test/unit/js/navigationBarTest.js
@@ -0,0 +1,102 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* global describe, before, after, it */
+
+const React = require('react')
+const mockery = require('mockery')
+const {shallow} = require('enzyme')
+const assert = require('assert')
+const Immutable = require('immutable')
+let NavigationBar, UrlBar
+require('../braveUnit')
+
+describe('NavigationBar component unit tests', function () {
+ before(function () {
+ mockery.enable({
+ warnOnReplace: false,
+ warnOnUnregistered: false,
+ useCleanCache: true
+ })
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_no_verified.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_yes_verified.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_no.svg', {})
+ mockery.registerMock('../../extensions/brave/img/urlbar/browser_URL_fund_yes.svg', {})
+ mockery.registerMock('electron', require('../lib/fakeElectron'))
+ NavigationBar = require('../../../js/components/navigationBar')
+ UrlBar = require('../../../app/renderer/components/urlBar')
+ })
+
+ after(function () {
+ mockery.disable()
+ })
+
+ const props = {
+ navbar: Immutable.fromJS({
+ urlbar: {
+ active: true
+ }
+ }),
+ activeFrameKey: 1,
+ canGoForward: false,
+ searchDetail: {
+ example: true
+ },
+ location: 'https://brave.com',
+ title: 'UrlBar unit test',
+ history: {
+ example2: true
+ },
+ isSecure: true,
+ siteSettings: Immutable.fromJS({
+ 'https?://brave.com': {
+ example3: true
+ }
+ }),
+ synopsis: [],
+ activeTabShowingMessageBox: false
+ }
+
+ describe('passing properties through (without changing them) to UrlBar', function () {
+ let urlBar
+
+ before(function () {
+ const wrapper = shallow(
+
+ )
+ urlBar = wrapper.find(UrlBar).node
+ })
+
+ it('passes activeFrameKey', function () {
+ assert.equal(urlBar.props.activeFrameKey, props.activeFrameKey)
+ })
+
+ it('passes canGoForward', function () {
+ assert.equal(urlBar.props.canGoForward, props.canGoForward)
+ })
+
+ it('passes searchDetail', function () {
+ assert.deepEqual(urlBar.props.searchDetail, props.searchDetail)
+ })
+
+ it('passes location', function () {
+ assert.equal(urlBar.props.location, props.location)
+ })
+
+ it('passes title', function () {
+ assert.equal(urlBar.props.title, props.title)
+ })
+
+ it('passes history', function () {
+ assert.equal(urlBar.props.history, props.history)
+ })
+
+ it('passes isSecure', function () {
+ assert.equal(urlBar.props.isSecure, props.isSecure)
+ })
+
+ it('passes activeTabShowingMessageBox', function () {
+ assert.equal(urlBar.props.activeTabShowingMessageBox, props.activeTabShowingMessageBox)
+ })
+ })
+})