mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-08 20:28:42 +02:00
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
289 lines
11 KiB
JavaScript
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": {}});
|
|
});
|
|
});
|
|
});
|