selenium-webdriver 3.1.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.
Files changed (65) hide show
  1. package/CHANGES.md +112 -0
  2. package/NOTICE +1 -1
  3. package/README.md +5 -11
  4. package/chrome.js +122 -33
  5. package/edge.js +2 -2
  6. package/example/async_await_test.js +69 -0
  7. package/example/chrome_android.js +2 -3
  8. package/example/chrome_mobile_emulation.js +3 -4
  9. package/example/firefox_channels.js +3 -3
  10. package/example/google_search.js +3 -3
  11. package/example/google_search_generator.js +2 -5
  12. package/example/google_search_test.js +5 -6
  13. package/example/headless.js +55 -0
  14. package/example/logging.js +3 -3
  15. package/example/parallel_flows.js +4 -7
  16. package/firefox/binary.js +3 -0
  17. package/firefox/extension.js +118 -81
  18. package/firefox/index.js +117 -263
  19. package/firefox/profile.js +18 -137
  20. package/ie.js +2 -2
  21. package/index.js +4 -1
  22. package/io/index.js +59 -0
  23. package/io/zip.js +214 -0
  24. package/lib/atoms/get-attribute.js +9 -0
  25. package/lib/atoms/is-displayed.js +73 -78
  26. package/lib/by.js +8 -0
  27. package/lib/capabilities.js +61 -22
  28. package/lib/command.js +2 -0
  29. package/lib/error.js +32 -2
  30. package/lib/http.js +53 -44
  31. package/lib/promise.js +72 -25
  32. package/lib/test/data/click_tests/disabled_element.html +12 -0
  33. package/lib/test/data/content-editable.html +10 -0
  34. package/lib/test/data/firefox/webextension.xpi +0 -0
  35. package/lib/test/data/key_logger.html +34 -0
  36. package/lib/test/data/nestedElements.html +10 -1
  37. package/lib/test/data/scrolling_tests/page_with_partially_hidden_element.html +14 -0
  38. package/lib/test/data/single_text_input.html +12 -0
  39. package/lib/test/index.js +4 -36
  40. package/lib/webdriver.js +147 -55
  41. package/net/portprober.js +1 -1
  42. package/opera.js +1 -1
  43. package/package.json +2 -2
  44. package/phantomjs.js +2 -2
  45. package/remote/index.js +21 -14
  46. package/safari.js +2 -2
  47. package/test/firefox/extension_test.js +41 -17
  48. package/test/firefox/firefox_test.js +37 -19
  49. package/test/firefox/profile_test.js +14 -59
  50. package/test/http/http_test.js +18 -0
  51. package/test/{io_test.js → io/io_test.js} +40 -1
  52. package/test/io/zip_test.js +128 -0
  53. package/test/lib/by_test.js +21 -0
  54. package/test/lib/error_test.js +21 -1
  55. package/test/lib/http_test.js +11 -3
  56. package/test/lib/webdriver_test.js +107 -3
  57. package/test/page_loading_test.js +0 -6
  58. package/test/remote_test.js +3 -3
  59. package/test/session_test.js +68 -23
  60. package/testing/index.js +2 -3
  61. package/lib/atoms/getAttribute.js +0 -12
  62. package/lib/firefox/amd64/libnoblur64.so +0 -0
  63. package/lib/firefox/i386/libnoblur.so +0 -0
  64. package/lib/firefox/webdriver.json +0 -69
  65. package/lib/firefox/webdriver.xpi +0 -0
@@ -17,24 +17,27 @@
17
17
 
18
18
  'use strict';
19
19
 
20
- var AdmZip = require('adm-zip'),
21
- assert = require('assert'),
20
+ var assert = require('assert'),
22
21
  crypto = require('crypto'),
23
22
  fs = require('fs'),
24
23
  path = require('path');
25
24
 
26
25
  var extension = require('../../firefox/extension'),
27
26
  io = require('../../io'),
27
+ zip = require('../../io/zip'),
28
28
  it = require('../../testing').it;
