From 1a49ab86112c4bb80ff5d7c77e69450b402ad0ef Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Thu, 27 Jul 2017 13:04:48 -0700 Subject: [PATCH] Autoplay refactoring fixes #9143 fixes #9008 fixes #9171 Auditors: @bsclifton, @bridiver, @cezaraugusto Test Plan: Covered by automatic test Specific STR for #9171: 1. Turn on autoplay to `always ask` and make sure there is no any allow autoplay permissions 2. Go to https://youtu.be/g_6yBZKj-eo and don't click on notification bar 3. Open another tab and go to https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_video_autoplay and still don't click on notification bar 4. Go back the youtube tab you will find out the notification bar is non clickable 5. Go to the w3schools tab and it will also be non clickable --- app/browser/reducers/autoplayReducer.js | 74 ++- app/renderer/components/frame/frame.js | 1 + js/actions/appActions.js | 11 + js/constants/appConstants.js | 1 + js/state/contentSettings.js | 3 +- .../bravery-components/notificationBarTest.js | 568 ++++++++++++------ test/fixtures/auto-click-play.html | 29 + .../browser/reducers/autoplayReducerTest.js | 292 +++++++++ 8 files changed, 752 insertions(+), 227 deletions(-) create mode 100644 test/fixtures/auto-click-play.html create mode 100644 test/unit/app/browser/reducers/autoplayReducerTest.js diff --git a/app/browser/reducers/autoplayReducer.js b/app/browser/reducers/autoplayReducer.js index d18c14f06c0..21f856d342b 100644 --- a/app/browser/reducers/autoplayReducer.js +++ b/app/browser/reducers/autoplayReducer.js @@ -7,31 +7,26 @@ const appConstants = require('../../../js/constants/appConstants') const {makeImmutable} = require('../../common/state/immutableUtil') const {ipcMain, webContents} = require('electron') -const AppStore = require('../../../js/stores/appStore') const siteSettings = require('../../../js/state/siteSettings') -const settings = require('../../../js/constants/settings') const appActions = require('../../../js/actions/appActions') const {getOrigin} = require('../../../js/state/siteUtil') const locale = require('../../locale') const messages = require('../../../js/constants/messages') -const getSetting = require('../../../js/settings').getSetting -const {autoplayOption} = require('../../common/constants/settingsEnums') -const showAutoplayMessageBox = (tabId) => { +let notificationCallbacks = [] + +const showAutoplayMessageBox = (state, tabId) => { const tab = webContents.fromTabID(tabId) if (!tab || tab.isDestroyed()) { return } const location = tab.getURL() const origin = getOrigin(location) - if (getSetting(settings.AUTOPLAY_MEDIA) === autoplayOption.ALWAYS_ALLOW) { - appActions.changeSiteSetting(origin, 'autoplay', true) - return - } - const originSettings = siteSettings.getSiteSettingsForURL(AppStore.getState().get('siteSettings'), origin) + const originSettings = siteSettings.getSiteSettingsForURL(state.get('siteSettings'), origin) if (originSettings && originSettings.get('autoplay') === false) { return } + const message = locale.translation('allowAutoplay', {origin}) appActions.showNotification({ @@ -46,33 +41,60 @@ const showAutoplayMessageBox = (tabId) => { } }) - ipcMain.once(messages.NOTIFICATION_RESPONSE, (e, msg, buttonIndex, persist) => { - if (msg === message) { - appActions.hideNotification(message) - if (buttonIndex === 0) { - appActions.changeSiteSetting(origin, 'autoplay', true) - if (tab && !tab.isDestroyed()) { - tab.reload() - tab.on('destroyed', function temporaryAllow (e) { - if (!persist) { - appActions.removeSiteSetting(origin, 'autoplay') + if (!notificationCallbacks[tabId]) { + notificationCallbacks[tabId] = (e, msg, buttonIndex, persist) => { + if (msg === message) { + appActions.hideNotification(message) + if (buttonIndex === 0) { + appActions.changeSiteSetting(origin, 'autoplay', true) + if (tab && !tab.isDestroyed()) { + tab.reload() + const temporaryAllow = (e) => { + tab.removeListener('media-started-playing', temporaryAllow) + if (!persist) { + appActions.removeSiteSetting(origin, 'autoplay') + } } - }) + tab.on('media-started-playing', temporaryAllow) + } + } else { + if (persist) { + appActions.changeSiteSetting(origin, 'autoplay', false) + } } - } else { - if (persist) { - appActions.changeSiteSetting(origin, 'autoplay', false) + if (notificationCallbacks[tabId]) { + ipcMain.removeListener(messages.NOTIFICATION_RESPONSE, notificationCallbacks[tabId]) + delete notificationCallbacks[tabId] } } } - }) + ipcMain.on(messages.NOTIFICATION_RESPONSE, notificationCallbacks[tabId]) + } +} + +const hideAutoplayMessageBox = (tabId) => { + const tab = webContents.fromTabID(tabId) + if (!tab || tab.isDestroyed()) { + return + } + const location = tab.getURL() + const origin = getOrigin(location) + const message = locale.translation('allowAutoplay', {origin}) + appActions.hideNotification(message) + if (notificationCallbacks[tabId]) { + ipcMain.removeListener(messages.NOTIFICATION_RESPONSE, notificationCallbacks[tabId]) + delete notificationCallbacks[tabId] + } } const autoplayReducer = (state, action, immutableAction) => { action = immutableAction || makeImmutable(action) switch (action.get('actionType')) { case appConstants.APP_AUTOPLAY_BLOCKED: - showAutoplayMessageBox(action.get('tabId')) + showAutoplayMessageBox(state, action.get('tabId')) + break + case appConstants.APP_AUTOPLAY_DISMISSED: + hideAutoplayMessageBox(action.get('tabId')) break } return state diff --git a/app/renderer/components/frame/frame.js b/app/renderer/components/frame/frame.js index 5ad3ef64eff..a6d59b624a2 100644 --- a/app/renderer/components/frame/frame.js +++ b/app/renderer/components/frame/frame.js @@ -779,6 +779,7 @@ class Frame extends React.Component { if (this.frame.isEmpty()) { return } + appActions.autoplayDismissed(this.props.tabId) windowActions.setAudioPlaybackActive(this.frame, true) }) this.webview.addEventListener('media-paused', ({title}) => { diff --git a/js/actions/appActions.js b/js/actions/appActions.js index dba81112cdd..3ecc3ac8531 100644 --- a/js/actions/appActions.js +++ b/js/actions/appActions.js @@ -1292,6 +1292,17 @@ const appActions = { }) }, + /** + * Notifies autoplay notification can be dismissed + * @param {number} tabId - Tab id of current frame + */ + autoplayDismissed: function (tabId) { + dispatch({ + actionType: appConstants.APP_AUTOPLAY_DISMISSED, + tabId + }) + }, + /** * Handle 'save-password' event from muon */ diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js index f8e12793899..761c4dcf9af 100644 --- a/js/constants/appConstants.js +++ b/js/constants/appConstants.js @@ -125,6 +125,7 @@ const appConstants = { APP_ON_GO_BACK_LONG: _, APP_ON_GO_FORWARD_LONG: _, APP_AUTOPLAY_BLOCKED: _, + APP_AUTOPLAY_DISMISSED: _, APP_SAVE_PASSWORD: _, APP_UPDATE_PASSWORD: _, APP_ADD_PASSWORD: _, /** @param {Object} passwordDetail */ diff --git a/js/state/contentSettings.js b/js/state/contentSettings.js index 0c94ff98f53..e94e4acf912 100644 --- a/js/state/contentSettings.js +++ b/js/state/contentSettings.js @@ -17,6 +17,7 @@ const urlParse = require('../../app/common/urlParse') const siteSettings = require('./siteSettings') const {registerUserPrefs} = require('./userPrefs') const {getSetting} = require('../settings') +const {autoplayOption} = require('../../app/common/constants/settingsEnums') const {getFlashResourceId} = require('../flash') const net = require('net') @@ -70,7 +71,7 @@ const getDefaultUserPrefContentSettings = (braveryDefaults, appSettings, appConf braveryDefaults = makeImmutable(braveryDefaults) return Immutable.fromJS({ autoplay: [{ - setting: 'block', + setting: getSetting(settings.AUTOPLAY_MEDIA) === autoplayOption.ALWAYS_ALLOW ? 'allow' : 'block', primaryPattern: '*' }], cookies: getDefault3rdPartyStorageSettings(braveryDefaults, appSettings, appConfig), diff --git a/test/bravery-components/notificationBarTest.js b/test/bravery-components/notificationBarTest.js index ee65f65839c..c756df1494f 100644 --- a/test/bravery-components/notificationBarTest.js +++ b/test/bravery-components/notificationBarTest.js @@ -285,211 +285,379 @@ describe('Autoplay test', function () { yield setup(this.app.client) }) - it('default always ask and block', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - }) + describe('autoplay', function () { + it('default always ask and block', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) - it('always allow', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .changeSetting('security.autoplay.media', autoplayOption.ALWAYS_ALLOW) - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - }) + it('always allow', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .changeSetting('security.autoplay.media', autoplayOption.ALWAYS_ALLOW) + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) - it('allow autoplay until tab closed', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('button=Yes') - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .newTab({ url }) - .waitForTabCount(2) - .waitForUrl(url) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .closeTabByIndex(0) - .activateURLMode() - .click(reloadButton) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - }) + it('allow autoplay once', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) - it('allow autoplay and remember', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('[data-l10n-id=rememberDecision]') - .click('button=Yes') - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .newTab({ url }) - .waitForTabCount(2) - .waitForUrl(url) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .closeTabByIndex(0) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === 'Autoplay playing' - }) - }) - }) + it('allow autoplay and remember', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .newTab({ url }) + .waitForTabCount(2) + .waitForUrl(url) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .closeTabByIndex(0) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) - it('keep blocking autoplay', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('button=No') - .windowByUrl(Brave.browserWindowUrl) - .activateURLMode() - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) + it('keep blocking autoplay', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + }) + + it('keep blocking autoplay and remember', function * () { + const url = Brave.server.url('autoplay.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForElementCount('.notificationItem', 0) + }) }) - it('keep blocking autoplay and remember', function * () { - const url = Brave.server.url('autoplay.html') - yield this.app.client - .tabByIndex(0) - .loadUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForExist(notificationBar) - .waitUntil(function () { - return this.getText(notificationBar).then((val) => val.includes('autoplay media')) - }) - .click('[data-l10n-id=rememberDecision]') - .click('button=No') - .windowByUrl(Brave.browserWindowUrl) - .click(reloadButton) - .tabByUrl(url) - .waitUntil(function () { - return this.getText('div[id="status"]') - .then((status) => { - return status === '' - }) - }) - .windowByUrl(Brave.browserWindowUrl) - .waitForElementCount('.notificationItem', 0) + describe('auto-click-play', function () { + it('default always ask and block', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) + + it('always allow', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .changeSetting('security.autoplay.media', autoplayOption.ALWAYS_ALLOW) + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) + + it('allow autoplay once', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + }) + + it('allow autoplay and remember', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=Yes') + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .newTab({ url }) + .waitForTabCount(2) + .waitForUrl(url) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .closeTabByIndex(0) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === 'Autoplay playing' + }) + }) + }) + + it('keep blocking autoplay', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .activateURLMode() + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + }) + + it('keep blocking autoplay and remember', function * () { + const url = Brave.server.url('auto-click-play.html') + yield this.app.client + .tabByIndex(0) + .loadUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForExist(notificationBar) + .waitUntil(function () { + return this.getText(notificationBar).then((val) => val.includes('autoplay media')) + }) + .click('[data-l10n-id=rememberDecision]') + .click('button=No') + .windowByUrl(Brave.browserWindowUrl) + .click(reloadButton) + .tabByUrl(url) + .waitUntil(function () { + return this.getText('div[id="status"]') + .then((status) => { + return status === '' + }) + }) + .windowByUrl(Brave.browserWindowUrl) + .waitForElementCount('.notificationItem', 0) + }) }) }) diff --git a/test/fixtures/auto-click-play.html b/test/fixtures/auto-click-play.html new file mode 100644 index 00000000000..55581055530 --- /dev/null +++ b/test/fixtures/auto-click-play.html @@ -0,0 +1,29 @@ + + + + + Autoplay + + + + + +
+ + + + + + diff --git a/test/unit/app/browser/reducers/autoplayReducerTest.js b/test/unit/app/browser/reducers/autoplayReducerTest.js new file mode 100644 index 00000000000..b69d6194926 --- /dev/null +++ b/test/unit/app/browser/reducers/autoplayReducerTest.js @@ -0,0 +1,292 @@ +/* global describe, it, before, after */ +const mockery = require('mockery') +const sinon = require('sinon') +const Immutable = require('immutable') +const assert = require('assert') +const fakeElectron = require('../../../lib/fakeElectron') + +const appConstants = require('../../../../../js/constants/appConstants') +const messages = require('../../../../../js/constants/messages') +require('../../../braveUnit') + +describe('autoplayReducer unit tests', function () { + let autoplayReducer + let fakeWebContents, fakeAppActions, fakeLocale + let showNotificationSpy, hideNotificationSpy, translationSpy, + removeListenerSpy, changeSiteSettingSpy, removeSiteSettingSpy + const tabId = 123 + const url = 'https://www.brave.com/niceplay' + const origin = 'https://www.brave.com' + const message = `Allow ${origin} to autoplay media?` + const showNotificationArg = { + buttons: [ + {text: 'Yes'}, + {text: 'No'} + ], + message, + frameOrigin: origin, + options: { + persist: true + } + } + + before(function () { + mockery.enable({ + warnOnReplace: false, + warnOnUnregistered: false, + useCleanCache: true + }) + + fakeWebContents = { + isDestroyed: () => false, + reload: () => {}, + on: (e, cb) => { cb(e) }, + removeListener: (e, cb) => {}, + getURL: () => { + return url + } + } + + fakeAppActions = { + showNotification: (arg) => {}, + hideNotification: (msg) => {}, + changeSiteSetting: (hostPattern, key, value) => {}, + removeSiteSetting: (hostPattern, key) => {} + } + + fakeLocale = { + translation: (msg, arg) => { + let retMsg = '' + switch (msg) { + case 'yes': + retMsg += 'Yes' + break + case 'no': + retMsg += 'No' + break + case 'allowAutoplay': + retMsg += `Allow ${arg.origin} to autoplay media?` + break + } + return retMsg + } + } + + fakeElectron.webContents = { + fromTabID: (tabId) => { + return fakeWebContents + } + } + + showNotificationSpy = sinon.spy(fakeAppActions, 'showNotification') + hideNotificationSpy = sinon.spy(fakeAppActions, 'hideNotification') + translationSpy = sinon.spy(fakeLocale, 'translation') + removeListenerSpy = sinon.spy(fakeElectron.ipcMain, 'removeListener') + changeSiteSettingSpy = sinon.spy(fakeAppActions, 'changeSiteSetting') + removeSiteSettingSpy = sinon.spy(fakeAppActions, 'removeSiteSetting') + + mockery.registerMock('electron', fakeElectron) + mockery.registerMock('../../../js/actions/appActions', fakeAppActions) + mockery.registerMock('../../locale', fakeLocale) + + autoplayReducer = require('../../../../../app/browser/reducers/autoplayReducer') + }) + + after(function () { + showNotificationSpy.restore() + hideNotificationSpy.restore() + translationSpy.restore() + removeListenerSpy.restore() + changeSiteSettingSpy.restore() + removeSiteSettingSpy.restore() + mockery.deregisterAll() + mockery.disable() + }) + + describe('Allow autoplay once', function () { + before(function () { + autoplayReducer(Immutable.fromJS({ + siteSettings: {} + }), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_BLOCKED, + tabId: tabId + })) + fakeElectron.ipcMain.send(messages.NOTIFICATION_RESPONSE, {}, message, 0, false) + }) + + it('calls local.translation', function () { + assert(translationSpy.withArgs('allowAutoplay', {origin}).called) + assert(translationSpy.withArgs('yes').called) + assert(translationSpy.withArgs('no').called) + }) + + it('calls appActions.showNotification', function () { + assert(showNotificationSpy.withArgs(showNotificationArg).called) + }) + + it('calls appActions.hideNotification', function () { + assert(hideNotificationSpy.withArgs(message).called) + }) + + it('calls appActions.changeSiteSetting', function () { + assert(changeSiteSettingSpy.withArgs(origin, 'autoplay', true).called) + }) + + it('calls appActions.removeSiteSetting', function () { + assert(removeSiteSettingSpy.withArgs(origin, 'autoplay').called) + }) + + it('calls ipcMain.removeListener', function () { + assert(removeListenerSpy.called) + }) + }) + + describe('Allow autoplay and remember', function () { + before(function () { + autoplayReducer(Immutable.fromJS({ + siteSettings: {} + }), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_BLOCKED, + tabId: tabId + })) + fakeElectron.ipcMain.send(messages.NOTIFICATION_RESPONSE, {}, message, 0, true) + }) + + it('calls local.translation', function () { + assert(translationSpy.withArgs('allowAutoplay', {origin}).called) + assert(translationSpy.withArgs('yes').called) + assert(translationSpy.withArgs('no').called) + }) + + it('calls appActions.showNotification', function () { + assert(showNotificationSpy.withArgs(showNotificationArg).called) + }) + + it('calls appActions.hideNotification', function () { + assert(hideNotificationSpy.withArgs(message).called) + }) + + it('calls appActions.changeSiteSetting', function () { + assert(changeSiteSettingSpy.withArgs(origin, 'autoplay', true).called) + }) + + it('calls ipcMain.removeListener', function () { + assert(removeListenerSpy.called) + }) + }) + + describe('Deny autoplay once', function () { + before(function () { + autoplayReducer(Immutable.fromJS({ + siteSettings: {} + }), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_BLOCKED, + tabId: tabId + })) + fakeElectron.ipcMain.send(messages.NOTIFICATION_RESPONSE, {}, message, 1, false) + }) + + it('calls local.translation', function () { + assert(translationSpy.withArgs('allowAutoplay', {origin}).called) + assert(translationSpy.withArgs('yes').called) + assert(translationSpy.withArgs('no').called) + }) + + it('calls appActions.showNotification', function () { + assert(showNotificationSpy.withArgs(showNotificationArg).called) + }) + + it('calls appActions.hideNotification', function () { + assert(hideNotificationSpy.withArgs(message).called) + }) + + it('calls ipcMain.removeListener', function () { + assert(removeListenerSpy.called) + }) + }) + + describe('Deny autoplay and remember', function () { + before(function () { + autoplayReducer(Immutable.fromJS({ + siteSettings: {} + }), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_BLOCKED, + tabId: tabId + })) + fakeElectron.ipcMain.send(messages.NOTIFICATION_RESPONSE, {}, message, 1, true) + }) + + it('calls local.translation', function () { + assert(translationSpy.withArgs('allowAutoplay', {origin}).called) + assert(translationSpy.withArgs('yes').called) + assert(translationSpy.withArgs('no').called) + }) + + it('calls appActions.showNotification', function () { + assert(showNotificationSpy.withArgs(showNotificationArg).called) + }) + + it('calls appActions.hideNotification', function () { + assert(hideNotificationSpy.withArgs(message).called) + }) + + it('calls appActions.changeSiteSetting', function () { + assert(changeSiteSettingSpy.withArgs(origin, 'autoplay', false).called) + }) + + it('calls ipcMain.removeListener', function () { + assert(removeListenerSpy.called) + }) + }) + + describe('Calling with exsting deny rules', function () { + before(function () { + showNotificationSpy.reset() + autoplayReducer(Immutable.fromJS({ + siteSettings: { + 'https://www.brave.com': { + autoplay: false + } + } + }), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_BLOCKED, + tabId: tabId + })) + autoplayReducer(Immutable.Map(), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_DISMISSED, + tabId: tabId + })) + + it('never calls appActions.showNotification', function () { + assert(showNotificationSpy.neverCalledWith(showNotificationArg)) + }) + }) + }) + + describe('APP_AUTOPLAY_DISMISSED', function () { + before(function () { + autoplayReducer(Immutable.fromJS({ + siteSettings: {} + }), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_BLOCKED, + tabId: tabId + })) + autoplayReducer(Immutable.Map(), Immutable.fromJS({ + actionType: appConstants.APP_AUTOPLAY_DISMISSED, + tabId: tabId + })) + }) + + it('calls local.translation', function () { + assert(translationSpy.withArgs('allowAutoplay', {origin}).called) + }) + + it('calls appActions.hideNotification', function () { + assert(hideNotificationSpy.withArgs(message).called) + }) + + it('calls ipcMain.removeListener', function () { + assert(removeListenerSpy.called) + }) + }) +})