selenium-webdriver 3.5.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/firefox/index.js CHANGED
@@ -124,7 +124,6 @@ const url = require('url');
124
124
 
125
125
  const {Binary, Channel} = require('./binary'),
126
126
  Profile = require('./profile').Profile,
127
- decodeProfile = require('./profile').decode,
128
127
  http = require('../http'),
129
128
  httpUtil = require('../http/util'),
130
129
  io = require('../io'),
@@ -138,35 +137,6 @@ const {Binary, Channel} = require('./binary'),
138
137
  remote = require('../remote');
139
138
 
140
139
 
141
- /**
142
- * Firefox-specific capability keys. Users should use the {@linkplain Options}
143
- * class instead of referencing these keys directly. _These keys are considered
144
- * implementation details and may be removed or changed at any time._
145
- *
146
- * @enum {string}
147
- */
148
- const Capability = {
149
- /**
150
- * Defines the Firefox binary to use. May be set to either a
151
- * {@linkplain Binary} instance, or a string path to the Firefox executable.
152
- */
153
- BINARY: 'firefox_binary',
154
-
155
- /**
156
- * @deprecated This will be removed in a future release. There is no
157
- * replacement.
158
- */
159
- MARIONETTE: 'marionette',
160
-
161
- /**
162
- * Defines the Firefox profile to use. May be set to either a
163
- * {@linkplain Profile} instance, or to a base-64 encoded zip of a profile
164
- * directory.
165
- */
166
- PROFILE: 'firefox_profile'
167
- };
168
-
169
-
170
140
  /**
171
141
  * Configuration options for the FirefoxDriver.
172
142
  */
