-
Notifications
You must be signed in to change notification settings - Fork 54
/
test_FeatureGateImplementation.js
125 lines (104 loc) · 4.74 KB
/
test_FeatureGateImplementation.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
ChromeUtils.import("resource://featuregates/FeatureGate.jsm", this);
ChromeUtils.import("resource://featuregates/FeatureGateImplementation.jsm", this);
ChromeUtils.import("resource://testing-common/httpd.js", this);
const kDefinitionDefaults = {
id: "test-feature",
title: "Test Feature",
description: "A feature for testing",
restartRequired: false,
type: "boolean",
preference: "test.feature",
defaultValue: false,
isPublic: false,
};
function definitionFactory(override = {}) {
return Object.assign({}, kDefinitionDefaults, override);
}
class DefinitionServer {
constructor(definitionOverrides = []) {
this.server = new HttpServer();
this.server.registerPathHandler("/definitions.json", this);
this.definitions = {};
for (const override of definitionOverrides) {
this.addDefinition(override);
}
this.server.start();
registerCleanupFunction(() => new Promise(resolve => this.server.stop(resolve)));
}
// for nsIHttpRequestHandler
handle(request, response) {
// response.setHeader("Content-Type", "application/json");
response.write(JSON.stringify(this.definitions));
}
get definitionsUrl() {
const {primaryScheme, primaryHost, primaryPort} = this.server.identity;
return `${primaryScheme}://${primaryHost}:${primaryPort}/definitions.json`;
}
addDefinition(overrides = {}) {
const definition = definitionFactory(overrides);
// convert targeted values, used by fromId
definition.isPublic = {default: definition.isPublic};
definition.defaultValue = {default: definition.defaultValue};
this.definitions[definition.id] = definition;
return definition;
}
}
// getValue should work
add_task(async function testGetValue() {
const preference = "test.pref";
equal(
Services.prefs.getPrefType(preference),
Services.prefs.PREF_INVALID,
"Before creating the feature gate, the preference should not exist",
);
const feature = new FeatureGateImplementation(definitionFactory({ preference, defaultValue: false }));
equal(
Services.prefs.getBoolPref(preference),
false,
"Creating a preference should set its default value",
);
equal(await feature.getValue(), false, "getValue() should return the same value");
Services.prefs.setBoolPref(preference, true);
equal(await feature.getValue(), true, "getValue() should return the new value");
Services.prefs.setBoolPref(preference, false);
equal(await feature.getValue(), false, "getValue() should return the third value");
// cleanup
Services.prefs.getDefaultBranch("").deleteBranch(preference);
});
// event observers should work
add_task(async function testGetValue() {
const preference = "test.pref";
const feature = new FeatureGateImplementation(definitionFactory({ preference, defaultValue: false }));
const observer = {
onChange: sinon.stub(),
onEnable: sinon.stub(),
onDisable: sinon.stub(),
};
let rv = await feature.addObserver(observer);
equal(rv, false, "addObserver returns the current value");
Assert.deepEqual(observer.onChange.args, [], "onChange should not be called");
Assert.deepEqual(observer.onEnable.args, [], "onEnable should not be called");
Assert.deepEqual(observer.onDisable.args, [], "onDisable should not be called");
Services.prefs.setBoolPref(preference, true);
await Promise.resolve(); // Allow events to be called async
Assert.deepEqual(observer.onChange.args, [[true]], "onChange should be called with the new value");
Assert.deepEqual(observer.onEnable.args, [[]], "onEnable should be called");
Assert.deepEqual(observer.onDisable.args, [], "onDisable should not be called");
Services.prefs.setBoolPref(preference, false);
await Promise.resolve(); // Allow events to be called async
Assert.deepEqual(observer.onChange.args, [[true], [false]], "onChange should be called again with the new value");
Assert.deepEqual(observer.onEnable.args, [[]], "onEnable should not be called a second time");
Assert.deepEqual(observer.onDisable.args, [[]], "onDisable should be called for the first time");
Services.prefs.setBoolPref(preference, false);
await Promise.resolve(); // Allow events to be called async
Assert.deepEqual(observer.onChange.args, [[true], [false]], "onChange should not be called if the value did not change");
Assert.deepEqual(observer.onEnable.args, [[]], "onEnable should not be called again if the value did not change");
Assert.deepEqual(observer.onDisable.args, [[]], "onDisable should not be called if the value did not change");
// cleanup
feature.removeAllObservers();
Services.prefs.getDefaultBranch("").deleteBranch(preference);
});