selenium-webdriver 3.0.1 → 3.5.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 (67) hide show
  1. package/CHANGES.md +92 -0
  2. package/NOTICE +1 -1
  3. package/README.md +11 -14
  4. package/chrome.js +125 -36
  5. package/edge.js +3 -3
  6. package/example/async_await_test.js +68 -0
  7. package/example/chrome_headless.js +47 -0
  8. package/example/chrome_mobile_emulation.js +1 -1
  9. package/example/firefox_channels.js +73 -0
  10. package/example/google_search_test.js +1 -1
  11. package/firefox/binary.js +114 -57
  12. package/firefox/extension.js +118 -81
  13. package/firefox/index.js +67 -135
  14. package/firefox/profile.js +13 -49
  15. package/ie.js +2 -2
  16. package/index.js +6 -3
  17. package/io/index.js +59 -0
  18. package/io/zip.js +214 -0
  19. package/lib/README +2 -3
  20. package/lib/actions.js +4 -4
  21. package/lib/atoms/getAttribute.js +9 -11
  22. package/lib/atoms/is-displayed.js +102 -0
  23. package/lib/by.js +9 -1
  24. package/lib/capabilities.js +5 -5
  25. package/lib/command.js +2 -0
  26. package/lib/error.js +29 -4
  27. package/lib/events.js +1 -1
  28. package/lib/firefox/webdriver.json +2 -1
  29. package/lib/http.js +84 -69
  30. package/lib/input.js +1 -1
  31. package/lib/promise.js +205 -81
  32. package/lib/symbols.js +1 -1
  33. package/lib/test/data/click_tests/disabled_element.html +12 -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/single_text_input.html +12 -0
  38. package/lib/test/index.js +9 -35
  39. package/lib/until.js +1 -1
  40. package/lib/webdriver.js +130 -34
  41. package/net/portprober.js +1 -1
  42. package/opera.js +2 -2
  43. package/package.json +2 -2
  44. package/phantomjs.js +2 -2
  45. package/remote/index.js +17 -11
  46. package/safari.js +47 -8
  47. package/test/firefox/extension_test.js +41 -17
  48. package/test/firefox/firefox_test.js +70 -23
  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 +20 -1
  55. package/test/lib/http_test.js +41 -2
  56. package/test/lib/promise_test.js +19 -0
  57. package/test/lib/until_test.js +28 -13
  58. package/test/lib/webdriver_test.js +107 -3
  59. package/test/page_loading_test.js +0 -6
  60. package/test/rect_test.js +60 -0
  61. package/test/remote_test.js +3 -3
  62. package/test/session_test.js +68 -23
  63. package/testing/index.js +16 -5
  64. package/lib/atoms/isDisplayed.js +0 -106
  65. package/lib/firefox/amd64/libnoblur64.so +0 -0
  66. package/lib/firefox/i386/libnoblur.so +0 -0
  67. package/lib/firefox/webdriver.xpi +0 -0