@@ -175,9 +145,12 @@ class Options {
175
145
  /** @private {Profile} */
176
146
  this.profile_ = null;
177
147
 
178
- /** @private {Binary} */
148
+ /** @private {(Binary|Channel|string|null)} */
179
149
  this.binary_ = null;
180
150
 
151
+ /** @private {!Array<string>} */
152
+ this.args_ = [];
153
+
181
154
  /** @private {logging.Preferences} */
182
155
  this.logPrefs_ = null;
183
156
 
@@ -185,6 +158,47 @@ class Options {
185
158
  this.proxy_ = null;
186
159
  }
187
160
 
161
+ /**
162
+ * Specify additional command line arguments that should be used when starting
163
+ * the Firefox browser.
164
+ *
165
+ * @param {...(string|!Array<string>)} args The arguments to include.
166
+ * @return {!Options} A self reference.
167
+ */
168
+ addArguments(...args) {
169
+ this.args_ = this.args_.concat(...args);
170
+ return this;
171
+ }
172
+
173
+ /**
174
+ * Configures the geckodriver to start Firefox in headless mode.
175
+ *
176
+ * @return {!Options} A self reference.
177
+ */
178
+ headless() {
179
+ return this.addArguments('-headless');
180
+ }
181
+
182
+ /**
183
+ * Sets the initial window size when running in
184
+ * {@linkplain #headless headless} mode.
185
+ *
186
+ * @param {{width: number, height: number}} size The desired window size.
187
+ * @return {!Options} A self reference.
188
+ * @throws {TypeError} if width or height is unspecified, not a number, or
189
+ * less than or equal to 0.
190
+ */
191
+ windowSize({width, height}) {
192
+ function checkArg(arg) {
193
+ if (typeof arg !== 'number' || arg <= 0) {
194
+ throw TypeError('Arguments must be {width, height} with numbers > 0');
195
+ }
196
+ }
197
+ checkArg(width);
198
+ checkArg(height);
199
+ return this.addArguments(`--window-size=${width},${height}`);
200
+ }
201
+
188
202
  /**
189
203
  * Sets the profile to use. The profile may be specified as a
190
204
  * {@link Profile} object or as the path to an existing Firefox profile to use
@@ -211,17 +225,14 @@ class Options {
211
225
  * @throws {TypeError} If `binary` is an invalid type.
212
226
  */
213
227
  setBinary(binary) {
214
- if (typeof binary === 'string' || binary instanceof Channel) {
215
- binary = new Binary(binary);
216
- }
217
-
218
- if (!(binary instanceof Binary)) {
219
- throw TypeError(
220
- 'binary must be a string path, Channel, or Binary object');
228
+ if (binary instanceof Binary
229
+ || binary instanceof Channel
230
+ || typeof binary === 'string') {
231
+ this.binary_ = binary;
232
+ return this;
221
233
  }
222
-
223
- this.binary_ = binary;
224
- return this;
234
+ throw TypeError(
235
+ 'binary must be a string path, Channel, or Binary object');
225
236
  }
226
237
 
227
238
  /**
@@ -245,33 +256,69 @@ class Options {
245
256
  return this;
246
257
  }
247
258
 
248
- /**
249
- * @deprecated This method has been deprecated and will be removed in the next
250
- * release. It is a no-op.
251
- */
252
- useGeckoDriver(enable) {
253
- return this;
254
- }
255
-
256
259
  /**
257
260
  * Converts these options to a {@link capabilities.Capabilities} instance.
258
261
  *
259
262
  * @return {!capabilities.Capabilities} A new capabilities object.
260
263
  */
261
264
  toCapabilities() {
262
- var caps = capabilities.Capabilities.firefox();
265
+ let caps = capabilities.Capabilities.firefox();
266
+ let firefoxOptions = {};
267
+ caps.set('moz:firefoxOptions', firefoxOptions);
268
+
263
269
  if (this.logPrefs_) {
264
270
  caps.set(capabilities.Capability.LOGGING_PREFS, this.logPrefs_);
265
271
  }
272
+
266
273
  if (this.proxy_) {
267
274
  caps.set(capabilities.Capability.PROXY, this.proxy_);
268
275
  }
276
+
277
+ if (this.args_.length) {
278
+ firefoxOptions['args'] = this.args_.concat();
279
+ }
280
+
269
281
  if (this.binary_) {
270
- caps.set(Capability.BINARY, this.binary_);
282
+ if (this.binary_ instanceof Binary) {
283
+ let exe = this.binary_.getExe();
284
+ if (exe) {
285
+ firefoxOptions['binary'] = exe;
286
+ }
287
+
288
+ let args = this.binary_.getArguments();
289
+ if (args.length) {
290
+ if (this.args_.length) {
291
+ throw Error(
292
+ 'You may specify browser arguments with Options.addArguments'
293
+ + ' (preferred) or Binary.addArguments, but not both');
294
+ }
295
+ firefoxOptions['args'] = args;
296
+ }
297
+ } else if (this.binary_ instanceof Channel) {
298
+ firefoxOptions['binary'] = this.binary_.locate();
299
+
300
+ } else if (typeof this.binary_ === 'string') {
301
+ firefoxOptions['binary'] = this.binary_;
302
+ }
271
303
  }
304
+
272
305
  if (this.profile_) {
273
- caps.set(Capability.PROFILE, this.profile_);
306
+ // If the user specified a template directory or any extensions to
307
+ // install, we need to encode the profile as a base64 string (which
308
+ // requires writing it to disk first). Otherwise, if the user just
309
+ // specified some custom preferences, we can send those directly.
310
+ let profile = this.profile_;
311
+ if (profile.getTemplateDir() || profile.getExtensions().length) {
312
+ firefoxOptions['profile'] = profile.encode();
313
+
314
+ } else {
315
+ let prefs = profile.getPreferences();
316
+ if (Object.keys(prefs).length) {
317
+ firefoxOptions['prefs'] = prefs;
318
+ }
319
+ }
274
320
  }
321
+
275
322
  return caps;
276
323
  }
277
324
  }
@@ -410,111 +457,6 @@ class ServiceBuilder extends remote.DriverService.Builder {
410
457
  enableVerboseLogging(opt_trace) {
411
458
  return this.addArguments(opt_trace ? '-vv' : '-v');
412
459
  }
413
-
414
- /**
415
- * Sets the path to the executable Firefox binary that the geckodriver should
416
- * use. If this method is not called, this builder will attempt to locate
417
- * Firefox in the default installation location for the current platform.
418
- *
419
- * @param {(string|!Binary)} binary Path to the executable Firefox binary to use.
420
- * @return {!ServiceBuilder} A self reference.
421
- * @see Binary#locate()
422
- */
423
- setFirefoxBinary(binary) {
424
- let exe = typeof binary === 'string'
425
- ? Promise.resolve(binary) : binary.locate();
426
- return this.addArguments('-b', exe);
427
- }
428
- }
429
-
430
-
431
- /**
432
- * @typedef {{executor: !command.Executor,
433
- * capabilities: (!capabilities.Capabilities|
434
- * {desired: (capabilities.Capabilities|undefined),
435
- * required: (capabilities.Capabilities|undefined)}),
436
- * onQuit: function(this: void): ?}}
437
- */
438
- var DriverSpec;
439
-
440
-
441
- /**
442
- * @param {(http.Executor|remote.DriverService|undefined)} executor
443
- * @param {!capabilities.Capabilities} caps
444
- * @param {Profile} profile
445
- * @param {Binary} binary
446
- * @return {DriverSpec}
447
- */
448
- function createGeckoDriver(executor, caps, profile, binary) {
449
- let firefoxOptions = caps.get('moz:firefoxOptions') || {};
450
- caps.set('moz:firefoxOptions', firefoxOptions);
451
-
452
- if (binary) {
453
- if (binary.getExe()) {
454
- firefoxOptions['binary'] = binary.getExe();
455
- }
456
-
457
- let args = binary.getArguments();
458
- if (args.length) {
459
- firefoxOptions['args'] = args;
460
- }
461
- }
462
-
463
- if (profile) {
464
- // If the user specified a template directory or any extensions to install,
465
- // we need to encode the profile as a base64 string (which requires writing
466
- // it to disk first). Otherwise, if the user just specified some custom
467
- // preferences, we can send those directly.
468
- if (profile.getTemplateDir() || profile.getExtensions().length) {
469
- firefoxOptions['profile'] = profile.encode();
470
-
471
- } else {
472
- let prefs = profile.getPreferences();
473
- if (Object.keys(prefs).length) {
474
- firefoxOptions['prefs'] = prefs;
475
- }
476
- }
477
- }
478
-
479
- let sessionCaps = caps;
480
- if (caps.has(capabilities.Capability.PROXY)) {
481
- let proxy = normalizeProxyConfiguration(
482
- caps.get(capabilities.Capability.PROXY));
483
-
484
- // Marionette requires proxy settings to be specified as required
485
- // capabilities. See mozilla/geckodriver#97
486
- let required = new capabilities.Capabilities()
487
- .set(capabilities.Capability.PROXY, proxy);
488
-
489
- caps.delete(capabilities.Capability.PROXY);
490
- sessionCaps = {required, desired: caps};
491
- }
492
-
493
- /** @type {!command.Executor} */
494
- let cmdExecutor;
495
- let onQuit = function() {};
496
-
497
- if (executor instanceof http.Executor) {
498
- configureExecutor(executor);
499
- cmdExecutor = executor;
500
- } else if (executor instanceof remote.DriverService) {
501
- cmdExecutor = createExecutor(executor.start());
502
- onQuit = () => executor.kill();
503
- } else {
504
- let builder = new ServiceBuilder();
505
- if (binary) {
506
- builder.setFirefoxBinary(binary);
507
- }
508
- let service = builder.build();
509
- cmdExecutor = createExecutor(service.start());
510
- onQuit = () => service.kill();
511
- }
512
-
513
- return {
514
- executor: cmdExecutor,
515
- capabilities: sessionCaps,
516
- onQuit
517
- };
518
460
  }
519
461
 
520
462
 
@@ -555,21 +497,29 @@ class Driver extends webdriver.WebDriver {
555
497
  caps = new capabilities.Capabilities(opt_config);
556
498
  }
557
499
 
558
- let binary = caps.get(Capability.BINARY) || new Binary();
559
- caps.delete(Capability.BINARY);
560
- if (typeof binary === 'string') {
561
- binary = new Binary(binary);
500
+ if (caps.has(capabilities.Capability.PROXY)) {
501
+ let proxy =
502
+ normalizeProxyConfiguration(caps.get(capabilities.Capability.PROXY));
503
+ caps.set(capabilities.Capability.PROXY, proxy);
562
504
  }
563
505
 
564
- let profile;
565
- if (caps.has(Capability.PROFILE)) {
566
- profile = caps.get(Capability.PROFILE);
567
- caps.delete(Capability.PROFILE);
506
+ let executor;
507
+ let onQuit;
508
+
509
+ if (opt_executor instanceof http.Executor) {
510
+ executor = opt_executor;
511
+ configureExecutor(executor);
512
+ } else if (opt_executor instanceof remote.DriverService) {
513
+ executor = createExecutor(opt_executor.start());
514
+ onQuit = () => opt_executor.kill();
515
+ } else {
516
+ let service = new ServiceBuilder().build();
517
+ executor = createExecutor(service.start());
518
+ onQuit = () => service.kill();
568
519
  }
569
520
 
570
- let spec = createGeckoDriver(opt_executor, caps, profile, binary);
571
521
  return /** @type {!Driver} */(super.createSession(
572
- spec.executor, spec.capabilities, opt_flow, spec.onQuit));
522
+ executor, caps, opt_flow, onQuit));
573
523
  }