29
29
 
30
30
 
31
31
  var JETPACK_EXTENSION = path.join(__dirname,
32
32
  '../../lib/test/data/firefox/jetpack-sample.xpi');
33
33
  var NORMAL_EXTENSION = path.join(__dirname,
34
- '../../lib/test/data/firefox/sample.xpi');
34
+ '../../lib/test/data/firefox/sample.xpi');
35
+ var WEBEXTENSION_EXTENSION = path.join(__dirname,
36
+ '../../lib/test/data/firefox/webextension.xpi');
35
37
 
36
38
  var JETPACK_EXTENSION_ID = 'jid1-EaXX7k0wwiZR7w@jetpack';
37
39
  var NORMAL_EXTENSION_ID = 'sample@seleniumhq.org';
40
+ var WEBEXTENSION_EXTENSION_ID = 'webextensions-selenium-example@example.com';
38
41
 
39
42
 
40
43
  describe('extension', function() {
@@ -75,22 +78,43 @@ describe('extension', function() {
75
78
  });
76
79
  });
77
80
 
81
+ it('can install a webextension xpi file', function() {
82
+ return io.tmpDir().then(function(dir) {
83
+ return extension.install(WEBEXTENSION_EXTENSION, dir).then(function(id) {
84
+ assert.equal(WEBEXTENSION_EXTENSION_ID, id);
85
+ var file = path.join(dir, id + '.xpi');
86
+ assert.ok(fs.existsSync(file), 'no such file: ' + file);
87
+ assert.ok(!fs.statSync(file).isDirectory());
88
+
89
+ var copiedSha1 = crypto.createHash('sha1')
90
+ .update(fs.readFileSync(file))
91
+ .digest('hex');
92
+
93
+ var goldenSha1 = crypto.createHash('sha1')
94
+ .update(fs.readFileSync(WEBEXTENSION_EXTENSION))
95
+ .digest('hex');
96
+
97
+ assert.equal(copiedSha1, goldenSha1);
98
+ });
99
+ });
100
+ });
101
+
78
102
  it('can install an extension from a directory', function() {
79
103
  return io.tmpDir().then(function(srcDir) {
80
- var buf = fs.readFileSync(NORMAL_EXTENSION);
81
- new AdmZip(buf).extractAllTo(srcDir, true);
82
- return io.tmpDir().then(function(dstDir) {
83
- return extension.install(srcDir, dstDir).then(function(id) {
84
- assert.equal(NORMAL_EXTENSION_ID, id);
85
-
86
- var dir = path.join(dstDir, NORMAL_EXTENSION_ID);
87
-
88
- assert.ok(fs.existsSync(path.join(dir, 'chrome.manifest')));
89
- assert.ok(fs.existsSync(path.join(dir, 'content/overlay.xul')));
90
- assert.ok(fs.existsSync(path.join(dir, 'content/overlay.js')));
91
- assert.ok(fs.existsSync(path.join(dir, 'install.rdf')));
92
- });
93
- });
104
+ return zip.unzip(NORMAL_EXTENSION, srcDir)
105
+ .then(() => io.tmpDir())
106
+ .then(dstDir => {
107
+ return extension.install(srcDir, dstDir).then(function(id) {
108
+ assert.equal(NORMAL_EXTENSION_ID, id);
109
+
110
+ var dir = path.join(dstDir, NORMAL_EXTENSION_ID);
111
+
112
+ assert.ok(fs.existsSync(path.join(dir, 'chrome.manifest')));
113
+ assert.ok(fs.existsSync(path.join(dir, 'content/overlay.xul')));
114
+ assert.ok(fs.existsSync(path.join(dir, 'content/overlay.js')));
115
+ assert.ok(fs.existsSync(path.join(dir, 'install.rdf')));
116
+ });
117
+ });
94
118
  });
95
119
  });
96
120
  });
@@ -33,23 +33,36 @@ var JETPACK_EXTENSION = path.join(__dirname,
33
33
  '../../lib/test/data/firefox/jetpack-sample.xpi');