package/safari.js CHANGED
@@ -68,7 +68,7 @@ class ServiceBuilder extends remote.DriverService.Builder {
68
68
 
69
69
 
70
70
  const OPTIONS_CAPABILITY_KEY = 'safari.options';
71
-
71
+ const TECHNOLOGY_PREVIEW_OPTIONS_KEY = 'technologyPreview';
72
72
 
73
73
  /**
74
74
  * Configuration options specific to the {@link Driver SafariDriver}.
@@ -89,16 +89,17 @@ class Options {
89
89
  * Extracts the SafariDriver specific options from the given capabilities
90
90
  * object.
91
91
  * @param {!Capabilities} capabilities The capabilities object.
92
- * @return {!Options} The ChromeDriver options.
92
+ * @return {!Options} The SafariDriver options.
93
93
  */
94
94
  static fromCapabilities(capabilities) {
95
95
  var options = new Options();
96
-
97
96
  var o = capabilities.get(OPTIONS_CAPABILITY_KEY);
97
+
98
98
  if (o instanceof Options) {
99
99
  options = o;
100
100
  } else if (o) {
101
101
  options.setCleanSession(o.cleanSession);
102
+ options.setTechnologyPreview(o[TECHNOLOGY_PREVIEW_OPTIONS_KEY]);
102
103
  }
103
104
 
104
105
  if (capabilities.has(Capability.PROXY)) {
@@ -148,6 +149,22 @@ class Options {
148
149
  return this;
149
150
  }
150
151
 
152
+ /**
153
+ * Instruct the SafariDriver to use the Safari Technology Preview if true.
154
+ * Otherwise, use the release version of Safari. Defaults to using the release version of Safari.
155
+ *
156
+ * @param {boolean} useTechnologyPreview
157
+ * @return {!Options} A self reference.
158
+ */
159
+ setTechnologyPreview(useTechnologyPreview) {
160
+ if (!this.options_) {
161
+ this.options_ = {};
162
+ }
163
+
164
+ this.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY] = !!useTechnologyPreview;
165
+ return this;
166
+ }
167
+
151
168
  /**
152
169
  * Converts this options instance to a {@link Capabilities} object.
153
170
  * @param {Capabilities=} opt_capabilities The capabilities to
@@ -179,6 +196,23 @@ class Options {
179
196
  }
180
197
  }
181
198
 
199
+ /**
200
+ * @param {(Options|Object<string, *>)=} o The options object
201
+ * @return {boolean}
202
+ */
203
+ function useTechnologyPreview(o) {
204
+ if (o instanceof Options) {
205
+ return !!(o.options_ && o.options_[TECHNOLOGY_PREVIEW_OPTIONS_KEY]);
206
+ }
207
+
208
+ if (o && typeof o === 'object') {
209
+ return !!o[TECHNOLOGY_PREVIEW_OPTIONS_KEY];
210
+ }
211
+
212
+ return false;
213
+ }
214
+
215
+ const SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE = '/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver';
182
216
 
183
217
  /**
184
218
  * A WebDriver client for Safari. This class should never be instantiated
@@ -200,19 +234,24 @@ class Driver extends webdriver.WebDriver {
200
234
  * @return {!Driver} A new driver instance.
201
235
  */
202
236
  static createSession(opt_config, opt_flow) {
203
- let caps;
237
+ let caps, exe;
238
+
204
239
  if (opt_config instanceof Options) {
205
240
  caps = opt_config.toCapabilities();
206
241
  } else {
207
- caps = opt_config || Capabilities.safari()
242
+ caps = opt_config || Capabilities.safari();
243
+ }
244
+
245
+ if (useTechnologyPreview(caps.get(OPTIONS_CAPABILITY_KEY))) {
246
+ exe = SAFARIDRIVER_TECHNOLOGY_PREVIEW_EXE;
208
247
  }
209
248
 
210
- let service = new ServiceBuilder().build();
249
+ let service = new ServiceBuilder(exe).build();
211
250
  let executor = new http.Executor(
212
251
  service.start().then(url => new http.HttpClient(url)));
213
252
 
214
- return /** @type {!Driver} */(webdriver.WebDriver.createSession(
215
- executor, caps, opt_flow, this, () => service.kill()));
253
+ return /** @type {!Driver} */(super.createSession(
254
+ executor, caps, opt_flow, () => service.kill()));
216
255
  }
217
256
  }
218
257
 
@@ -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
  });
@@ -26,23 +26,27 @@ var firefox = require('../../firefox'),
26
26
  Context = require('../../firefox').Context,
27
27
  error = require('../..').error;
28
28
 
29
+ var {consume} = require('../../lib/promise');
30
+
29
31
 
30
32
  var JETPACK_EXTENSION = path.join(__dirname,
31
33
  '../../lib/test/data/firefox/jetpack-sample.xpi');
32
34
  var NORMAL_EXTENSION = path.join(__dirname,
33
35
  '../../lib/test/data/firefox/sample.xpi');
36
+ var WEBEXTENSION_EXTENSION = path.join(__dirname,
37
+ '../../lib/test/data/firefox/webextension.xpi');
34
38
 
35
39
 