574
524
 
575
525
  /**
@@ -33,28 +33,6 @@ const isDevMode = require('../lib/devmode'),
33
33
  extension = require('./extension');
34
34
 
35
35
 
36
- /** @const */
37
- const WEBDRIVER_PREFERENCES_PATH = isDevMode
38
- ? path.join(__dirname, '../../../firefox-driver/webdriver.json')
39
- : path.join(__dirname, '../lib/firefox/webdriver.json');
40
-
41
- /** @type {Object} */
42
- var defaultPreferences = null;
43
-
44
- /**
45
- * Synchronously loads the default preferences used for the FirefoxDriver.
46
- * @return {!Object} The default preferences JSON object.
47
- */
48
- function getDefaultPreferences() {
49
- if (!defaultPreferences) {
50
- var contents = /** @type {string} */(
51
- fs.readFileSync(WEBDRIVER_PREFERENCES_PATH, 'utf8'));
52
- defaultPreferences = /** @type {!Object} */(JSON.parse(contents));
53
- }
54
- return defaultPreferences;
55
- }
56
-
57
-
58
36
  /**
59
37
  * Parses a user.js file in a Firefox profile directory.
60
38
  * @param {string} f Path to the file to parse.
@@ -96,9 +74,13 @@ function writeUserPrefs(prefs, dir) {
96
74
  var userPrefs = path.join(dir, 'user.js');
97
75
  return loadUserPrefs(userPrefs).then(function(overrides) {
98
76
  Object.assign(prefs, overrides);
99
- Object.assign(prefs, getDefaultPreferences()['frozen']);
100
77
 
101
- var contents = Object.keys(prefs).map(function(key) {
78
+ let keys = Object.keys(prefs);
79
+ if (!keys.length) {
80
+ return dir;
81
+ }
82
+
83
+ let contents = Object.keys(prefs).map(function(key) {
102
84
  return 'user_pref(' + JSON.stringify(key) + ', ' +
103
85
  JSON.stringify(prefs[key]) + ');';
104
86
  }).join('\n');
@@ -146,22 +128,6 @@ function installExtensions(extensions, dir) {
146
128
  }
147
129
 
148
130
 
149
- /**
150
- * Decodes a base64 encoded profile.
151
- * @param {string} data The base64 encoded string.
152
- * @return {!Promise<string>} A promise for the path to the decoded profile
153
- * directory.
154
- */
155
- function decode(data) {
156
- return io.tmpFile().then(function(file) {
157
- let buf = new Buffer(data, 'base64');
158
- return io.write(file, buf)
159
- .then(io.tmpDir)
160
- .then(dir => unzip(file, dir));
161
- });
162
- }
163
-
164
-
165
131
 
