diff --git a/app/browser/reducers/aboutWelcomeReducer.js b/app/browser/reducers/aboutWelcomeReducer.js new file mode 100644 index 00000000000..23a1a00b2d5 --- /dev/null +++ b/app/browser/reducers/aboutWelcomeReducer.js @@ -0,0 +1,20 @@ +/* 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/. */ + +'use strict' + +const appConstants = require('../../../js/constants/appConstants') +const {makeImmutable} = require('../../common/state/immutableUtil') + +const aboutWelcomeReducer = (state, action, immutableAction) => { + action = immutableAction || makeImmutable(action) + switch (action.get('actionType')) { + case appConstants.APP_ACTIVATE_WELCOME_SCREEN: + state = state.setIn(['about', 'welcome', 'showOnLoad'], action.get('activateWelcomeScreen')) + break + } + return state +} + +module.exports = aboutWelcomeReducer diff --git a/app/browser/tabs.js b/app/browser/tabs.js index d0002e7b030..75b9fc65609 100644 --- a/app/browser/tabs.js +++ b/app/browser/tabs.js @@ -28,6 +28,7 @@ const {cleanupWebContents, currentWebContents, getWebContents, updateWebContents const {FilterOptions} = require('ad-block') const {isResourceEnabled} = require('../filtering') const autofill = require('../autofill') +const l10n = require('../../js/l10n') let currentPartitionNumber = 0 const incrementPartitionNumber = () => ++currentPartitionNumber @@ -179,6 +180,7 @@ const updateAboutDetails = (tab, tabValue) => { const autofillAddresses = appState.getIn(['autofill', 'addresses']) const versionInformation = appState.getIn(['about', 'brave', 'versionInformation']) const aboutDetails = tabValue.get('aboutDetails') + // TODO(bridiver) - convert this to an action if (url === 'about:preferences#payments') { tab.on('destroyed', () => { @@ -656,7 +658,10 @@ const api = { return true }, - create: (createProperties, cb = null, isRestore = false) => { + create: (createProperties, cb = null, isRestore = false, skipIfTest = true) => { + const appState = appStore.getState() + let shouldShowWelcomeScreen = appState.getIn(['about', 'welcome', 'showOnLoad']) + setImmediate(() => { const {safeBrowsingInstance} = require('../adBlock') createProperties = makeImmutable(createProperties).toJS() @@ -673,6 +678,19 @@ const api = { } if (!createProperties.url) { createProperties.url = newFrameUrl() + // don't open welcome screen for general tests + if (skipIfTest && process.env.NODE_ENV === 'test') { + shouldShowWelcomeScreen = false + } + if (shouldShowWelcomeScreen !== false) { + appActions.createTabRequested({ + url: 'about:welcome', + // avoid chrome-extension title + // while page's title is not fetch + title: l10n.translation('aboutWelcome') + }) + appActions.activateWelcomeScreen(false) + } } createProperties.url = normalizeUrl(createProperties.url) // TODO(bridiver) - this should be in filtering diff --git a/app/sessionStore.js b/app/sessionStore.js index e3748ab1f46..8f020c74943 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -656,6 +656,9 @@ module.exports.defaultAppState = () => { sites: topSites, ignoredTopSites: [], pinnedTopSites: pinnedTopSites + }, + welcome: { + showOnLoad: true } }, trackingProtection: { diff --git a/docs/appActions.md b/docs/appActions.md index d5822a2acaf..543ff93beb7 100644 --- a/docs/appActions.md +++ b/docs/appActions.md @@ -1130,6 +1130,17 @@ Clear temp setting for clear browsing data +### activateWelcomeScreen(shouldShowWelcomeScreen) + +Dispatches a message to the store to show the welcome screen. + +**Parameters** + +**shouldShowWelcomeScreen**: `Boolean`, true if a new tab +with the welcome screen should be show + + + * * * diff --git a/js/actions/appActions.js b/js/actions/appActions.js index 75ac5154976..835563f08a4 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -1442,6 +1442,19 @@ const appActions = { dispatch({ actionType: appConstants.APP_ON_CANCEL_BROWSING_DATA }) + }, + + /** + * Dispatches a message to the store to show the welcome screen. + * + * @param {Boolean} shouldShowWelcomeScreen - true if a new tab + * with the welcome screen should be show + */ + activateWelcomeScreen: function (activateWelcomeScreen) { + dispatch({ + actionType: appConstants.APP_ACTIVATE_WELCOME_SCREEN, + activateWelcomeScreen + }) } } diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index 03d69035d51..84a377d3dcc 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -124,6 +124,7 @@ const appConstants = { APP_ON_GO_TO_INDEX: _, APP_ON_GO_BACK_LONG: _, APP_ON_GO_FORWARD_LONG: _, + APP_ACTIVATE_WELCOME_SCREEN: _, APP_AUTOPLAY_BLOCKED: _, APP_SAVE_PASSWORD: _, APP_UPDATE_PASSWORD: _, diff --git a/js/stores/appStore.js b/js/stores/appStore.js index d07dd906886..91858e9813f 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -403,6 +403,7 @@ const handleAppAction = (action) => { require('../../app/browser/reducers/extensionsReducer'), require('../../app/browser/reducers/shareReducer'), require('../../app/browser/reducers/updatesReducer'), + require('../../app/browser/reducers/aboutWelcomeReducer'), require('../../app/ledger').doAction ] initialized = true diff --git a/test/unit/app/browser/reducers/aboutWelcomeReducerTest.js b/test/unit/app/browser/reducers/aboutWelcomeReducerTest.js new file mode 100644 index 00000000000..39ebe40eeb2 --- /dev/null +++ b/test/unit/app/browser/reducers/aboutWelcomeReducerTest.js @@ -0,0 +1,38 @@ +/* global describe, it, before, after */ +const mockery = require('mockery') +const Immutable = require('immutable') +const assert = require('assert') +const appConstants = require('../../../../../js/constants/appConstants') +const fakeElectron = require('../../../lib/fakeElectron') + +require('../../../braveUnit') + +describe('aboutWelcomeReducer', function () { + let aboutWelcomeReducer + + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + mockery.registerMock('electron', fakeElectron) + aboutWelcomeReducer = require('../../../../../app/browser/reducers/aboutWelcomeReducer') + }) + + after(function () { + mockery.disable() + }) + + describe('APP_ACTIVATE_WELCOME_SCREEN', function () { + before(function () { + this.newState = aboutWelcomeReducer(Immutable.Map(), { + actionType: appConstants.APP_ACTIVATE_WELCOME_SCREEN, + activateWelcomeScreen: false + }) + }) + it('can set visibility state to false', function () { + assert.equal(this.newState.getIn(['about', 'welcome', 'showOnLoad']), false) + }) + }) +}) diff --git a/test/unit/app/browser/tabsTest.js b/test/unit/app/browser/tabsTest.js index c36fbe99623..70a7a4a558d 100644 --- a/test/unit/app/browser/tabsTest.js +++ b/test/unit/app/browser/tabsTest.js @@ -9,7 +9,7 @@ const fakeAdBlock = require('../../lib/fakeAdBlock') require('../../braveUnit') -describe('tabs API', function () { +describe('tabs API unit tests', function () { let tabs, appActions before(function () { mockery.enable({ @@ -59,9 +59,28 @@ describe('tabs API', function () { }] }) + this.appState = { + about: { + welcome: { + showOnLoad: true + } + } + } + + this.appStore = { + getState: () => Immutable.fromJS(this.appState) + } + mockery.registerMock('electron', fakeElectron) mockery.registerMock('ad-block', fakeAdBlock) mockery.registerMock('leveldown', {}) + mockery.registerMock('../../js/stores/appStore', this.appStore) + mockery.registerMock('../../js/l10n', { + translation: (word) => word + }) + mockery.registerMock('../filtering', { + isResourceEnabled: (resourceName, url, isPrivate) => false + }) mockery.registerMock('./webContentsCache', { getWebContents: (tabId) => { @@ -90,25 +109,17 @@ describe('tabs API', function () { 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 () { + afterEach(function () { + this.tabWithDevToolsClosed.openDevTools.reset() + this.tabWithDevToolsClosed.closeDevTools.reset() + this.tabWithDevToolsOpened.openDevTools.reset() + this.tabWithDevToolsOpened.closeDevTools.reset() + }) it('opens dev tools if closed', function () { tabs.toggleDevTools(1) assert(this.tabWithDevToolsClosed.openDevTools.calledOnce) @@ -130,6 +141,7 @@ describe('tabs API', function () { assert(this.tabWithDevToolsOpenedAndFocused.closeDevTools.notCalled) }) }) + describe('isDevToolsFocused', function () { it('returns false if devtools are opened but not focused', function () { assert.equal(tabs.isDevToolsFocused(1), false) @@ -141,12 +153,21 @@ describe('tabs API', function () { assert.equal(tabs.isDevToolsFocused(3), true) }) }) + describe('moveTo', function () { before(function () { this.browserOpts = { positionByMouseCursor: true } }) + beforeEach(function () { + this.newWindowSpy = sinon.spy(appActions, 'newWindow') + this.newWebContentsAddedSpy = sinon.spy(appActions, 'newWebContentsAdded') + }) + afterEach(function () { + this.newWindowSpy.restore() + this.newWebContentsAddedSpy.restore() + }) it('moves tab to a new window', function () { const state = this.state.set('dragData', Immutable.fromJS({ windowId: 1, @@ -318,8 +339,49 @@ describe('tabs API', function () { }) }) - describe.skip('create', function () { - it('todo', function () { + describe('create', function () { + before(function () { + this.clock = sinon.useFakeTimers() + this.createTabRequestedSpy = sinon.spy(appActions, 'createTabRequested') + this.activateWelcomeScreenSpy = sinon.spy(appActions, 'activateWelcomeScreen') + this.extensionsCreateTabSpy = sinon.spy(fakeElectron.extensions, 'createTab') + }) + + after(function () { + this.clock.restore() + this.createTabRequestedSpy.restore() + this.activateWelcomeScreenSpy.restore() + this.extensionsCreateTabSpy.restore() + }) + + const createProperties = Immutable.fromJS({}) + const cb = null + const isRestore = false + const skipIfTest = false + + describe('when createProperties.url is not set', function () { + it('calls appActions.createTabRequested', function () { + this.createTabRequestedSpy.reset() + tabs.create(createProperties, cb, isRestore, skipIfTest) + this.clock.tick(1510) + assert.equal(this.createTabRequestedSpy.calledOnce, true) + }) + + describe('when welcome screen has not shown yet', function () { + it('calls appActions.activateWelcomeScreen if state is true', function () { + this.activateWelcomeScreenSpy.reset() + tabs.create(createProperties, cb, isRestore, skipIfTest) + this.clock.tick(1510) + assert.equal(this.activateWelcomeScreenSpy.calledOnce, true) + }) + }) + }) + + it('calls electron.extensions.createTab', function () { + this.extensionsCreateTabSpy.reset() + tabs.create(createProperties, cb, isRestore, skipIfTest) + this.clock.tick(1510) + assert.equal(this.extensionsCreateTabSpy.calledOnce, true) }) }) diff --git a/test/unit/app/sessionStoreTest.js b/test/unit/app/sessionStoreTest.js index 19fd92e789b..e99c3ccd431 100644 --- a/test/unit/app/sessionStoreTest.js +++ b/test/unit/app/sessionStoreTest.js @@ -854,6 +854,10 @@ describe('sessionStore unit tests', function () { }) describe('defaultAppState', function () { + it('sets showOnLoad to true (which triggers about:welcome)', function () { + const defaultAppState = sessionStore.defaultAppState() + assert.equal(defaultAppState.about.welcome.showOnLoad, true) + }) }) describe('isProtocolHandled', function () { diff --git a/test/unit/lib/fakeElectron.js b/test/unit/lib/fakeElectron.js index 19ba7489c58..f77c09e3ed7 100644 --- a/test/unit/lib/fakeElectron.js +++ b/test/unit/lib/fakeElectron.js @@ -79,6 +79,9 @@ const fakeElectron = { defaultSession: { partition: 'default' } + }, + extensions: { + createTab: function () {} } }