34
34
  var NORMAL_EXTENSION = path.join(__dirname,
35
35
  '../../lib/test/data/firefox/sample.xpi');
36
+ var WEBEXTENSION_EXTENSION = path.join(__dirname,
37
+ '../../lib/test/data/firefox/webextension.xpi');
36
38
 
37
39
 
38
40
  test.suite(function(env) {
39
41
  describe('firefox', function() {
40
42
  describe('Options', function() {
41
- var driver;
43
+ let driver;
42
44
 
43
- test.beforeEach(function() {
45
+ beforeEach(function() {
44
46
  driver = null;
45
47
  });
46
48
 
47
- test.afterEach(function() {
49
+ afterEach(function() {
48
50
  if (driver) {
49
51
  return driver.quit();
50
52
  }
51
53
  });
52
54
 
55
+ /**
56
+ * @param {...string} extensions the extensions to install.
57
+ * @return {!firefox.Profile} a new profile.
58
+ */
59
+ function profileWithExtensions(...extensions) {
60
+ let profile = new firefox.Profile();
61
+ profile.setPreference('xpinstall.signatures.required', false);
62
+ extensions.forEach(ext => profile.addExtension(ext));
63
+ return profile;
64
+ }
65
+
53
66
  /**
54
67
  * Runs a test that requires Firefox Developer Edition. The test will be
55
68
  * skipped if dev cannot be found on the current system.
@@ -97,9 +110,7 @@ test.suite(function(env) {
97
110
  });
98
111
 
99
112
  test.it('can start Firefox with a jetpack extension', function() {
100
- let profile = new firefox.Profile();
101
- profile.addExtension(JETPACK_EXTENSION);
102
-
113
+ let profile = profileWithExtensions(JETPACK_EXTENSION);
103
114
  let options = new firefox.Options().setProfile(profile);
104
115
 
105
116
  return runWithFirefoxDev(options, function*() {
@@ -113,9 +124,7 @@ test.suite(function(env) {
113
124
  });
114
125
 
115
126
  test.it('can start Firefox with a normal extension', function() {
116
- let profile = new firefox.Profile();
117
- profile.addExtension(NORMAL_EXTENSION);
118
-
127
+ let profile = profileWithExtensions(NORMAL_EXTENSION);
119
128
  let options = new firefox.Options().setProfile(profile);
120
129
 
121
130
  return runWithFirefoxDev(options, function*() {
@@ -128,11 +137,23 @@ test.suite(function(env) {
128
137
  });
129
138
  });
130
139
 
131
- test.it('can start Firefox with multiple extensions', function() {
132
- let profile = new firefox.Profile();
133
- profile.addExtension(JETPACK_EXTENSION);
134
- profile.addExtension(NORMAL_EXTENSION);
140
+ test.it('can start Firefox with a webextension extension', function() {
141
+ let profile = profileWithExtensions(WEBEXTENSION_EXTENSION);
142
+ let options = new firefox.Options().setProfile(profile);
135
143
 
144
+ return runWithFirefoxDev(options, function*() {
145
+ yield driver.get(test.Pages.echoPage);
146
+
147
+ let footer =
148
+ yield driver.findElement({id: 'webextensions-selenium-example'});
149
+ let text = yield footer.getText();
150
+ assert(text).equalTo('Content injected by webextensions-selenium-example');
151
+ });
152
+ });
153
+
154
+ test.it('can start Firefox with multiple extensions', function() {
155
+ let profile =
156
+ profileWithExtensions(JETPACK_EXTENSION, NORMAL_EXTENSION);
136
157
  let options = new firefox.Options().setProfile(profile);
137
158
 
138
159
  return runWithFirefoxDev(options, function*() {
@@ -198,13 +219,11 @@ test.suite(function(env) {
198
219
  }
199
220
  });
200
221
 
201
- test.ignore(() => !env.isMarionette).
202
- it('can get context', function() {
222
+ test.it('can get context', function() {
203
223
  return assert(driver.getContext()).equalTo(Context.CONTENT);
204
224
  });
205
225
 
206
- test.ignore(() => !env.isMarionette).
207
- it('can set context', function*() {
226
+ test.it('can set context', function*() {
208
227
  yield driver.setContext(Context.CHROME);
209
228
  let ctxt = yield driver.getContext();
210
229
  assert(ctxt).equalTo(Context.CHROME);
@@ -214,8 +233,7 @@ test.suite(function(env) {
214
233
  assert(ctxt).equalTo(Context.CONTENT);
215
234
  });
216
235
 
217
- test.ignore(() => !env.isMarionette).
218
- it('throws on unknown context', function() {
236
+ test.it('throws on unknown context', function() {
219
237
  return driver.setContext("foo").then(assert.fail, function(e) {
220
238
  assert(e).instanceOf(error.InvalidArgumentError);
221
239
  });
@@ -17,8 +17,7 @@
17
17
 
18
18
  'use strict';
19
19
 
20
- var AdmZip = require('adm-zip'),
21
- assert = require('assert'),
20
+ var assert = require('assert'),
22
21
  fs = require('fs'),
23
22
  path = require('path');
24
23
 
@@ -33,10 +32,12 @@ var JETPACK_EXTENSION = path.join(__dirname,
33
32
  '../../lib/test/data/firefox/jetpack-sample.xpi');
34
33
  var NORMAL_EXTENSION = path.join(__dirname,
35
34
  '../../lib/test/data/firefox/sample.xpi');
35
+ var WEBEXTENSION_EXTENSION = path.join(__dirname,
36
+ '../../lib/test/data/firefox/webextension.xpi');
36
37
 
37
38
  var JETPACK_EXTENSION_ID = 'jid1-EaXX7k0wwiZR7w@jetpack.xpi';
38
39
  var NORMAL_EXTENSION_ID = 'sample@seleniumhq.org';
39
- var WEBDRIVER_EXTENSION_ID = 'fxdriver@googlecode.com';
40
+ var WEBEXTENSION_EXTENSION_ID = 'webextensions-selenium-example@example.com';
40
41
 
41
42
 
42
43
 
@@ -57,13 +58,6 @@ describe('Profile', function() {
57
58
  assert.equal('http://www.example.com',
58
59
  profile.getPreference('browser.newtab.url'));
59
60
  });
60
-
61
- it('throws if setting a frozen preference', function() {
62
- var profile = new Profile();
63
- assert.throws(function() {
64
- profile.setPreference('app.update.auto', true);
65
- });
66
- });
67
61
  });
68
62
 
69
63
  describe('writeToDisk', function() {
@@ -104,20 +98,6 @@ describe('Profile', function() {
104
98
  });
105
99
 
106
100
  describe('user.js', function() {
107
-
108
- it('writes defaults', function() {
109
- return new Profile().writeToDisk().then(function(dir) {
110
- return loadUserPrefs(path.join(dir, 'user.js'));
111
- }).then(function(prefs) {
112
- // Just check a few.
113
- assert.equal(false, prefs['app.update.auto']);
114
- assert.equal(true, prefs['browser.EULA.override']);
115
- assert.equal(false, prefs['extensions.update.enabled']);
116
- assert.equal('about:blank', prefs['browser.newtab.url']);
117
- assert.equal(30, prefs['dom.max_script_run_time']);
118
- });
119
- });
120
-
121
101
  it('merges template user.js into preferences', function() {
122
102
  return io.tmpDir().then(function(dir) {
123
103
  fs.writeFileSync(path.join(dir, 'user.js'), [
@@ -133,19 +113,6 @@ describe('Profile', function() {
133
113
  assert.equal(1234, prefs['dom.max_script_run_time']);
134
114
  });
135
115
  });
136
-
137
- it('ignores frozen preferences when merging template user.js',
138
- function() {
139
- return io.tmpDir().then(function(dir) {
140
- fs.writeFileSync(path.join(dir, 'user.js'),
141
- 'user_pref("app.update.auto", true)');
142
- return new Profile(dir).writeToDisk();
143
- }).then(function(profile) {
144
- return loadUserPrefs(path.join(profile, 'user.js'));
145
- }).then(function(prefs) {
146
- assert.equal(false, prefs['app.update.auto']);
147
- });
148
- });
149
116
  });
150
117
 
151
118
  describe('extensions', function() {
@@ -153,33 +120,21 @@ describe('Profile', function() {
153
120
  var profile = new Profile();
154
121
  profile.addExtension(JETPACK_EXTENSION);
155
122
  profile.addExtension(NORMAL_EXTENSION);
123
+ profile.addExtension(WEBEXTENSION_EXTENSION);
156
124
 
157
125
  return profile.writeToDisk().then(function(dir) {
158
126
  dir = path.join(dir, 'extensions');
159
- assert.ok(fs.existsSync(path.join(dir, JETPACK_EXTENSION_ID)));
160
- assert.ok(fs.existsSync(path.join(dir, NORMAL_EXTENSION_ID)));
161
- assert.ok(fs.existsSync(path.join(dir, WEBDRIVER_EXTENSION_ID)));
127
+ assertExists(JETPACK_EXTENSION_ID);
128
+ assertExists(NORMAL_EXTENSION_ID);
129
+ assertExists(WEBEXTENSION_EXTENSION_ID + '.xpi');
130
+
131
+ function assertExists(file) {
132
+ assert.ok(
133
+ fs.existsSync(path.join(dir, file)),
134
+ `expected ${file} to exist`);
135
+ }
162
136
  });
163
137
  });
164
138
  });
165
139
  });
166
-
167
- describe('encode', function() {
168
- it('excludes the bundled WebDriver extension', function() {
169
- return new Profile().encode().then(function(data) {
170
- return decode(data);
171
- }).then(function(dir) {
172
- assert.ok(fs.existsSync(path.join(dir, 'user.js')));
173
- assert.ok(fs.existsSync(path.join(dir, 'extensions')));
174
- return loadUserPrefs(path.join(dir, 'user.js'));
175
- }).then(function(prefs) {
176
- // Just check a few.
177
- assert.equal(false, prefs['app.update.auto']);
178
- assert.equal(true, prefs['browser.EULA.override']);
179
- assert.equal(false, prefs['extensions.update.enabled']);
180
- assert.equal('about:blank', prefs['browser.newtab.url']);
181
- assert.equal(30, prefs['dom.max_script_run_time']);
182
- });
183
- });
184
- });
185
140
  });
@@ -44,6 +44,14 @@ describe('HttpClient', function() {
44
44
  res.writeHead(200, {'content-type': 'text/plain'});
45
45
  res.end('hello, world!');
46
46
 
47
+ } else if (req.method == 'GET' && req.url == '/chunked') {
48
+ res.writeHead(200, {
49
+ 'content-type': 'text/html; charset=utf-8',
50
+ 'transfer-encoding': 'chunked'
51
+ });
52
+ res.write('<!DOCTYPE html>');
53
+ setTimeout(() => res.end('<h1>Hello, world!</h1>'), 20);
54
+
47
55
  } else if (req.method == 'GET' && req.url == '/badredirect') {
48
56
  res.writeHead(303, {});
49
57
  res.end();
@@ -121,6 +129,16 @@ describe('HttpClient', function() {
121
129
  });
122
130
  });
123
131
 
132
+ it('handles chunked responses', function() {
133
+ let request = new HttpRequest('GET', '/chunked');
134
+
135
+ let client = new HttpClient(server.url());
136
+ return client.send(request).then(response => {
137
+ assert.equal(200, response.status);
138
+ assert.equal(response.body, '<!DOCTYPE html><h1>Hello, world!</h1>');
139
+ });
140
+ });
141
+
124
142
  it('can use basic auth', function() {
125
143
  var parsed = url.parse(server.url());
126
144
  parsed.auth = 'genie:bottle';
@@ -22,7 +22,7 @@ var assert = require('assert'),
22
22
  path = require('path'),
23
23
  tmp = require('tmp');
24
24
 
25
- var io = require('../io');
25
+ var io = require('../../io');
26
26
 
27
27
 
28
28
  describe('io', function() {
@@ -318,4 +318,43 @@ describe('io', function() {
318
318
  (e) => assert.equal('ENOENT', e.code));
319
319
  });
320
320
  });
321
+
322
+ describe('mkdirp', function() {
323
+ it('recursively creates entire directory path', function() {
324
+ return io.tmpDir().then(root => {
325
+ let dst = path.join(root, 'foo/bar/baz');
326
+ return io.mkdirp(dst).then(d => {
327
+ assert.strictEqual(d, dst);
328
+ return io.stat(d).then(stats => {
329
+ assert.ok(stats.isDirectory());
330
+ });
331
+ });
332
+ });
333
+ });
334
+
335
+ it('does nothing if the directory already exists', function() {
336
+ return io.tmpDir()
337
+ .then(dir => io.mkdirp(dir).then(d => assert.strictEqual(d, dir)));
338
+ });
339
+ });
340
+
341
+ describe('walkDir', function() {
342
+ it('walk directory', function() {
343
+ return io.tmpDir().then(dir => {
344
+ fs.writeFileSync(path.join(dir, 'file1'), 'hello');
345
+ fs.mkdirSync(path.join(dir, 'sub'));
346
+ fs.mkdirSync(path.join(dir, 'sub/folder'));
347
+ fs.writeFileSync(path.join(dir, 'sub/folder/file2'), 'goodbye');
348
+
349
+ return io.walkDir(dir).then(seen => {
350
+ assert.deepStrictEqual(
351
+ seen,
352
+ [{path: 'file1', dir: false},
353
+ {path: 'sub', dir: true},
354
+ {path: 'sub/folder', dir: true},
355
+ {path: 'sub/folder/file2', dir: false}]);
356
+ });
357
+ });
358
+ });
359
+ })
321
360
  });
@@ -0,0 +1,128 @@
1
+ // Licensed to the Software Freedom Conservancy (SFC) under one
2
+ // or more contributor license agreements. See the NOTICE file
3
+ // distributed with this work for additional information
4
+ // regarding copyright ownership. The SFC licenses this file
5
+ // to you under the Apache License, Version 2.0 (the
6
+ // "License"); you may not use this file except in compliance
7
+ // with the License. You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing,
12
+ // software distributed under the License is distributed on an
13
+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ // KIND, either express or implied. See the License for the
15
+ // specific language governing permissions and limitations
16
+ // under the License.
17
+
18
+ 'use strict';
19
+
20
+ const assert = require('assert');
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+
24
+ const io = require('../../io');
25
+ const devmode = require('../../lib/devmode');
26
+ const zip = require('../../io/zip');
27
+ const {InvalidArgumentError} = require('../../lib/error');
28
+
29
+
30
+ const SAMPLE_XPI_PATH =
31
+ path.join(__dirname, '../../lib/test/data/firefox/sample.xpi');
32
+
33
+ describe('io/zip', function() {
34
+ describe('unzip', function() {
35
+ it('creates destination dir if necessary', function() {
36
+ return io.tmpDir()
37
+ .then(dir => zip.unzip(SAMPLE_XPI_PATH, dir))
38
+ .then(dir => {
39
+ assertExists(path.join(dir, 'chrome.manifest'));
40
+ assertExists(path.join(dir, 'content/overlay.js'));
41
+ assertExists(path.join(dir, 'content/overlay.xul'));
42
+ assertExists(path.join(dir, 'install.rdf'));
43
+ });
44
+ });
45
+ });
46
+
47
+ describe('Zip', function() {
48
+ let dir;
49
+
50
+ beforeEach(function() {
51
+ return io.tmpDir().then(d => dir = d);
52
+ });
53
+
54
+ it('can convert an archive to a buffer', function() {
55
+ let z = new zip.Zip;
56
+ return io.mkdirp(path.join(dir, 'a/b/c/d/e')).then(() => {
57
+ return Promise.all([
58
+ io.write(path.join(dir, 'foo'), 'a file'),
59
+ io.write(path.join(dir, 'a/b/c/carrot'), 'an orange carrot'),
60
+ io.write(path.join(dir, 'a/b/c/d/e/elephant'), 'e is for elephant')
61
+ ]);
62
+ })
63
+ .then(() => z.addDir(dir))
64
+ .then(() => Promise.all([io.tmpDir(), z.toBuffer()]))
65
+ .then(([outDir, buf]) => {
66
+ let output = path.join(outDir, 'out.zip');
67
+ return io.write(output, buf)
68
+ .then(() => io.tmpDir())
69
+ .then(d => zip.unzip(output, d))
70
+ .then(d => {
71
+ assertContents(path.join(d, 'foo'), 'a file');
72
+ assertContents(path.join(d, 'a/b/c/carrot'), 'an orange carrot');
73
+ assertContents(
74
+ path.join(d, 'a/b/c/d/e/elephant'),
75
+ 'e is for elephant');
76
+ });
77
+ });
78
+ });
79
+
80
+ describe('getFile', function() {
81
+ it('returns archive file contents as a buffer', function() {
82
+ let foo = path.join(dir, 'foo');
83
+ fs.writeFileSync(foo, 'hello, world!');
84
+
85
+ let z = new zip.Zip;
86
+ return z.addFile(foo).then(() => {
87
+ assert.ok(z.has('foo'));
88
+ return z.getFile('foo');
89
+ }).then(
90
+ buffer => assert.equal(buffer.toString('utf8'), 'hello, world!'));
91
+ });
92
+
93
+ it('returns an error if file is not in archive', function() {
94
+ let z = new zip.Zip;
95
+ assert.ok(!z.has('some-file'));
96
+ return z.getFile('some-file')
97
+ .then(() => assert.fail('should have failed'),
98
+ e => assert.strictEqual(e.constructor, InvalidArgumentError));
99
+ });
100
+
101
+ it(
102
+ 'returns a rejected promise if the requested path is a directory',
103
+ function() {
104
+ let file = path.join(dir, 'aFile');
105
+ fs.writeFileSync(file, 'hello, world!');
106
+
107
+ let z = new zip.Zip;
108
+ return z.addDir(dir, 'foo')
109
+ .then(() => z.getFile('foo'))
110
+ .then(
111
+ () => assert.fail('should have failed'),
112
+ e => assert.strictEqual(
113
+ e.constructor, InvalidArgumentError))
114
+ .then(() => z.getFile('foo/aFile'))
115
+ .then(b => assert.equal(b.toString('utf8'), 'hello, world!'));
116
+ });
117
+ });
118
+ });
119
+
120
+ function assertExists(p) {
121
+ assert.ok(fs.existsSync(p), `expected ${p} to exist`);
122
+ }
123
+
124
+ function assertContents(p, c) {
125
+ assert.strictEqual(
126
+ fs.readFileSync(p, 'utf8'), c, `unexpected file contents for ${p}`);
127
+ }
128
+ });
@@ -88,6 +88,27 @@ describe('by', function() {
88
88
  });
89
89
 
90
90
  describe('checkedLocator', function() {
91
+ it('accepts a By instance', function() {
92
+ let original = by.By.name('foo');
93
+ let locator = by.checkedLocator(original);
94
+ assert.strictEqual(locator, original);
95
+ });
96
+
97
+ it('accepts custom locator functions', function() {
98
+ let original = function() {};
99
+ let locator = by.checkedLocator(original);
100
+ assert.strictEqual(locator, original);
101
+ });
102
+
103
+ // See https://github.com/SeleniumHQ/selenium/issues/3056
104
+ it('accepts By-like objects', function() {
105
+ let fakeBy = {using: 'id', value: 'foo'};
106
+ let locator = by.checkedLocator(fakeBy);
107
+ assert.strictEqual(locator.constructor, by.By);
108
+ assert.equal(locator.using, 'id');
109
+ assert.equal(locator.value, 'foo');
110
+ });
111
+
91
112
  it('accepts class name', function() {
92
113
  let locator = by.checkedLocator({className: 'foo'});
93
114
  assert.equal('css selector', locator.using);
@@ -38,6 +38,7 @@ describe('error', function() {
38
38
  });
39
39
 
40
40
  test('unknown error', error.WebDriverError);
41
+ test('element not interactable', error.ElementNotInteractableError);
41
42
  test('element not selectable', error.ElementNotSelectableError);
42
43
  test('element not visible', error.ElementNotVisibleError);
43
44
  test('invalid argument', error.InvalidArgumentError);
@@ -187,13 +188,32 @@ describe('error', function() {
187
188
  test('unknown method', error.UnknownMethodError);
188
189
  test('unsupported operation', error.UnsupportedOperationError);
189
190
 
191
+ it('leaves remoteStacktrace empty if not in encoding', function() {
192
+ assert.throws(
193
+ () => error.throwDecodedError({
194
+ error: 'session not created',
195
+ message: 'oops'
196
+ }),
197
+ (e) => {
198
+ assert.strictEqual(e.constructor, error.SessionNotCreatedError);
199
+ assert.strictEqual(e.message, 'oops');
200
+ assert.strictEqual(e.remoteStacktrace, '');
201
+ return true;
202
+ });
203
+ });
204
+
190
205
  function test(status, expectedType) {
191
206
  it(`"${status}" => ${expectedType.name}`, function() {
192
207
  assert.throws(
193
- () => error.throwDecodedError({error: status, message: 'oops'}),
208
+ () => error.throwDecodedError({
209
+ error: status,
210
+ message: 'oops',
211
+ stacktrace: 'some-stacktrace'
212
+ }),
194
213
  (e) => {
195
214
  assert.strictEqual(e.constructor, expectedType);
196
215
  assert.strictEqual(e.message, 'oops');
216
+ assert.strictEqual(e.remoteStacktrace, 'some-stacktrace');
197
217
  return true;
198
218
  });
199
219
  });
@@ -293,7 +293,14 @@ describe('http', function() {
293
293
  });
294
294
 
295
295
  it('auto-upgrades on W3C response', function() {
296
- var rawResponse = {sessionId: 's123', value: {name: 'Bob'}};
296
+ let rawResponse = {
297
+ value: {
298
+ sessionId: 's123',
299
+ value: {
300
+ name: 'Bob'
301
+ }
302
+ }
303
+ };
297
304
 
298
305
  send.returns(Promise.resolve(
299
306
  new http.Response(200, {}, JSON.stringify(rawResponse))));
@@ -344,7 +351,8 @@ describe('http', function() {
344
351
  });
345
352
 
346
353
  it('handles w3c new session failures', function() {
347
- let rawResponse = {error: 'no such element', message: 'oops'};
354
+ let rawResponse =
355
+ {value: {error: 'no such element', message: 'oops'}};
348
356
 
349
357
  send.returns(Promise.resolve(
350
358
  new http.Response(500, {}, JSON.stringify(rawResponse))));
@@ -429,7 +437,7 @@ describe('http', function() {
429
437
  });
430
438
 
431
439
  it('does not auto-upgrade on W3C response', function() {
432
- var rawResponse = {sessionId: 's123', value: {name: 'Bob'}};
440
+ var rawResponse = {value: {sessionId: 's123', value: {name: 'Bob'}}};
433
441
 
434
442
  send.returns(Promise.resolve(
435
443
  new http.Response(200, {}, JSON.stringify(rawResponse))));