forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			280 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			280 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
const { ExperimentAPI } = ChromeUtils.import(
 | 
						|
  "resource://messaging-system/experiments/ExperimentAPI.jsm"
 | 
						|
);
 | 
						|
const { ExperimentFakes } = ChromeUtils.import(
 | 
						|
  "resource://testing-common/MSTestUtils.jsm"
 | 
						|
);
 | 
						|
const { FileTestUtils } = ChromeUtils.import(
 | 
						|
  "resource://testing-common/FileTestUtils.jsm"
 | 
						|
);
 | 
						|
const { TestUtils } = ChromeUtils.import(
 | 
						|
  "resource://testing-common/TestUtils.jsm"
 | 
						|
);
 | 
						|
 | 
						|
/**
 | 
						|
 * #getExperiment
 | 
						|
 */
 | 
						|
add_task(async function test_getExperiment_slug() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const manager = ExperimentFakes.manager();
 | 
						|
  const expected = ExperimentFakes.experiment("foo");
 | 
						|
 | 
						|
  await manager.onStartup();
 | 
						|
 | 
						|
  sandbox.stub(ExperimentAPI, "_store").get(() => ExperimentFakes.childStore());
 | 
						|
 | 
						|
  manager.store.addExperiment(expected);
 | 
						|
 | 
						|
  // Wait to sync to child
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => ExperimentAPI.getExperiment({ slug: "foo" }),
 | 
						|
    "Wait for child to sync"
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.deepEqual(
 | 
						|
    ExperimentAPI.getExperiment({ slug: "foo" }),
 | 
						|
    expected,
 | 
						|
    "should return an experiment by slug"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_getExperiment_group() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const manager = ExperimentFakes.manager();
 | 
						|
  const expected = ExperimentFakes.experiment("foo", {
 | 
						|
    branch: { slug: "treatment", value: { title: "hi" }, groups: ["blue"] },
 | 
						|
  });
 | 
						|
 | 
						|
  await manager.onStartup();
 | 
						|
 | 
						|
  sandbox.stub(ExperimentAPI, "_store").get(() => ExperimentFakes.childStore());
 | 
						|
 | 
						|
  manager.store.addExperiment(expected);
 | 
						|
 | 
						|
  // Wait to sync to child
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => ExperimentAPI.getExperiment({ group: "blue" }),
 | 
						|
    "Wait for child to sync"
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.deepEqual(
 | 
						|
    ExperimentAPI.getExperiment({ group: "blue" }),
 | 
						|
    expected,
 | 
						|
    "should return an experiment by slug"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * #getValue
 | 
						|
 */
 | 
						|
add_task(async function test_getValue() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const manager = ExperimentFakes.manager();
 | 
						|
  const value = { title: "hi" };
 | 
						|
  const expected = ExperimentFakes.experiment("foo", {
 | 
						|
    branch: { slug: "treatment", value },
 | 
						|
  });
 | 
						|
 | 
						|
  await manager.onStartup();
 | 
						|
 | 
						|
  sandbox.stub(ExperimentAPI, "_store").get(() => ExperimentFakes.childStore());
 | 
						|
 | 
						|
  manager.store.addExperiment(expected);
 | 
						|
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => ExperimentAPI.getExperiment({ slug: "foo" }),
 | 
						|
    "Wait for child to sync"
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.deepEqual(
 | 
						|
    ExperimentAPI.getValue({ slug: "foo" }),
 | 
						|
    value,
 | 
						|
    "should return an experiment value by slug"
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.equal(
 | 
						|
    ExperimentAPI.getValue({ slug: "doesnotexist" }),
 | 
						|
    undefined,
 | 
						|
    "should return undefined if the experiment is not found"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * #getRecipe
 | 
						|
 */
 | 
						|
add_task(async function test_getRecipe() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const RECIPE = {
 | 
						|
    arguments: ExperimentFakes.recipe("foo"),
 | 
						|
  };
 | 
						|
  sandbox.stub(ExperimentAPI._remoteSettingsClient, "get").resolves([RECIPE]);
 | 
						|
 | 
						|
  const recipe = await ExperimentAPI.getRecipe("foo");
 | 
						|
  Assert.deepEqual(
 | 
						|
    recipe,
 | 
						|
    RECIPE,
 | 
						|
    "should return an experiment recipe if found"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_getRecipe_Failure() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  sandbox.stub(ExperimentAPI._remoteSettingsClient, "get").throws();
 | 
						|
 | 
						|
  const recipe = await ExperimentAPI.getRecipe("foo");
 | 
						|
  Assert.equal(recipe, undefined, "should return undefined if RS throws");
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * #getAllBranches
 | 
						|
 */
 | 
						|
add_task(async function test_getAllBranches() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const RECIPE = {
 | 
						|
    arguments: ExperimentFakes.recipe("foo"),
 | 
						|
  };
 | 
						|
  sandbox.stub(ExperimentAPI._remoteSettingsClient, "get").resolves([RECIPE]);
 | 
						|
 | 
						|
  const branches = await ExperimentAPI.getAllBranches("foo");
 | 
						|
  Assert.deepEqual(
 | 
						|
    branches,
 | 
						|
    RECIPE.arguments.branches,
 | 
						|
    "should return all branches if found a recipe"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_getAllBranches_Failure() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  sandbox.stub(ExperimentAPI._remoteSettingsClient, "get").throws();
 | 
						|
 | 
						|
  const branches = await ExperimentAPI.getAllBranches("foo");
 | 
						|
  Assert.equal(branches, undefined, "should return undefined if RS throws");
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * #on
 | 
						|
 * #off
 | 
						|
 */
 | 
						|
add_task(async function test_event_updates_content() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const manager = ExperimentFakes.manager();
 | 
						|
  const expected = ExperimentFakes.experiment("foo");
 | 
						|
  const updateEventCbStub = sandbox.stub();
 | 
						|
 | 
						|
  // Setup ExperimentManager and child store for ExperimentAPI
 | 
						|
  await manager.onStartup();
 | 
						|
  sandbox.stub(ExperimentAPI, "_store").get(() => ExperimentFakes.childStore());
 | 
						|
 | 
						|
  // Set update cb
 | 
						|
  ExperimentAPI.on("update:foo", updateEventCbStub);
 | 
						|
 | 
						|
  // Add some data
 | 
						|
  manager.store.addExperiment(expected);
 | 
						|
 | 
						|
  // Wait to sync
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => ExperimentAPI.getExperiment({ slug: "foo" }),
 | 
						|
    "Wait for child to sync"
 | 
						|
  );
 | 
						|
 | 
						|
  let baselineCallCount = updateEventCbStub.callCount;
 | 
						|
 | 
						|
  // Trigger an update
 | 
						|
  manager.store.updateExperiment("foo", { active: false });
 | 
						|
 | 
						|
  // Wait for update to child store
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => updateEventCbStub.callCount === baselineCallCount + 1,
 | 
						|
    "An `update` event was not sent"
 | 
						|
  );
 | 
						|
 | 
						|
  // Remove the update listener
 | 
						|
  ExperimentAPI.off("update:foo", updateEventCbStub);
 | 
						|
  // Trigger another change
 | 
						|
  manager.store.updateExperiment("foo", { active: true });
 | 
						|
 | 
						|
  const [, cbExperimentValue] = updateEventCbStub.firstCall.args;
 | 
						|
 | 
						|
  Assert.deepEqual(
 | 
						|
    expected.slug,
 | 
						|
    cbExperimentValue.slug,
 | 
						|
    "should return the updated experiment"
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.equal(
 | 
						|
    updateEventCbStub.callCount,
 | 
						|
    baselineCallCount + 1,
 | 
						|
    "Should only have seen 1 update"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * #on
 | 
						|
 * #off
 | 
						|
 */
 | 
						|
add_task(async function test_event_updates_main() {
 | 
						|
  const sandbox = sinon.createSandbox();
 | 
						|
  const manager = ExperimentFakes.manager();
 | 
						|
  const expected = ExperimentFakes.experiment("foo");
 | 
						|
  const updateEventCbStub = sandbox.stub();
 | 
						|
 | 
						|
  // Setup ExperimentManager and child store for ExperimentAPI
 | 
						|
  await manager.onStartup();
 | 
						|
  sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
 | 
						|
 | 
						|
  // Set update cb
 | 
						|
  ExperimentAPI.on("update:foo", updateEventCbStub);
 | 
						|
 | 
						|
  // Add some data
 | 
						|
  manager.store.addExperiment(expected);
 | 
						|
 | 
						|
  let baselineCallCount = updateEventCbStub.callCount;
 | 
						|
 | 
						|
  // Trigger an update
 | 
						|
  manager.store.updateExperiment("foo", { active: false });
 | 
						|
 | 
						|
  // Wait for update to child store
 | 
						|
  await TestUtils.waitForCondition(
 | 
						|
    () => updateEventCbStub.callCount === baselineCallCount + 1,
 | 
						|
    "An `update` event was not sent"
 | 
						|
  );
 | 
						|
 | 
						|
  // Remove the update listener
 | 
						|
  ExperimentAPI.off("update:foo", updateEventCbStub);
 | 
						|
  // Trigger another change
 | 
						|
  manager.store.updateExperiment("foo", { active: true });
 | 
						|
 | 
						|
  const [, cbExperimentValue] = updateEventCbStub.firstCall.args;
 | 
						|
 | 
						|
  Assert.deepEqual(
 | 
						|
    expected.slug,
 | 
						|
    cbExperimentValue.slug,
 | 
						|
    "should return the updated experiment"
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.equal(
 | 
						|
    updateEventCbStub.callCount,
 | 
						|
    baselineCallCount + 1,
 | 
						|
    "Should only have seen 1 update"
 | 
						|
  );
 | 
						|
 | 
						|
  sandbox.restore();
 | 
						|
});
 |