forked from mirrors/gecko-dev
MozReview-Commit-ID: 8BVWPm810jk Differential Revision: https://phabricator.services.mozilla.com/D53415 --HG-- extra : moz-landing-system : lando
308 lines
8.2 KiB
JavaScript
308 lines
8.2 KiB
JavaScript
import {
|
|
ASRouterTargeting,
|
|
CachedTargetingGetter,
|
|
} from "lib/ASRouterTargeting.jsm";
|
|
import { OnboardingMessageProvider } from "lib/OnboardingMessageProvider.jsm";
|
|
|
|
// Note that tests for the ASRouterTargeting environment can be found in
|
|
// test/functional/mochitest/browser_asrouter_targeting.js
|
|
|
|
describe("#CachedTargetingGetter", () => {
|
|
const sixHours = 6 * 60 * 60 * 1000;
|
|
let sandbox;
|
|
let clock;
|
|
let frecentStub;
|
|
let topsitesCache;
|
|
beforeEach(() => {
|
|
sandbox = sinon.createSandbox();
|
|
clock = sinon.useFakeTimers();
|
|
frecentStub = sandbox.stub(
|
|
global.NewTabUtils.activityStreamProvider,
|
|
"getTopFrecentSites"
|
|
);
|
|
sandbox.stub(global.Cu, "reportError");
|
|
topsitesCache = new CachedTargetingGetter("getTopFrecentSites");
|
|
});
|
|
|
|
afterEach(() => {
|
|
sandbox.restore();
|
|
clock.restore();
|
|
});
|
|
|
|
it("should only make a request every 6 hours", async () => {
|
|
frecentStub.resolves();
|
|
clock.tick(sixHours);
|
|
|
|
await topsitesCache.get();
|
|
await topsitesCache.get();
|
|
|
|
assert.calledOnce(
|
|
global.NewTabUtils.activityStreamProvider.getTopFrecentSites
|
|
);
|
|
|
|
clock.tick(sixHours);
|
|
|
|
await topsitesCache.get();
|
|
|
|
assert.calledTwice(
|
|
global.NewTabUtils.activityStreamProvider.getTopFrecentSites
|
|
);
|
|
});
|
|
it("throws when failing getter", async () => {
|
|
frecentStub.rejects(new Error("fake error"));
|
|
clock.tick(sixHours);
|
|
|
|
// assert.throws expect a function as the first parameter, try/catch is a
|
|
// workaround
|
|
let rejected = false;
|
|
try {
|
|
await topsitesCache.get();
|
|
} catch (e) {
|
|
rejected = true;
|
|
}
|
|
|
|
assert(rejected);
|
|
});
|
|
it("should check targeted message before message without targeting", async () => {
|
|
const messages = await OnboardingMessageProvider.getUntranslatedMessages();
|
|
const stub = sandbox
|
|
.stub(ASRouterTargeting, "checkMessageTargeting")
|
|
.resolves();
|
|
const context = {
|
|
attributionData: {
|
|
campaign: "non-fx-button",
|
|
source: "addons.mozilla.org",
|
|
},
|
|
};
|
|
await ASRouterTargeting.findMatchingMessage({
|
|
messages,
|
|
trigger: { id: "firstRun" },
|
|
context,
|
|
});
|
|
|
|
const messageCount = messages.filter(
|
|
message => message.trigger && message.trigger.id === "firstRun"
|
|
).length;
|
|
|
|
assert.equal(stub.callCount, messageCount);
|
|
const calls = stub.getCalls().map(call => call.args[0]);
|
|
const lastCall = calls[calls.length - 1];
|
|
assert.equal(lastCall.id, "TRAILHEAD_1");
|
|
});
|
|
describe("sortMessagesByPriority", () => {
|
|
it("should sort messages in descending priority order", async () => {
|
|
const [
|
|
m1,
|
|
m2,
|
|
m3,
|
|
] = await OnboardingMessageProvider.getUntranslatedMessages();
|
|
const checkMessageTargetingStub = sandbox
|
|
.stub(ASRouterTargeting, "checkMessageTargeting")
|
|
.resolves(false);
|
|
sandbox.stub(ASRouterTargeting, "isTriggerMatch").resolves(true);
|
|
|
|
await ASRouterTargeting.findMatchingMessage({
|
|
messages: [
|
|
{ ...m1, priority: 0 },
|
|
{ ...m2, priority: 1 },
|
|
{ ...m3, priority: 2 },
|
|
],
|
|
trigger: "testing",
|
|
});
|
|
|
|
assert.equal(checkMessageTargetingStub.callCount, 3);
|
|
|
|
const [arg_m1] = checkMessageTargetingStub.firstCall.args;
|
|
assert.equal(arg_m1.id, m3.id);
|
|
|
|
const [arg_m2] = checkMessageTargetingStub.secondCall.args;
|
|
assert.equal(arg_m2.id, m2.id);
|
|
|
|
const [arg_m3] = checkMessageTargetingStub.thirdCall.args;
|
|
assert.equal(arg_m3.id, m1.id);
|
|
});
|
|
it("should sort messages with no priority last", async () => {
|
|
const [
|
|
m1,
|
|
m2,
|
|
m3,
|
|
] = await OnboardingMessageProvider.getUntranslatedMessages();
|
|
const checkMessageTargetingStub = sandbox
|
|
.stub(ASRouterTargeting, "checkMessageTargeting")
|
|
.resolves(false);
|
|
sandbox.stub(ASRouterTargeting, "isTriggerMatch").resolves(true);
|
|
|
|
await ASRouterTargeting.findMatchingMessage({
|
|
messages: [
|
|
{ ...m1, priority: 0 },
|
|
{ ...m2, priority: undefined },
|
|
{ ...m3, priority: 2 },
|
|
],
|
|
trigger: "testing",
|
|
});
|
|
|
|
assert.equal(checkMessageTargetingStub.callCount, 3);
|
|
|
|
const [arg_m1] = checkMessageTargetingStub.firstCall.args;
|
|
assert.equal(arg_m1.id, m3.id);
|
|
|
|
const [arg_m2] = checkMessageTargetingStub.secondCall.args;
|
|
assert.equal(arg_m2.id, m1.id);
|
|
|
|
const [arg_m3] = checkMessageTargetingStub.thirdCall.args;
|
|
assert.equal(arg_m3.id, m2.id);
|
|
});
|
|
it("should keep the order of messages with same priority unchanged", async () => {
|
|
const [
|
|
m1,
|
|
m2,
|
|
m3,
|
|
] = await OnboardingMessageProvider.getUntranslatedMessages();
|
|
const checkMessageTargetingStub = sandbox
|
|
.stub(ASRouterTargeting, "checkMessageTargeting")
|
|
.resolves(false);
|
|
sandbox.stub(ASRouterTargeting, "isTriggerMatch").resolves(true);
|
|
|
|
await ASRouterTargeting.findMatchingMessage({
|
|
messages: [
|
|
{ ...m1, priority: 2, targeting: undefined, rank: 1 },
|
|
{ ...m2, priority: undefined, targeting: undefined, rank: 1 },
|
|
{ ...m3, priority: 2, targeting: undefined, rank: 1 },
|
|
],
|
|
trigger: "testing",
|
|
});
|
|
|
|
assert.equal(checkMessageTargetingStub.callCount, 3);
|
|
|
|
const [arg_m1] = checkMessageTargetingStub.firstCall.args;
|
|
assert.equal(arg_m1.id, m1.id);
|
|
|
|
const [arg_m2] = checkMessageTargetingStub.secondCall.args;
|
|
assert.equal(arg_m2.id, m3.id);
|
|
|
|
const [arg_m3] = checkMessageTargetingStub.thirdCall.args;
|
|
assert.equal(arg_m3.id, m2.id);
|
|
});
|
|
});
|
|
describe("combineContexts", () => {
|
|
it("should combine the properties of the two objects", () => {
|
|
const joined = ASRouterTargeting.combineContexts(
|
|
{
|
|
get foo() {
|
|
return "foo";
|
|
},
|
|
},
|
|
{
|
|
get bar() {
|
|
return "bar";
|
|
},
|
|
}
|
|
);
|
|
assert.propertyVal(joined, "foo", "foo");
|
|
assert.propertyVal(joined, "bar", "bar");
|
|
});
|
|
it("should warn when properties overlap", () => {
|
|
ASRouterTargeting.combineContexts(
|
|
{
|
|
get foo() {
|
|
return "foo";
|
|
},
|
|
},
|
|
{
|
|
get foo() {
|
|
return "bar";
|
|
},
|
|
}
|
|
);
|
|
assert.calledOnce(global.Cu.reportError);
|
|
});
|
|
});
|
|
});
|
|
describe("ASRouterTargeting", () => {
|
|
let evalStub;
|
|
let sandbox;
|
|
let clock;
|
|
beforeEach(() => {
|
|
sandbox = sinon.createSandbox();
|
|
evalStub = sandbox.stub(global.FilterExpressions, "eval");
|
|
sandbox.replace(ASRouterTargeting, "Environment", {});
|
|
clock = sinon.useFakeTimers();
|
|
});
|
|
afterEach(() => {
|
|
clock.restore();
|
|
sandbox.restore();
|
|
});
|
|
it("should cache evaluation result", async () => {
|
|
evalStub.resolves(true);
|
|
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl1" },
|
|
{},
|
|
sandbox.stub(),
|
|
true
|
|
);
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl2" },
|
|
{},
|
|
sandbox.stub(),
|
|
true
|
|
);
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl1" },
|
|
{},
|
|
sandbox.stub(),
|
|
true
|
|
);
|
|
|
|
assert.calledTwice(evalStub);
|
|
});
|
|
it("should not cache evaluation result", async () => {
|
|
evalStub.resolves(true);
|
|
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl" },
|
|
{},
|
|
sandbox.stub(),
|
|
false
|
|
);
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl" },
|
|
{},
|
|
sandbox.stub(),
|
|
false
|
|
);
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl" },
|
|
{},
|
|
sandbox.stub(),
|
|
false
|
|
);
|
|
|
|
assert.calledThrice(evalStub);
|
|
});
|
|
it("should expire cache entries", async () => {
|
|
evalStub.resolves(true);
|
|
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl" },
|
|
{},
|
|
sandbox.stub(),
|
|
true
|
|
);
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl" },
|
|
{},
|
|
sandbox.stub(),
|
|
true
|
|
);
|
|
clock.tick(60 * 1000 + 1);
|
|
await ASRouterTargeting.checkMessageTargeting(
|
|
{ targeting: "jexl" },
|
|
{},
|
|
sandbox.stub(),
|
|
true
|
|
);
|
|
|
|
assert.calledTwice(evalStub);
|
|
});
|
|
});
|