gecko-dev/browser/components/newtab/test/unit/asrouter/MessageLoaderUtils.test.js
k88hudson e8e8efbf45 Bug 1496457 - Add Newsletter template, addon install telemetry, remove legacy onboarding code, and bug fixes to Activity Stream r=Mardak
Differential Revision: https://phabricator.services.mozilla.com/D7916

--HG--
rename : browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json => browser/components/newtab/content-src/asrouter/templates/NewsletterSnippet/NewsletterSnippet.schema.json
extra : moz-landing-system : lando
2018-10-05 19:16:25 +00:00

289 lines
11 KiB
JavaScript

import {GlobalOverrider} from "test/unit/utils";
import {MessageLoaderUtils} from "lib/ASRouter.jsm";
const {STARTPAGE_VERSION} = MessageLoaderUtils;
const FAKE_STORAGE = {
set() {
return Promise.resolve();
},
get() { return Promise.resolve(); },
};
const FAKE_RESPONSE_HEADERS = {get() {}};
describe("MessageLoaderUtils", () => {
let fetchStub;
let clock;
beforeEach(() => {
clock = sinon.useFakeTimers();
fetchStub = sinon.stub(global, "fetch");
});
afterEach(() => {
clock.restore();
fetchStub.restore();
});
describe("#loadMessagesForProvider", () => {
it("should return messages for a local provider with hardcoded messages", async () => {
const sourceMessage = {id: "foo"};
const provider = {id: "provider123", type: "local", messages: [sourceMessage]};
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.isArray(result.messages);
// Does the message have the right properties?
const [message] = result.messages;
assert.propertyVal(message, "id", "foo");
assert.propertyVal(message, "provider", "provider123");
});
it("should return messages for remote provider", async () => {
const sourceMessage = {id: "foo"};
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve({messages: [sourceMessage]}), headers: FAKE_RESPONSE_HEADERS});
const provider = {id: "provider123", type: "remote", url: "https://foo.com"};
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.isArray(result.messages);
// Does the message have the right properties?
const [message] = result.messages;
assert.propertyVal(message, "id", "foo");
assert.propertyVal(message, "provider", "provider123");
assert.propertyVal(message, "provider_url", "https://foo.com");
});
describe("remote provider HTTP codes", () => {
const testMessage = {id: "foo"};
const provider = {id: "provider123", type: "remote", url: "https://foo.com", updateCycleInMs: 300};
const respJson = {messages: [testMessage]};
function assertReturnsCorrectMessages(actual) {
assert.isArray(actual.messages);
// Does the message have the right properties?
const [message] = actual.messages;
assert.propertyVal(message, "id", testMessage.id);
assert.propertyVal(message, "provider", provider.id);
assert.propertyVal(message, "provider_url", provider.url);
}
it("should return messages for 200 response", async () => {
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve(respJson), headers: FAKE_RESPONSE_HEADERS});
assertReturnsCorrectMessages(await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE));
});
it("should return messages for a 302 response with json", async () => {
fetchStub.resolves({ok: false, status: 302, json: () => Promise.resolve(respJson), headers: FAKE_RESPONSE_HEADERS});
assertReturnsCorrectMessages(await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE));
});
it("should return an empty array for a 204 response", async () => {
fetchStub.resolves({ok: true, status: 204, json: () => "", headers: FAKE_RESPONSE_HEADERS});
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.deepEqual(result.messages, []);
});
it("should return an empty array for a 500 response", async () => {
fetchStub.resolves({ok: false, status: 500, json: () => "", headers: FAKE_RESPONSE_HEADERS});
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.deepEqual(result.messages, []);
});
it("should return cached messages for a 304 response", async () => {
clock.tick(302);
const messages = [{id: "message-1"}, {id: "message-2"}];
const fakeStorage = {
set() {
return Promise.resolve();
},
get() {
return Promise.resolve({
[provider.id]: {
version: STARTPAGE_VERSION,
url: provider.url,
messages,
etag: "etag0987654321",
lastFetched: 1,
},
});
},
};
fetchStub.resolves({ok: true, status: 304, json: () => "", headers: FAKE_RESPONSE_HEADERS});
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, fakeStorage);
assert.equal(result.messages.length, messages.length);
messages.forEach(message => {
assert.ok(result.messages.find(m => m.id === message.id));
});
});
it("should return an empty array if json doesn't parse properly", async () => {
fetchStub.resolves({ok: false, status: 200, json: () => "", headers: FAKE_RESPONSE_HEADERS});
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.deepEqual(result.messages, []);
});
it("should return an empty array if the request rejects", async () => {
fetchStub.rejects(new Error("something went wrong"));
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.deepEqual(result.messages, []);
});
});
describe("remote provider caching", () => {
const provider = {id: "provider123", type: "remote", url: "https://foo.com", updateCycleInMs: 300};
it("should return cached results if they aren't expired", async () => {
clock.tick(1);
const messages = [{id: "message-1"}, {id: "message-2"}];
const fakeStorage = {
set() { return Promise.resolve(); },
get() {
return Promise.resolve({
[provider.id]: {
version: STARTPAGE_VERSION,
url: provider.url,
messages,
etag: "etag0987654321",
lastFetched: Date.now(),
},
});
},
};
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, fakeStorage);
assert.equal(result.messages.length, messages.length);
messages.forEach(message => {
assert.ok(result.messages.find(m => m.id === message.id));
});
});
it("should return fetch results if the cache messages are expired", async () => {
clock.tick(302);
const testMessage = {id: "foo"};
const respJson = {messages: [testMessage]};
const fakeStorage = {
set() { return Promise.resolve(); },
get() {
return Promise.resolve({
[provider.id]: {
version: STARTPAGE_VERSION,
url: provider.url,
messages: [{id: "message-1"}, {id: "message-2"}],
etag: "etag0987654321",
lastFetched: 1,
},
});
},
};
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve(respJson), headers: FAKE_RESPONSE_HEADERS});
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, fakeStorage);
assert.equal(result.messages.length, 1);
assert.equal(result.messages[0].id, testMessage.id);
});
});
it("should return an empty array for a remote provider with a blank URL without attempting a request", async () => {
const provider = {id: "provider123", type: "remote", url: ""};
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.notCalled(fetchStub);
assert.deepEqual(result.messages, []);
});
it("should return .lastUpdated with the time at which the messages were fetched", async () => {
const sourceMessage = {id: "foo"};
const provider = {
id: "provider123",
type: "remote",
url: "foo.com",
};
fetchStub.resolves({
ok: true,
status: 200,
json: () => new Promise(resolve => {
clock.tick(42);
resolve({messages: [sourceMessage]});
}),
headers: FAKE_RESPONSE_HEADERS,
});
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
assert.propertyVal(result, "lastUpdated", 42);
});
});
describe("#shouldProviderUpdate", () => {
it("should return true if the provider does not had a .lastUpdated property", () => {
assert.isTrue(MessageLoaderUtils.shouldProviderUpdate({id: "foo"}));
});
it("should return false if the provider does not had a .updateCycleInMs property and has a .lastUpdated", () => {
clock.tick(1);
assert.isFalse(MessageLoaderUtils.shouldProviderUpdate({id: "foo", lastUpdated: 0}));
});
it("should return true if the time since .lastUpdated is greater than .updateCycleInMs", () => {
clock.tick(301);
assert.isTrue(MessageLoaderUtils.shouldProviderUpdate({id: "foo", lastUpdated: 0, updateCycleInMs: 300}));
});
it("should return false if the time since .lastUpdated is less than .updateCycleInMs", () => {
clock.tick(299);
assert.isFalse(MessageLoaderUtils.shouldProviderUpdate({id: "foo", lastUpdated: 0, updateCycleInMs: 300}));
});
});
describe("#installAddonFromURL", () => {
let globals;
let sandbox;
let getInstallStub;
let installAddonStub;
beforeEach(() => {
globals = new GlobalOverrider();
sandbox = sinon.sandbox.create();
getInstallStub = sandbox.stub();
installAddonStub = sandbox.stub();
globals.set("AddonManager", {
getInstallForURL: getInstallStub,
installAddonFromWebpage: installAddonStub,
});
});
afterEach(() => {
sandbox.restore();
globals.restore();
});
it("should call the Addons API when passed a valid URL", async () => {
getInstallStub.resolves(null);
installAddonStub.resolves(null);
await MessageLoaderUtils.installAddonFromURL({}, "foo.com");
assert.calledOnce(getInstallStub);
assert.calledOnce(installAddonStub);
// Verify that the expected installation source has been passed to the getInstallForURL
// method (See Bug 1496167 for a rationale).
assert.calledWithExactly(getInstallStub, "foo.com", "application/x-xpinstall", null,
null, null, null, null, {source: "activitystream"});
});
it("should not call the Addons API on invalid URLs", async () => {
sandbox.stub(global.Services.scriptSecurityManager, "getSystemPrincipal").throws();
await MessageLoaderUtils.installAddonFromURL({}, "https://foo.com");
assert.notCalled(getInstallStub);
assert.notCalled(installAddonStub);
});
});
describe("#cleanupCache", () => {
it("should remove data for providers no longer active", async () => {
const fakeStorage = {
get: sinon.stub().returns(Promise.resolve({
"id-1": {},
"id-2": {},
"id-3": {},
})),
set: sinon.stub().returns(Promise.resolve()),
};
const fakeProviders = [{id: "id-1", type: "remote"}, {id: "id-3", type: "remote"}];
await MessageLoaderUtils.cleanupCache(fakeProviders, fakeStorage);
assert.calledOnce(fakeStorage.set);
assert.calledWith(fakeStorage.set, MessageLoaderUtils.REMOTE_LOADER_CACHE_KEY, {"id-1": {}, "id-3": {}});
});
});
});