36
40
  test.suite(function(env) {
37
41
  describe('firefox', function() {
38
42
  describe('Options', function() {
39
- var driver;
43
+ let driver;
40
44
 
41
- test.beforeEach(function() {
45
+ beforeEach(function() {
42
46
  driver = null;
43
47
  });
44
48
 
45
- test.afterEach(function() {
49
+ afterEach(function() {
46
50
  if (driver) {
47
51
  return driver.quit();
48
52
  }
@@ -53,9 +57,7 @@ test.suite(function(env) {
53
57
  * skipped if dev cannot be found on the current system.
54
58
  */
55
59
  function runWithFirefoxDev(options, testFn) {
56
- let binary = new firefox.Binary();
57
- binary.useDevEdition();
58
- return binary.locate().then(exe => {
60
+ return firefox.Channel.AURORA.locate().then(exe => {
59
61
  options.setBinary(exe);
60
62
  driver = env.builder()
61
63
  .setFirefoxOptions(options)
@@ -67,21 +69,33 @@ test.suite(function(env) {
67
69
  });
68
70
  }
69
71
 
70
- test.it('can start Firefox with custom preferences', function*() {
71
- var profile = new firefox.Profile();
72
- profile.setPreference('general.useragent.override', 'foo;bar');
72
+ describe('can start Firefox with custom preferences', function() {
73
+ function runTest(opt_dir) {
74
+ return consume(function*() {
75
+ let profile = new firefox.Profile(opt_dir);
76
+ profile.setPreference('general.useragent.override', 'foo;bar');
73
77
 
74
- var options = new firefox.Options().setProfile(profile);
78
+ let options = new firefox.Options().setProfile(profile);
75
79
 
76
- driver = env.builder().
77
- setFirefoxOptions(options).
78
- build();
80
+ driver = env.builder().
81
+ setFirefoxOptions(options).
82
+ build();
79
83
 
80
- yield driver.get('data:text/html,<html><div>content</div></html>');
84
+ yield driver.get('data:text/html,<html><div>content</div></html>');
85
+
86
+ var userAgent = yield driver.executeScript(
87
+ 'return window.navigator.userAgent');
88
+ assert(userAgent).equalTo('foo;bar');
89
+ });
90
+ }
91
+
92
+ test.it('profile created from scratch', function() {
93
+ return runTest();
94
+ });
81
95
 
82
- var userAgent = yield driver.executeScript(
83
- 'return window.navigator.userAgent');
84
- assert(userAgent).equalTo('foo;bar');
96
+ test.it('profile created from template', function() {
97
+ return io.tmpDir().then(runTest);
98
+ });
85
99
  });
86
100
 
87
101
  test.it('can start Firefox with a jetpack extension', function() {
@@ -116,6 +130,22 @@ test.suite(function(env) {
116
130
  });
117
131
  });
118
132
 
133
+ test.it('can start Firefox with a webextension extension', function() {
134
+ let profile = new firefox.Profile();
135
+ profile.addExtension(WEBEXTENSION_EXTENSION);
136
+
137
+ let options = new firefox.Options().setProfile(profile);
138
+
139
+ return runWithFirefoxDev(options, function*() {
140
+ yield driver.get(test.Pages.echoPage);
141
+
142
+ let footer =
143
+ yield driver.findElement({id: 'webextensions-selenium-example'});
144
+ let text = yield footer.getText();
145
+ assert(text).equalTo('Content injected by webextensions-selenium-example');
146
+ });
147
+ });
148
+
119
149
  test.it('can start Firefox with multiple extensions', function() {
120
150
  let profile = new firefox.Profile();
121
151
  profile.addExtension(JETPACK_EXTENSION);
@@ -138,6 +168,26 @@ test.suite(function(env) {
138
168
  });
139
169
  });
140
170
 
171
+ test.it('can be used alongside preset capabilities', function*() {
172
+ let binary = yield firefox.Channel.AURORA.locate();
173
+
174
+ let profile = new firefox.Profile();
175
+ profile.addExtension(JETPACK_EXTENSION);
176
+ profile.setPreference('general.useragent.override', 'foo;bar');
177
+
178
+ driver = yield env.builder()
179
+ .withCapabilities({'moz:firefoxOptions': {binary}})
180
+ .setFirefoxOptions(new firefox.Options().setProfile(profile))
181
+ .build();
182
+
183
+ yield loadJetpackPage(driver,
184
+ 'data:text/html;charset=UTF-8,<html><div>content</div></html>');
185
+
186
+ let text =
187
+ yield driver.findElement({id: 'jetpack-sample-banner'}).getText();
188
+ assert(text).equalTo('Hello, world!');
189
+ });
190
+
141
191
  function loadJetpackPage(driver, url) {
142
192
  // On linux the jetpack extension does not always run the first time
143
193
  // we load a page. If this happens, just reload the page (a simple
@@ -186,13 +236,11 @@ test.suite(function(env) {
186
236
  }
187
237
  });
188
238
 
189
- test.ignore(() => !env.isMarionette).
190
- it('can get context', function() {
239
+ test.it('can get context', function() {
191
240
  return assert(driver.getContext()).equalTo(Context.CONTENT);
192
241
  });
193
242
 
194
- test.ignore(() => !env.isMarionette).
195
- it('can set context', function*() {
243
+ test.it('can set context', function*() {
196
244
  yield driver.setContext(Context.CHROME);
197
245
  let ctxt = yield driver.getContext();
198
246
  assert(ctxt).equalTo(Context.CHROME);
@@ -202,8 +250,7 @@ test.suite(function(env) {
202
250
  assert(ctxt).equalTo(Context.CONTENT);
203
251
  });
204
252
 
205
- test.ignore(() => !env.isMarionette).
206
- it('throws on unknown context', function() {
253
+ test.it('throws on unknown context', function() {
207
254
  return driver.setContext("foo").then(assert.fail, function(e) {
208
255
  assert(e).instanceOf(error.InvalidArgumentError);
209
256
  });
@@ -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
  });