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.
- package/CHANGES.md +112 -0
- package/NOTICE +1 -1
- package/README.md +5 -11
- package/chrome.js +122 -33
- package/edge.js +2 -2
- package/example/async_await_test.js +69 -0
- package/example/chrome_android.js +2 -3
- package/example/chrome_mobile_emulation.js +3 -4
- package/example/firefox_channels.js +3 -3
- package/example/google_search.js +3 -3
- package/example/google_search_generator.js +2 -5
- package/example/google_search_test.js +5 -6
- package/example/headless.js +55 -0
- package/example/logging.js +3 -3
- package/example/parallel_flows.js +4 -7
- package/firefox/binary.js +3 -0
- package/firefox/extension.js +118 -81
- package/firefox/index.js +117 -263
- package/firefox/profile.js +18 -137
- package/ie.js +2 -2
- package/index.js +4 -1
- package/io/index.js +59 -0
- package/io/zip.js +214 -0
- package/lib/atoms/get-attribute.js +9 -0
- package/lib/atoms/is-displayed.js +73 -78
- package/lib/by.js +8 -0
- package/lib/capabilities.js +61 -22
- package/lib/command.js +2 -0
- package/lib/error.js +32 -2
- package/lib/http.js +53 -44
- package/lib/promise.js +72 -25
- package/lib/test/data/click_tests/disabled_element.html +12 -0
- package/lib/test/data/content-editable.html +10 -0
- package/lib/test/data/firefox/webextension.xpi +0 -0
- package/lib/test/data/key_logger.html +34 -0
- package/lib/test/data/nestedElements.html +10 -1
- package/lib/test/data/scrolling_tests/page_with_partially_hidden_element.html +14 -0
- package/lib/test/data/single_text_input.html +12 -0
- package/lib/test/index.js +4 -36
- package/lib/webdriver.js +147 -55
- package/net/portprober.js +1 -1
- package/opera.js +1 -1
- package/package.json +2 -2
- package/phantomjs.js +2 -2
- package/remote/index.js +21 -14
- package/safari.js +2 -2
- package/test/firefox/extension_test.js +41 -17
- package/test/firefox/firefox_test.js +37 -19
- package/test/firefox/profile_test.js +14 -59
- package/test/http/http_test.js +18 -0
- package/test/{io_test.js → io/io_test.js} +40 -1
- package/test/io/zip_test.js +128 -0
- package/test/lib/by_test.js +21 -0
- package/test/lib/error_test.js +21 -1
- package/test/lib/http_test.js +11 -3
- package/test/lib/webdriver_test.js +107 -3
- package/test/page_loading_test.js +0 -6
- package/test/remote_test.js +3 -3
- package/test/session_test.js +68 -23
- package/testing/index.js +2 -3
- package/lib/atoms/getAttribute.js +0 -12
- package/lib/firefox/amd64/libnoblur64.so +0 -0
- package/lib/firefox/i386/libnoblur.so +0 -0
- package/lib/firefox/webdriver.json +0 -69
- package/lib/firefox/webdriver.xpi +0 -0
|
@@ -17,24 +17,27 @@
|
|
|
17
17
|
|
|
18
18
|
'use strict';
|
|
19
19
|
|
|
20
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
43
|
+
let driver;
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
beforeEach(function() {
|
|
44
46
|
driver = null;
|
|
45
47
|
});
|
|
46
48
|
|
|
47
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
132
|
-
let profile =
|
|
133
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
});
|
package/test/http/http_test.js
CHANGED
|
@@ -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('
|
|
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
|
+
});
|
package/test/lib/by_test.js
CHANGED
|
@@ -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);
|
package/test/lib/error_test.js
CHANGED
|
@@ -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({
|
|
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
|
});
|
package/test/lib/http_test.js
CHANGED
|
@@ -293,7 +293,14 @@ describe('http', function() {
|
|
|
293
293
|
});
|
|
294
294
|
|
|
295
295
|
it('auto-upgrades on W3C response', function() {
|
|
296
|
-
|
|
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 =
|
|
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))));
|