Source code

Revision control

Copy as Markdown

Other Tools

/* global Services */
import {
AboutPreferences,
PREFERENCES_LOADED_EVENT,
} from "lib/AboutPreferences.sys.mjs";
import { actionTypes as at, actionCreators as ac } from "common/Actions.mjs";
import { GlobalOverrider } from "test/unit/utils";
describe("AboutPreferences Feed", () => {
let globals;
let sandbox;
let Sections;
let DiscoveryStream;
let instance;
beforeEach(() => {
globals = new GlobalOverrider();
sandbox = globals.sandbox;
Sections = [];
DiscoveryStream = { config: { enabled: false } };
instance = new AboutPreferences();
instance.store = {
dispatch: sandbox.stub(),
getState: () => ({ Sections, DiscoveryStream }),
};
globals.set("NimbusFeatures", {
newtab: { getAllVariables: sandbox.stub() },
});
});
afterEach(() => {
globals.restore();
});
describe("#onAction", () => {
it("should call .init() on an INIT action", () => {
const stub = sandbox.stub(instance, "init");
instance.onAction({ type: at.INIT });
assert.calledOnce(stub);
});
it("should call .uninit() on an UNINIT action", () => {
const stub = sandbox.stub(instance, "uninit");
instance.onAction({ type: at.UNINIT });
assert.calledOnce(stub);
});
it("should call .openPreferences on SETTINGS_OPEN", () => {
const action = {
type: at.SETTINGS_OPEN,
_target: { browser: { ownerGlobal: { openPreferences: sinon.spy() } } },
};
instance.onAction(action);
assert.calledOnce(action._target.browser.ownerGlobal.openPreferences);
});
it("should call .BrowserAddonUI.openAddonsMgr with the extension id on OPEN_WEBEXT_SETTINGS", () => {
const action = {
type: at.OPEN_WEBEXT_SETTINGS,
data: "foo",
_target: {
browser: {
ownerGlobal: {
BrowserAddonUI: { openAddonsMgr: sinon.spy() },
},
},
},
};
instance.onAction(action);
assert.calledWith(
action._target.browser.ownerGlobal.BrowserAddonUI.openAddonsMgr,
);
});
});
describe("#observe", () => {
it("should watch for about:preferences loading", () => {
sandbox.stub(Services.obs, "addObserver");
instance.init();
assert.calledOnce(Services.obs.addObserver);
assert.calledWith(
Services.obs.addObserver,
instance,
PREFERENCES_LOADED_EVENT
);
});
it("should stop watching on uninit", () => {
sandbox.stub(Services.obs, "removeObserver");
instance.uninit();
assert.calledOnce(Services.obs.removeObserver);
assert.calledWith(
Services.obs.removeObserver,
instance,
PREFERENCES_LOADED_EVENT
);
});
it("should try to render on event", async () => {
const stub = sandbox.stub(instance, "renderPreferences");
Sections.push({});
await instance.observe(window, PREFERENCES_LOADED_EVENT);
assert.calledOnce(stub);
assert.equal(stub.firstCall.args[0], window);
assert.include(stub.firstCall.args[1], Sections[0]);
});
it("Hide topstories rows select in sections if discovery stream is enabled", async () => {
const stub = sandbox.stub(instance, "renderPreferences");
Sections.push({
rowsPref: "row_pref",
maxRows: 3,
pref: { descString: "foo" },
learnMore: { link: "https://foo.com" },
id: "topstories",
});
DiscoveryStream = { config: { enabled: true } };
await instance.observe(window, PREFERENCES_LOADED_EVENT);
assert.calledOnce(stub);
const [, structure] = stub.firstCall.args;
assert.equal(structure[0].id, "search");
assert.equal(structure[1].id, "topsites");
assert.equal(structure[2].id, "topstories");
assert.isEmpty(structure[2].rowsPref);
});
});
describe("#renderPreferences", () => {
let node;
let prefStructure;
let Preferences;
let gHomePane;
const testRender = () =>
instance.renderPreferences(
{
document: {
createXULElement: sandbox.stub().returns(node),
l10n: {
setAttributes(el, id, args) {
el.setAttribute("data-l10n-id", id);
el.setAttribute("data-l10n-args", JSON.stringify(args));
},
},
createProcessingInstruction: sandbox.stub(),
createElementNS: sandbox.stub().callsFake(() => node),
getElementById: sandbox.stub().returns(node),
insertBefore: sandbox.stub().returnsArg(0),
querySelector: sandbox
.stub()
.returns({ appendChild: sandbox.stub() }),
},
Preferences,
gHomePane,
},
prefStructure,
DiscoveryStream.config
);
beforeEach(() => {
node = {
appendChild: sandbox.stub().returnsArg(0),
addEventListener: sandbox.stub(),
classList: { add: sandbox.stub(), remove: sandbox.stub() },
cloneNode: sandbox.stub().returnsThis(),
insertAdjacentElement: sandbox.stub().returnsArg(1),
setAttribute: sandbox.stub(),
remove: sandbox.stub(),
style: {},
};
prefStructure = [];
Preferences = {
add: sandbox.stub(),
get: sandbox.stub().returns({
on: sandbox.stub(),
}),
};
gHomePane = { toggleRestoreDefaultsBtn: sandbox.stub() };
});
describe("#getString", () => {
it("should not fail if titleString is not provided", () => {
prefStructure = [{ pref: {} }];
testRender();
assert.calledWith(
node.setAttribute,
"data-l10n-id",
sinon.match.typeOf("undefined")
);
});
it("should return the string id if titleString is just a string", () => {
const titleString = "foo";
prefStructure = [{ pref: { titleString } }];
testRender();
assert.calledWith(node.setAttribute, "data-l10n-id", titleString);
});
it("should set id and args if titleString is an object with id and values", () => {
const titleString = { id: "foo", values: { provider: "bar" } };
prefStructure = [{ pref: { titleString } }];
testRender();
assert.calledWith(node.setAttribute, "data-l10n-id", titleString.id);
assert.calledWith(
node.setAttribute,
"data-l10n-args",
JSON.stringify(titleString.values)
);
});
});
describe("#linkPref", () => {
it("should add a pref to the global", () => {
prefStructure = [{ pref: { feed: "feed" } }];
testRender();
assert.calledOnce(Preferences.add);
});
it("should skip adding if not shown", () => {
prefStructure = [{ shouldHidePref: true }];
testRender();
assert.notCalled(Preferences.add);
});
});
describe("pref icon", () => {
it("should default to webextension icon", () => {
prefStructure = [{ pref: { feed: "feed" } }];
testRender();
assert.calledWith(
node.setAttribute,
"src",
);
});
it("should use desired glyph icon", () => {
prefStructure = [{ icon: "mail", pref: { feed: "feed" } }];
testRender();
assert.calledWith(
node.setAttribute,
"src",
);
});
it("should use specified chrome icon", () => {
const icon = "chrome://the/icon.svg";
prefStructure = [{ icon, pref: { feed: "feed" } }];
testRender();
assert.calledWith(node.setAttribute, "src", icon);
});
});
describe("title line", () => {
it("should render a title", () => {
const titleString = "the_title";
prefStructure = [{ pref: { titleString } }];
testRender();
assert.calledWith(node.setAttribute, "data-l10n-id", titleString);
});
});
describe("top stories", () => {
const href = "https://disclaimer/";
const eventSource = "https://disclaimer/";
beforeEach(() => {
prefStructure = [
{
id: "topstories",
pref: { feed: "feed", learnMore: { link: { href } } },
eventSource,
},
];
});
it("should add a link for top stories", () => {
testRender();
assert.calledWith(node.setAttribute, "href", href);
});
it("should setup a user event for top stories eventSource", () => {
sinon.spy(instance, "setupUserEvent");
testRender();
assert.calledWith(node.addEventListener, "command");
assert.calledWith(instance.setupUserEvent, node, eventSource);
});
it("should setup a user event for top stories nested pref eventSource", () => {
sinon.spy(instance, "setupUserEvent");
prefStructure = [
{
id: "topstories",
pref: {
feed: "feed",
learnMore: { link: { href } },
nestedPrefs: [
{
name: "showSponsored",
titleString:
"home-prefs-recommended-by-option-sponsored-stories",
icon: "icon-info",
eventSource: "POCKET_SPOCS",
},
],
},
},
];
testRender();
assert.calledWith(node.addEventListener, "command");
assert.calledWith(instance.setupUserEvent, node, "POCKET_SPOCS");
});
it("should fire store dispatch with onCommand", () => {
const element = {
addEventListener: (command, action) => {
// Trigger the action right away because we only care about testing the action here.
action({ target: { checked: true } });
},
};
instance.setupUserEvent(element, eventSource);
assert.calledWith(
instance.store.dispatch,
ac.UserEvent({
event: "PREF_CHANGED",
source: eventSource,
value: { menu_source: "ABOUT_PREFERENCES", status: true },
})
);
});
});
describe("description line", () => {
it("should render a description", () => {
const descString = "the_desc";
prefStructure = [{ pref: { descString } }];
testRender();
assert.calledWith(node.setAttribute, "data-l10n-id", descString);
});
it("should render rows dropdown with appropriate number", () => {
prefStructure = [
{ rowsPref: "row_pref", maxRows: 3, pref: { descString: "foo" } },
];
testRender();
assert.calledWith(node.setAttribute, "value", 1);
assert.calledWith(node.setAttribute, "value", 2);
assert.calledWith(node.setAttribute, "value", 3);
});
});
describe("nested prefs", () => {
const titleString = "im_nested";
beforeEach(() => {
prefStructure = [{ pref: { nestedPrefs: [{ titleString }] } }];
});
it("should render a nested pref", () => {
testRender();
assert.calledWith(node.setAttribute, "data-l10n-id", titleString);
});
it("should set node hidden to true", () => {
prefStructure[0].pref.nestedPrefs[0].hidden = true;
testRender();
assert.isTrue(node.hidden);
});
it("should add a change event", () => {
testRender();
assert.calledOnce(Preferences.get().on);
assert.calledWith(Preferences.get().on, "change");
});
it("should default node disabled to false", async () => {
Preferences.get = sandbox.stub().returns({
on: sandbox.stub(),
_value: true,
});
testRender();
assert.isFalse(node.disabled);
});
it("should default node disabled to true", async () => {
testRender();
assert.isTrue(node.disabled);
});
it("should set node disabled to true", async () => {
const pref = {
on: sandbox.stub(),
_value: true,
};
Preferences.get = sandbox.stub().returns(pref);
testRender();
pref._value = !pref._value;
await Preferences.get().on.firstCall.args[1]();
assert.isTrue(node.disabled);
});
it("should set node disabled to false", async () => {
const pref = {
on: sandbox.stub(),
_value: false,
};
Preferences.get = sandbox.stub().returns(pref);
testRender();
pref._value = !pref._value;
await Preferences.get().on.firstCall.args[1]();
assert.isFalse(node.disabled);
});
});
describe("restore defaults btn", () => {
it("should call toggleRestoreDefaultsBtn", () => {
testRender();
assert.calledOnce(gHomePane.toggleRestoreDefaultsBtn);
});
});
});
});