166
132
  /**
167
133
  * Models a Firefox profile directory for use with the FirefoxDriver. The
@@ -178,15 +144,9 @@ class Profile {
178
144
  /** @private {!Object} */
179
145
  this.preferences_ = {};
180
146
 
181
- /** @private {boolean} */
182
- this.nativeEventsEnabled_ = true;
183
-
184
147
  /** @private {(string|undefined)} */
185
148
  this.template_ = opt_dir;
186
149
 
187
- /** @private {number} */
188
- this.port_ = 0;
189
-
190
150
  /** @private {!Array<string>} */
191
151
  this.extensions_ = [];
192
152
  }
@@ -222,12 +182,6 @@ class Profile {
222
182
  * @throws {Error} If attempting to set a frozen preference.
223
183
  */
224
184
  setPreference(key, value) {
225
- var frozen = getDefaultPreferences()['frozen'];
226
- if (frozen.hasOwnProperty(key) && frozen[key] !== value) {
227
- throw Error('You may not set ' + key + '=' + JSON.stringify(value)
228
- + '; value is frozen for proper WebDriver functionality ('
229
- + key + '=' + JSON.stringify(frozen[key]) + ')');
230
- }
231
185
  this.preferences_[key] = value;
232
186
  }
233
187
 
@@ -262,23 +216,6 @@ class Profile {
262
216
  this.preferences_['webdriver_firefox_allowed_hosts'] = host;
263
217
  }
264
218
 
265
- /**
266
- * @return {number} The port this profile is currently configured to use, or
267
- * 0 if the port will be selected at random when the profile is written
268
- * to disk.
269
- */
270
- getPort() {
271
- return this.port_;
272
- }
273
-
274
- /**
275
- * Sets the port to use for the WebDriver extension loaded by this profile.
276
- * @param {number} port The desired port, or 0 to use any free port.
277
- */
278
- setPort(port) {
279
- this.port_ = port;
280
- }
281
-
282
219
  /**
283
220
  * @return {boolean} Whether the FirefoxDriver is configured to automatically
284
221
  * accept untrusted SSL certificates.
@@ -312,22 +249,6 @@ class Profile {
312
249
  return !!this.preferences_['webdriver_assume_untrusted_issuer'];
313
250
  }
314
251
 
315
- /**
316
- * Sets whether to use native events with this profile.
317
- * @param {boolean} enabled .
318
- */
319
- setNativeEventsEnabled(enabled) {
320
- this.nativeEventsEnabled_ = enabled;
321
- }
322
-
323
- /**
324
- * Returns whether native events are enabled in this profile.
325
- * @return {boolean} .
326
- */
327
- nativeEventsEnabled() {
328
- return this.nativeEventsEnabled_;
329
- }
330
-
331
252
  /**
332
253
  * Writes this profile to disk.
333
254
  * @return {!Promise<string>} A promise for the path to the new profile
@@ -344,10 +265,7 @@ class Profile {
344
265
  }
345
266
 
346
267
  // Freeze preferences for async operations.
347
- var prefs = {};
348
- Object.assign(prefs, getDefaultPreferences()['mutable']);
349
- Object.assign(prefs, getDefaultPreferences()['frozen']);
350
- Object.assign(prefs, this.preferences_);
268
+ let prefs = Object.assign({}, this.preferences_);
351
269
 
352
270
  // Freeze extensions for async operations.
353
271
  var extensions = this.extensions_.concat();
@@ -390,5 +308,4 @@ class Profile {
390
308
 
391
309
 
392
310
  exports.Profile = Profile;
393
- exports.decode = decode;
394
311
  exports.loadUserPrefs = loadUserPrefs;
File without changes
@@ -204,16 +204,19 @@ function toMap(hash) {
204
204
  /**
205
205
  * Describes a set of capabilities for a WebDriver session.
206
206
  */
207
- class Capabilities extends Map {
207
+ class Capabilities {
208
208
  /**
209
- * @param {(Capabilities|Map<string, ?>|Object)=} opt_other Another set of
209
+ * @param {(Capabilities|Map<string, ?>|Object)=} other Another set of
210
210
  * capabilities to initialize this instance from.
211
211
  */
212
- constructor(opt_other) {
213
- if (opt_other && !(opt_other instanceof Map)) {
214
- opt_other = toMap(opt_other);
212
+ constructor(other = undefined) {
213
+ if (other instanceof Capabilities) {
214
+ other = other.map_;
215
+ } else if (other && !(other instanceof Map)) {
216
+ other = toMap(other);
215
217
  }
216
- super(opt_other);
218
+ /** @private @const {!Map<string, ?>} */
219
+ this.map_ = new Map(other);
217
220
  }
218
221
 
219
222
  /**
@@ -221,8 +224,7 @@ class Capabilities extends Map {
221
224
  */
222
225
  static android() {
223
226
  return new Capabilities()
224
- .set(Capability.BROWSER_NAME, Browser.ANDROID)
225
- .set(Capability.PLATFORM, 'ANDROID');
227
+ .set(Capability.BROWSER_NAME, Browser.ANDROID);
226
228
  }
227
229
 
228
230
  /**
@@ -237,8 +239,7 @@ class Capabilities extends Map {
237
239
  */
238
240
  static edge() {
239
241
  return new Capabilities()
240
- .set(Capability.BROWSER_NAME, Browser.EDGE)
241
- .set(Capability.PLATFORM, 'WINDOWS');
242
+ .set(Capability.BROWSER_NAME, Browser.EDGE);
242
243
  }
243
244
 
244
245
  /**
@@ -253,8 +254,7 @@ class Capabilities extends Map {
253
254
  */
254
255
  static ie() {
255
256
  return new Capabilities().
256
- set(Capability.BROWSER_NAME, Browser.INTERNET_EXPLORER).
257
- set(Capability.PLATFORM, 'WINDOWS');
257
+ set(Capability.BROWSER_NAME, Browser.INTERNET_EXPLORER);
258
258
  }
259
259
 
260
260
  /**
@@ -262,8 +262,7 @@ class Capabilities extends Map {
262
262
  */
263
263
  static ipad() {
264
264
  return new Capabilities().
265
- set(Capability.BROWSER_NAME, Browser.IPAD).
266
- set(Capability.PLATFORM, 'MAC');
265
+ set(Capability.BROWSER_NAME, Browser.IPAD);
267
266
  }
268
267
 
269
268
  /**
@@ -271,8 +270,7 @@ class Capabilities extends Map {
271
270
  */
272
271
  static iphone() {
273
272
  return new Capabilities().
274
- set(Capability.BROWSER_NAME, Browser.IPHONE).
275
- set(Capability.PLATFORM, 'MAC');
273
+ set(Capability.BROWSER_NAME, Browser.IPHONE);
276
274
  }
277
275
 
278
276
  /**
@@ -296,8 +294,7 @@ class Capabilities extends Map {
296
294
  */
297
295
  static safari() {
298
296
  return new Capabilities().
299
- set(Capability.BROWSER_NAME, Browser.SAFARI).
300
- set(Capability.PLATFORM, 'MAC');
297
+ set(Capability.BROWSER_NAME, Browser.SAFARI);
301
298
  }
302
299
 
303
300
  /**
@@ -328,6 +325,35 @@ class Capabilities extends Map {
328
325
  return serialize(this);
329
326
  }
330
327
 
328
+ /**
329
+ * @param {string} key the parameter key to get.
330
+ * @return {T} the stored parameter value.
331
+ * @template T
332
+ */
333
+ get(key) {
334
+ return this.map_.get(key);
335
+ }
336
+
337
+ /**
338
+ * @param {string} key the key to test.
339
+ * @return {boolean} whether this capability set has the specified key.
340
+ */
341
+ has(key) {
342
+ return this.map_.has(key);
343
+ }
344
+
345
+ /**
346
+ * @return {!Iterator<string>} an iterator of the keys set.
347
+ */
348
+ keys() {
349
+ return this.map_.keys();
350
+ }
351
+
352
+ /** @return {number} The number of capabilities set. */
353
+ get size() {
354
+ return this.map_.size;
355
+ }
356
+
331
357
  /**
332
358
  * Merges another set of capabilities into this instance.
333
359
  * @param {!(Capabilities|Map<String, ?>|Object<string, ?>)} other The other
@@ -339,7 +365,12 @@ class Capabilities extends Map {
339
365
  throw new TypeError('no capabilities provided for merge');
340
366
  }
341
367
 
342
- if (!(other instanceof Map)) {
368
+ let map;
369
+ if (other instanceof Capabilities) {
370
+ map = other.map_;
371
+ } else if (other instanceof Map) {
372
+ map = other;
373
+ } else {
343
374
  other = toMap(other);
344
375
  }
345
376
 
@@ -350,18 +381,26 @@ class Capabilities extends Map {
350
381
  return this;
351
382
  }
352
383
 
384
+ /**
385
+ * Deletes an entry from this set of capabilities.
386
+ *
387
+ * @param {string} key the capability key to delete.
388
+ */
389
+ delete(key) {
390
+ this.map_.delete(key);
391
+ }
392
+
353
393
  /**
354
394
  * @param {string} key The capability key.
355
395
  * @param {*} value The capability value.
356
396
  * @return {!Capabilities} A self reference.
357
397
  * @throws {TypeError} If the `key` is not a string.
358
- * @override
359
398
  */
360
399
  set(key, value) {
361
400
  if (typeof key !== 'string') {
362
401
  throw new TypeError('Capability keys must be strings: ' + typeof key);
363
402
  }
364
- super.set(key, value);
403
+ this.map_.set(key, value);
365
404
  return this;
366
405
  }
367
406