Bug 1441984 - Only show OpenInPrivateBrowsing option if private browsing enabled

This commit is contained in:
k88hudson 2018-03-01 13:23:11 -05:00
Родитель 9df2a5ee0d
Коммит 1623117fcb
6 изменённых файлов: 64 добавлений и 29 удалений

Просмотреть файл

@ -1,4 +1,5 @@
import {actionCreators as ac} from "common/Actions.jsm";
import {connect} from "react-redux";
import {ContextMenu} from "content-src/components/ContextMenu/ContextMenu";
import {injectIntl} from "react-intl";
import {LinkMenuOptions} from "content-src/lib/link-menu-options";
@ -9,12 +10,12 @@ const DEFAULT_SITE_MENU_OPTIONS = ["CheckPinTopSite", "EditTopSite", "Separator"
export class _LinkMenu extends React.PureComponent {
getOptions() {
const {props} = this;
const {site, index, source} = props;
const {site, index, source, isPrivateBrowsingEnabled} = props;
// Handle special case of default site
const propOptions = !site.isDefault ? props.options : DEFAULT_SITE_MENU_OPTIONS;
const options = propOptions.map(o => LinkMenuOptions[o](site, index, source)).map(option => {
const options = propOptions.map(o => LinkMenuOptions[o](site, index, source, isPrivateBrowsingEnabled)).map(option => {
const {action, impression, id, string_id, type, userEvent} = option;
if (!type && id) {
option.label = props.intl.formatMessage({id: string_id || id});
@ -50,4 +51,5 @@ export class _LinkMenu extends React.PureComponent {
}
}
export const LinkMenu = injectIntl(_LinkMenu);
const getState = state => ({isPrivateBrowsingEnabled: state.Prefs.values.isPrivateBrowsingEnabled});
export const LinkMenu = connect(getState)(injectIntl(_LinkMenu));

Просмотреть файл

@ -1,5 +1,15 @@
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
const _OpenInPrivateWindow = site => ({
id: "menu_action_open_private_window",
icon: "new-window-private",
action: ac.OnlyToMain({
type: at.OPEN_PRIVATE_WINDOW,
data: {url: site.url, referrer: site.referrer}
}),
userEvent: "OPEN_PRIVATE_WINDOW"
});
/**
* List of functions that return items that can be included as menu options in a
* LinkMenu. All functions take the site as the first parameter, and optionally
@ -35,15 +45,6 @@ export const LinkMenuOptions = {
}),
userEvent: "OPEN_NEW_WINDOW"
}),
OpenInPrivateWindow: site => ({
id: "menu_action_open_private_window",
icon: "new-window-private",
action: ac.AlsoToMain({
type: at.OPEN_PRIVATE_WINDOW,
data: {url: site.url, referrer: site.referrer}
}),
userEvent: "OPEN_PRIVATE_WINDOW"
}),
BlockUrl: (site, index, eventSource) => ({
id: "menu_action_dismiss",
icon: "dismiss",
@ -152,5 +153,6 @@ export const LinkMenuOptions = {
CheckPinTopSite: (site, index) => (site.isPinned ? LinkMenuOptions.UnpinTopSite(site) : LinkMenuOptions.PinTopSite(site, index)),
CheckSavedToPocket: (site, index) => (site.pocket_id ? LinkMenuOptions.DeleteFromPocket(site) : LinkMenuOptions.SaveToPocket(site, index)),
CheckBookmarkOrArchive: site => (site.pocket_id ? LinkMenuOptions.ArchiveFromPocket(site) : LinkMenuOptions.CheckBookmark(site)),
CheckDeleteHistoryOrEmpty: (site, index, eventSource) => (site.pocket_id ? LinkMenuOptions.EmptyItem() : LinkMenuOptions.DeleteUrl(site, index, eventSource))
CheckDeleteHistoryOrEmpty: (site, index, eventSource) => (site.pocket_id ? LinkMenuOptions.EmptyItem() : LinkMenuOptions.DeleteUrl(site, index, eventSource)),
OpenInPrivateWindow: (site, index, eventSource, isEnabled) => (isEnabled ? _OpenInPrivateWindow(site) : LinkMenuOptions.EmptyItem())
};

Просмотреть файл

@ -8,6 +8,9 @@ const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStrea
const {PrerenderData} = ChromeUtils.import("resource://activity-stream/common/PrerenderData.jsm", {});
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
this.PrefsFeed = class PrefsFeed {
@ -63,6 +66,9 @@ this.PrefsFeed = class PrefsFeed {
values[name] = this._prefs.get(name);
}
// Not a pref, but we need this to determine whether to show private-browsing-related stuff
values.isPrivateBrowsingEnabled = PrivateBrowsingUtils.enabled;
// Set the initial state of all prefs in redux
this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values}));

Просмотреть файл

@ -1,8 +1,11 @@
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
import {Card, PlaceholderCard} from "content-src/components/Card/Card";
import {combineReducers, createStore} from "redux";
import {INITIAL_STATE, reducers} from "common/Reducers.jsm";
import {cardContextTypes} from "content-src/components/Card/types";
import {LinkMenu} from "content-src/components/LinkMenu/LinkMenu";
import {mountWithIntl} from "test/unit/utils";
import {Provider} from "react-redux";
import React from "react";
import {shallow} from "enzyme";
@ -23,10 +26,15 @@ let DEFAULT_PROPS = {
contextMenuOptions: ["Separator"]
};
function mountCardWithProps(props) {
const store = createStore(combineReducers(reducers), INITIAL_STATE);
return mountWithIntl(<Provider store={store}><Card {...props} /></Provider>);
}
describe("<Card>", () => {
let wrapper;
beforeEach(() => {
wrapper = mountWithIntl(<Card {...DEFAULT_PROPS} />);
wrapper = mountCardWithProps(DEFAULT_PROPS);
});
it("should render a Card component", () => assert.ok(wrapper.exists()));
it("should add the right url", () => assert.propertyVal(wrapper.find("a").props(), "href", DEFAULT_PROPS.link.url));
@ -42,7 +50,7 @@ describe("<Card>", () => {
const link = Object.assign({}, DEFAULT_PROPS.link);
delete link.image;
wrapper = mountWithIntl(<Card {...Object.assign({}, DEFAULT_PROPS, {link})} />);
wrapper = mountCardWithProps(Object.assign({}, DEFAULT_PROPS, {link}));
assert.lengthOf(wrapper.find(".card-preview-image"), 0);
});
@ -68,7 +76,7 @@ describe("<Card>", () => {
const link = Object.assign({}, DEFAULT_PROPS.link);
link.contextMenuOptions = ["CheckBookmark"];
wrapper = mountWithIntl(<Card {...Object.assign({}, DEFAULT_PROPS, {link})} />);
wrapper = mountCardWithProps(Object.assign({}, DEFAULT_PROPS, {link}));
wrapper.find(".context-menu-button").simulate("click", {preventDefault: () => {}});
const {options} = wrapper.find(LinkMenu).props();
assert.equal(options, link.contextMenuOptions);
@ -103,13 +111,6 @@ describe("<Card>", () => {
button.simulate("click", {preventDefault: () => {}});
assert.isTrue(wrapper.find(".card-outer").hasClass("active"));
});
it("should have a loaded preview image when the image is loaded", () => {
assert.isFalse(wrapper.find(".card-preview-image").hasClass("loaded"));
wrapper.setState({imageLoaded: true});
assert.isTrue(wrapper.find(".card-preview-image").hasClass("loaded"));
});
describe("image loading", () => {
let link;
let triggerImage = {};
@ -123,7 +124,14 @@ describe("<Card>", () => {
link = Object.assign({}, DEFAULT_PROPS.link);
link.image += uniqueLink++;
wrapper = mountWithIntl(<Card {...Object.assign({}, DEFAULT_PROPS, {link})} />);
wrapper = shallow(<Card {...DEFAULT_PROPS} link={link} />);
});
it("should have a loaded preview image when the image is loaded", () => {
assert.isFalse(wrapper.find(".card-preview-image").hasClass("loaded"));
wrapper.setState({imageLoaded: true});
assert.isTrue(wrapper.find(".card-preview-image").hasClass("loaded"));
});
it("should start not loaded", () => {
assert.isFalse(wrapper.state("imageLoaded"));
@ -196,7 +204,7 @@ describe("<Card>", () => {
}));
});
it("should notify Web Extensions with WEBEXT_CLICK if props.isWebExtension is true", () => {
wrapper = mountWithIntl(<Card {...DEFAULT_PROPS} isWebExtension={true} eventSource={"MyExtension"} index={3} />);
wrapper = mountCardWithProps(Object.assign({}, DEFAULT_PROPS, {isWebExtension: true, eventSource: "MyExtension", index: 3}));
const card = wrapper.find(".card");
const event = {preventDefault() {}};
card.simulate("click", event);

Просмотреть файл

@ -39,7 +39,7 @@ describe("<LinkMenu>", () => {
}
});
it("should show the correct options for default sites", () => {
wrapper = shallowWithIntl(<LinkMenu site={{url: "", isDefault: true}} options={["CheckBookmark"]} source={"TOP_SITES"} dispatch={() => {}} />);
wrapper = shallowWithIntl(<LinkMenu site={{url: "", isDefault: true}} options={["CheckBookmark"]} source={"TOP_SITES"} isPrivateBrowsingEnabled={true} dispatch={() => {}} />);
const {options} = wrapper.find(ContextMenu).props();
let i = 0;
assert.propertyVal(options[i++], "id", "menu_action_pin");
@ -157,7 +157,14 @@ describe("<LinkMenu>", () => {
menu_action_archive_pocket: {pocket_id: "1234"}
};
const {options} = shallowWithIntl(<LinkMenu site={FAKE_SITE} dispatch={dispatch} index={FAKE_INDEX} options={propOptions} source={FAKE_SOURCE} shouldSendImpressionStats={true} />)
const {options} = shallowWithIntl(<LinkMenu
site={FAKE_SITE}
dispatch={dispatch}
index={FAKE_INDEX}
isPrivateBrowsingEnabled={true}
options={propOptions}
source={FAKE_SOURCE}
shouldSendImpressionStats={true} />)
.find(ContextMenu).props();
afterEach(() => dispatch.reset());
options.filter(o => o.type !== "separator").forEach(option => {

Просмотреть файл

@ -1,4 +1,5 @@
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
import {GlobalOverrider} from "test/unit/utils";
import {PrefsFeed} from "lib/PrefsFeed.jsm";
import {PrerenderData} from "common/PrerenderData.jsm";
const {initialPrefs} = PrerenderData;
@ -6,6 +7,8 @@ const {initialPrefs} = PrerenderData;
const PRERENDER_PREF_NAME = "prerender";
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
let overrider = new GlobalOverrider();
describe("PrefsFeed", () => {
let feed;
let FAKE_PREFS;
@ -21,16 +24,23 @@ describe("PrefsFeed", () => {
ignore: sinon.spy(),
ignoreBranch: sinon.spy()
};
overrider.set({PrivateBrowsingUtils: {enabled: true}});
});
afterEach(() => {
overrider.restore();
});
it("should set a pref when a SET_PREF action is received", () => {
feed.onAction(ac.SetPref("foo", 2));
assert.calledWith(feed._prefs.set, "foo", 2);
});
it("should dispatch PREFS_INITIAL_VALUES on init", () => {
it("should dispatch PREFS_INITIAL_VALUES on init with pref values and .isPrivateBrowsingEnabled", () => {
feed.onAction({type: at.INIT});
assert.calledOnce(feed.store.dispatch);
assert.equal(feed.store.dispatch.firstCall.args[0].type, at.PREFS_INITIAL_VALUES);
assert.deepEqual(feed.store.dispatch.firstCall.args[0].data, {foo: 1, bar: 2});
const [{data}] = feed.store.dispatch.firstCall.args;
assert.equal(data.foo, 1);
assert.equal(data.bar, 2);
assert.isTrue(data.isPrivateBrowsingEnabled);
});
it("should add one branch observer on init", () => {
feed.onAction({type: at.INIT});