OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** @fileoverview Suite of tests for cr-settings-prefs. */ | |
6 cr.define('cr_settings_prefs', function() { | |
7 /** | |
8 * Mock of chrome.settingsPrivate API. | |
9 * @constructor | |
10 * @extends {chrome.settingsPrivate} | |
11 */ | |
12 function MockSettingsApi() { | |
13 this.prefs = {}; | |
14 this.listener_ = null; | |
15 | |
16 // Hack alert: bind this instance's onPrefsChanged members to this. | |
17 this.onPrefsChanged = { | |
18 addListener: this.onPrefsChanged.addListener.bind(this), | |
19 removeListener: this.onPrefsChanged.removeListener.bind(this), | |
20 }; | |
21 | |
22 this.addBooleanPref_('top_level_pref', true); | |
23 this.addBooleanPref_('browser.enable_flash', false); | |
24 this.addBooleanPref_('browser.enable_html5', true); | |
25 this.addNumberPref_('device.overclock', .6); | |
26 this.addStringPref_('homepage', 'example.com'); | |
27 } | |
28 | |
29 MockSettingsApi.prototype = { | |
30 // chrome.settingsPrivate overrides. | |
31 onPrefsChanged: { | |
32 addListener: function(listener) { | |
33 this.listener_ = listener; | |
34 }, | |
35 | |
36 removeListener: function(listener) { | |
37 expectNotEquals(null, this.listener_); | |
38 this.listener_ = null; | |
39 }, | |
40 }, | |
41 | |
42 getAllPrefs: function(callback) { | |
43 // Send a copy of prefs to keep our internal state private. | |
44 var prefs = []; | |
45 for (var key in this.prefs) | |
46 prefs.push(Object.assign({}, this.prefs[key])); | |
47 | |
48 setTimeout(callback.bind(null, prefs)); | |
49 }, | |
50 | |
51 setPref: function(key, value, pageId, callback) { | |
52 var pref = this.prefs[key]; | |
53 assertNotEquals(undefined, pref); | |
54 assertEquals(typeof value, typeof pref.value); | |
55 assertEquals(Array.isArray(value), Array.isArray(pref.value)); | |
56 | |
57 if (this.failNextSetPref_) { | |
58 setTimeout(callback.bind(null, false)); | |
59 this.failNextSetPref_ = false; | |
60 return; | |
61 } | |
62 | |
63 // TODO(michaelpg): support list and dict prefs. | |
64 var changed = this.prefs[key].value != value; | |
65 this.prefs[key].value = value; | |
66 setTimeout(function() { | |
67 callback(true); | |
68 // Like chrome.settingsPrivate, send a notification when prefs change. | |
69 if (changed) | |
70 this.sendPrefChanges([key], [value]); | |
71 }.bind(this)); | |
72 }, | |
73 | |
74 getPref: function(key, callback) { | |
75 var pref = this.prefs[key]; | |
76 assertNotEquals(undefined, pref); | |
77 | |
78 var prefCopy = Object.assign({}, pref); | |
79 setTimeout(callback.bind(null, prefCopy)); | |
80 }, | |
81 | |
82 // Functions used by tests. | |
83 | |
84 /** Instructs the API to fail when setPref is next called. */ | |
85 failNextSetPref: function() { | |
86 this.failNextSetPref_ = true; | |
87 }, | |
88 | |
89 /** | |
90 * Notifies the listener of pref changes. | |
91 * @param {!Array<string>} keys | |
92 * @param {!Array<*>} values | |
93 */ | |
94 sendPrefChanges: function(keys, values) { | |
95 var prefs = []; | |
96 for (var i = 0; i < keys.length; i++) { | |
97 var key = keys[i]; | |
98 var pref = this.prefs[key]; | |
99 pref.value = values[i]; | |
100 prefs.push(Object.assign({}, pref)); | |
101 } | |
102 | |
103 setTimeout(this.listener_.bind(null, prefs)); | |
104 }, | |
105 | |
106 // Private methods for use by the mock API. | |
107 | |
108 /** | |
109 * @param {!chrome.settingsPrivate.PrefType} type | |
110 * @param {string} key | |
111 * @param {*} value | |
112 */ | |
113 addPref_: function(type, key, value) { | |
114 this.prefs[key] = { | |
115 type: type, | |
116 key: key, | |
117 value: value, | |
118 }; | |
119 }, | |
120 | |
121 /** | |
122 * @param {string} key | |
123 * @param {boolean} value | |
124 */ | |
125 addBooleanPref_: function(key, value) { | |
126 this.addPref_(chrome.settingsPrivate.PrefType.BOOLEAN, key, value); | |
127 }, | |
128 | |
129 /** | |
130 * @param {string} key | |
131 * @param {number} value | |
132 */ | |
133 addNumberPref_: function(key, value) { | |
134 this.addPref_(chrome.settingsPrivate.PrefType.NUMBER, key, value); | |
135 }, | |
136 | |
137 /** | |
138 * @param {string} key | |
139 * @param {string} value | |
140 */ | |
141 addStringPref_: function(key, value) { | |
142 this.addPref_(chrome.settingsPrivate.PrefType.STRING, key, value); | |
143 }, | |
144 }; | |
145 | |
146 /** | |
147 * Helper function to deal with asynchronicity by repeatedly queueing | |
148 * tasks to check if the callback returns true. | |
149 * @param {function(): boolean} callback | |
150 * @return {Promise} | |
151 */ | |
152 function waitUntilTrue(callback) { | |
153 return new Promise(function(resolve, reject) { | |
154 var interval = setInterval(function() { | |
155 if (callback.call()) { | |
156 clearInterval(interval); | |
157 resolve(); | |
158 } | |
159 }); | |
160 }); | |
161 } | |
162 | |
163 /** | |
164 * @param {!Object} prefStore Pref store from <cr-settings-prefs>. | |
165 * @param {string} key Pref key of the pref to return. | |
166 * @return {(chrome.settingsPrivate.PrefObject|undefined} | |
Dan Beam
2015/09/14 23:31:48
nit: https://xkcd.com/859/
michaelpg
2015/09/15 01:17:57
Done.
| |
167 */ | |
168 function getPrefFromKey(prefStore, key) { | |
169 var path = key.split('.'); | |
170 var pref = prefStore; | |
171 for (var part of path) { | |
172 pref = pref[part]; | |
173 if (!pref) | |
174 return; | |
stevenjb
2015/09/14 23:18:19
nit: return undefined? (That would be more clear t
Dan Beam
2015/09/14 23:31:48
not all that common
michaelpg
2015/09/15 01:17:58
Done.
| |
175 } | |
176 return pref; | |
177 } | |
178 | |
179 function registerTests() { | |
180 suite('CrSettingsPrefs', function() { | |
181 /** | |
182 * Prefs instance created before each test. | |
183 * @type {CrSettingsPrefs} | |
184 */ | |
185 var prefs; | |
186 | |
187 /** @type {MockSettingsApi} */ | |
188 var mockApi = null; | |
189 | |
190 // Initialize a <cr-settings-prefs> element before each test. | |
191 setup(function(done) { | |
192 mockApi = new MockSettingsApi(); | |
193 // TODO(michaelpg): don't use global variables to inject the API. | |
194 window.mockApi = mockApi; | |
195 | |
196 // Create and attach the <cr-settings-prefs> element. | |
197 PolymerTest.clearBody(); | |
198 prefs = document.createElement('cr-settings-prefs'); | |
199 document.body.appendChild(prefs); | |
200 | |
201 window.mockApi = undefined; | |
202 | |
203 // Wait for CrSettingsPrefs.INITIALIZED. | |
204 if (!CrSettingsPrefs.isInitialized) { | |
205 var listener = function() { | |
206 document.removeEventListener(CrSettingsPrefs.INITIALIZED, listener); | |
207 done(); | |
208 }; | |
209 document.addEventListener(CrSettingsPrefs.INITIALIZED, listener); | |
210 return; | |
211 } | |
212 | |
213 done(); | |
214 }); | |
215 | |
216 test('receives and caches prefs', function() { | |
217 // Test that each pref has been successfully copied to the Polymer | |
218 // |prefs| property. | |
219 for (var key in mockApi.prefs) { | |
220 var expectedPref = mockApi.prefs[key]; | |
221 var actualPref = getPrefFromKey(prefs.prefs, key); | |
222 if (!expectNotEquals(undefined, actualPref)) { | |
223 // We've already registered an error, so skip the pref. | |
224 continue; | |
225 } | |
226 | |
227 expectEquals(expectedPref.key, actualPref.key); | |
228 expectEquals(expectedPref.type, actualPref.type); | |
229 if (expectedPref.type != chrome.settingsPrivate.LIST) { | |
230 expectEquals(expectedPref.value, actualPref.value); | |
231 } else { | |
232 expectEquals(JSON.stringify(expectedPref.value), | |
233 JSON.stringify(actualPref.value)); | |
234 } | |
235 } | |
236 }); | |
237 | |
238 test('forwards pref changes to API', function() { | |
239 // Test that cr-settings-prefs uses the setPref API. | |
240 prefs.set('prefs.browser.enable_flash.value', true); | |
241 expectTrue(mockApi.prefs['browser.enable_flash'].value); | |
242 | |
243 prefs.set('prefs.device.overclock.value', 1.2); | |
244 expectEquals(1.2, mockApi.prefs['device.overclock'].value); | |
245 | |
246 prefs.set('prefs.homepage.value', 'chromium.org'); | |
247 expectEquals('chromium.org', mockApi.prefs['homepage'].value); | |
248 | |
249 // Test that when setPref fails, the pref is reverted locally. | |
250 mockApi.failNextSetPref(); | |
251 prefs.set('prefs.browser.enable_flash.value', false); | |
252 | |
253 mockApi.failNextSetPref(); | |
254 prefs.set('prefs.device.overclock.value', 2.0); | |
255 | |
256 mockApi.failNextSetPref(); | |
257 prefs.set('prefs.homepage.value', 'invalid-url'); | |
258 | |
259 // Multiple asynchronous round trips need to happen. | |
260 return Promise.all([ | |
261 waitUntilTrue(function() { | |
262 return prefs.prefs.browser.enable_flash.value; | |
263 }), | |
264 waitUntilTrue(function() { | |
265 return prefs.prefs.device.overclock.value == 1.2; | |
266 }), | |
267 waitUntilTrue(function() { | |
268 return prefs.prefs.homepage.value == 'chromium.org'; | |
269 }), | |
270 ]); | |
271 }); | |
272 | |
273 test('responds to API changes', function(done) { | |
274 mockApi.sendPrefChanges(['top_level_pref'], [false]); | |
275 PolymerTest.async(function() { | |
276 expectEquals(false, prefs.prefs.top_level_pref.value); | |
277 | |
278 mockApi.sendPrefChanges(['top_level_pref'], [true]); | |
279 }); | |
280 PolymerTest.async(function() { | |
281 expectEquals(true, prefs.prefs.top_level_pref.value); | |
282 done(); | |
283 }); | |
284 }); | |
285 }); | |
286 } | |
287 | |
288 return { | |
289 registerTests: registerTests, | |
290 }; | |
291 }); | |
OLD | NEW |