diff --git a/src/disco/addonManager.js b/src/disco/addonManager.js
index d03876eaa8c..c8b747e97b9 100644
--- a/src/disco/addonManager.js
+++ b/src/disco/addonManager.js
@@ -28,8 +28,12 @@ export function install(url, eventCallback,
log.info(`[install] Adding listener for ${event}`);
installObj.addEventListener(event, callback);
}
- log.info('Events to handle the installation initialized.');
- return installObj.install();
+ return new Promise((resolve, reject) => {
+ installObj.addEventListener('onInstallEnded', () => resolve());
+ installObj.addEventListener('onInstallFailed', () => reject());
+ log.info('Events to handle the installation initialized.');
+ installObj.install();
+ });
});
}
diff --git a/src/disco/components/Addon.js b/src/disco/components/Addon.js
index d90ec719da1..2fcf5fda1f4 100644
--- a/src/disco/components/Addon.js
+++ b/src/disco/components/Addon.js
@@ -253,7 +253,8 @@ export function makeProgressHandler(dispatch, guid) {
}
export function mapDispatchToProps(dispatch, { _tracking = tracking,
- _addonManager = addonManager } = {}) {
+ _addonManager = addonManager,
+ ...ownProps } = {}) {
if (config.get('server')) {
return {};
}
@@ -272,10 +273,28 @@ export function mapDispatchToProps(dispatch, { _tracking = tracking,
});
},
- install({ guid, installURL, name }) {
+ install() {
+ const { guid, i18n, iconUrl, installURL, name } = ownProps;
dispatch({ type: START_DOWNLOAD, payload: { guid } });
_tracking.sendEvent({ action: 'addon', category: INSTALL_CATEGORY, label: name });
- return _addonManager.install(installURL, makeProgressHandler(dispatch, guid));
+ return _addonManager.install(installURL, makeProgressHandler(dispatch, guid))
+ .then(() => {
+ document.dispatchEvent(new CustomEvent('mozUITour', {
+ bubbles: true,
+ detail: {
+ action: 'showInfo',
+ data: {
+ target: 'appMenu',
+ icon: iconUrl,
+ title: i18n.gettext('Installed and added to toolbar'),
+ text: i18n.sprintf(
+ i18n.gettext('Click here to access %(name)s any time.'),
+ { name }),
+ buttons: [{ label: i18n.gettext('Ok'), callbackID: 'add-on-installed' }],
+ },
+ },
+ }));
+ });
},
uninstall({ guid, name, type }) {
@@ -289,6 +308,6 @@ export function mapDispatchToProps(dispatch, { _tracking = tracking,
};
}
-export default connect(
+export default translate({ withRef: true })(connect(
mapStateToProps, mapDispatchToProps, undefined, { withRef: true }
-)(translate({ withRef: true })(Addon));
+)(Addon));
diff --git a/src/disco/components/InstallButton.js b/src/disco/components/InstallButton.js
index 51097a5a85e..6b8209a643c 100644
--- a/src/disco/components/InstallButton.js
+++ b/src/disco/components/InstallButton.js
@@ -44,7 +44,7 @@ export class InstallButton extends React.Component {
if (type === THEME_TYPE && status === UNINSTALLED) {
installTheme(this.refs.themeData, guid, name);
} else if (status === UNINSTALLED) {
- install({ guid, installURL, name });
+ install();
} else if (status === INSTALLED) {
uninstall({ guid, installURL, name, type });
}
diff --git a/tests/client/disco/TestAddonManager.js b/tests/client/disco/TestAddonManager.js
index 3e063fa8975..482e6b9a51f 100644
--- a/tests/client/disco/TestAddonManager.js
+++ b/tests/client/disco/TestAddonManager.js
@@ -20,15 +20,18 @@ describe('addonManager', () => {
uninstall: sinon.stub(),
};
fakeInstallObj = {
- addEventListener: sinon.stub(),
- install: sinon.stub(),
+ addEventListener: sinon.spy(function addEventListener(eventName, cb) {
+ this[`${eventName}Listener`] = cb;
+ }),
+ install: sinon.spy(function install() {
+ this.onInstallEndedListener();
+ }),
};
fakeMozAddonManager = {
- createInstall: sinon.stub(),
+ createInstall: sinon.stub().returns(Promise.resolve(fakeInstallObj)),
getAddonByID: sinon.stub(),
addEventListener: sinon.stub(),
};
- fakeMozAddonManager.createInstall.returns(Promise.resolve(fakeInstallObj));
});
describe('getAddon()', () => {
@@ -49,31 +52,46 @@ describe('addonManager', () => {
});
describe('install()', () => {
- it('should call mozAddonManager.createInstall() with url', () => {
- addonManager.install(fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager });
- assert.ok(fakeMozAddonManager.createInstall.calledWith({ url: fakeInstallUrl }));
- });
-
- it('should call installObj.addEventListener to setup events', () => addonManager.install(
- fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager })
+ it(
+ 'should call mozAddonManager.createInstall() with url',
+ () => addonManager.install(
+ fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager })
.then(() => {
- assert.equal(fakeInstallObj.addEventListener.callCount, installEventList.length);
+ assert.ok(fakeMozAddonManager.createInstall.calledWith({ url: fakeInstallUrl }));
}));
+ it(
+ 'should call installObj.addEventListener to setup events',
+ () => addonManager.install(
+ fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager })
+ .then(() => {
+ // It registers an extra onInstallFailed and onInstallEnded listener.
+ assert.equal(fakeInstallObj.addEventListener.callCount, installEventList.length + 2);
+ }));
+
it('should call installObj.install()', () => addonManager.install(
fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager })
.then(() => {
assert.ok(fakeInstallObj.install.called);
}));
+ it('rejects if the install fails', () => {
+ fakeInstallObj.install = sinon.spy(function install() {
+ this.onInstallFailedListener();
+ });
+ return addonManager.install(
+ fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager })
+ .then(
+ unexpectedSuccess,
+ () => assert.ok(fakeInstallObj.install.called));
+ });
+
it('passes the installObj, the event and the id to the callback', () => {
const fakeEvent = { type: 'fakeEvent' };
- let callback;
- fakeInstallObj.addEventListener = (event, cb) => { callback = cb; };
return addonManager.install(
fakeInstallUrl, fakeCallback, { _mozAddonManager: fakeMozAddonManager })
.then(() => {
- callback(fakeEvent);
+ fakeInstallObj.onDownloadProgressListener(fakeEvent);
assert.ok(fakeCallback.calledWith(fakeInstallObj, fakeEvent));
});
});
diff --git a/tests/client/disco/components/TestAddon.js b/tests/client/disco/components/TestAddon.js
index efbad28b598..7aa9165f124 100644
--- a/tests/client/disco/components/TestAddon.js
+++ b/tests/client/disco/components/TestAddon.js
@@ -445,7 +445,10 @@ describe('', () => {
it('calls addonManager.install()', () => {
const fakeAddonManager = getFakeAddonManagerWrapper();
const dispatch = sinon.spy();
- const { install } = mapDispatchToProps(dispatch, { _addonManager: fakeAddonManager });
+ const i18n = getFakeI18nInst();
+ const { install } = mapDispatchToProps(
+ dispatch,
+ { _addonManager: fakeAddonManager, i18n, installURL });
return install({ guid, installURL })
.then(() => {
assert(fakeAddonManager.install.calledWith(installURL, sinon.match.func));
@@ -456,12 +459,14 @@ describe('', () => {
const fakeAddonManager = getFakeAddonManagerWrapper();
const name = 'hai-addon';
const type = 'extension';
+ const i18n = getFakeI18nInst();
const dispatch = sinon.spy();
const fakeTracking = {
sendEvent: sinon.spy(),
};
- const { install } = mapDispatchToProps(dispatch,
- { _tracking: fakeTracking, _addonManager: fakeAddonManager });
+ const { install } = mapDispatchToProps(
+ dispatch,
+ { _tracking: fakeTracking, _addonManager: fakeAddonManager, i18n, name });
return install({ guid, installURL, name, type })
.then(() => {
assert(fakeTracking.sendEvent.calledWith({
@@ -472,11 +477,13 @@ describe('', () => {
});
});
-
it('should dispatch START_DOWNLOAD', () => {
const fakeAddonManager = getFakeAddonManagerWrapper();
+ const i18n = getFakeI18nInst();
const dispatch = sinon.spy();
- const { install } = mapDispatchToProps(dispatch, { _addonManager: fakeAddonManager });
+ const { install } = mapDispatchToProps(
+ dispatch,
+ { _addonManager: fakeAddonManager, guid, i18n });
return install({ guid, installURL })
.then(() => assert(dispatch.calledWith({
type: START_DOWNLOAD,
diff --git a/tests/client/disco/components/TestInstallButton.js b/tests/client/disco/components/TestInstallButton.js
index 39134f78368..f022f34bf65 100644
--- a/tests/client/disco/components/TestInstallButton.js
+++ b/tests/client/disco/components/TestInstallButton.js
@@ -136,7 +136,7 @@ describe('', () => {
const button = renderButton({ guid, i18n, install, installURL, name, status: UNINSTALLED });
const root = findDOMNode(button);
Simulate.click(root);
- assert(install.calledWith({ guid, installURL, name }));
+ assert(install.calledWith());
});
it('should call uninstall function on click when installed', () => {
diff --git a/tests/client/helpers.js b/tests/client/helpers.js
index dd6a8077cb2..86bdb47fd06 100644
--- a/tests/client/helpers.js
+++ b/tests/client/helpers.js
@@ -46,6 +46,7 @@ export function getFakeI18nInst() {
dpgettext: sinon.stub(),
npgettext: sinon.stub(),
dnpgettext: sinon.stub(),
+ sprintf: sinon.stub(),
};
}