Skip to content

Commit db63215

Browse files
committed
Add support for file uploads to webdriverjs
1 parent cc506f1 commit db63215

File tree

11 files changed

+277
-20
lines changed

11 files changed

+277
-20
lines changed

javascript/node/selenium-webdriver/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
necessary, so they have been made no-ops.
5656
* `WebDriver.wait()` may now be used to wait for a promise to resolve, with
5757
an optional timeout. Refer to the API documentation for more information.
58+
* Added support for copying files to a remote Selenium via `sendKeys` to test
59+
file uploads. Refer to the API documentation for more information. Sample
60+
usage included in `test/upload_test.js`
5861
* FIXED: 8380: `firefox.Driver` will delete its temporary profile on `quit`.
5962
* FIXED: 8306: Stack overflow in promise callbacks eliminated.
6063
* FIXED: 8221: Added support for defining custom command mappings. Includes

javascript/node/selenium-webdriver/chrome.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,15 @@ var Driver = function(opt_config, opt_service, opt_flow) {
502502
util.inherits(Driver, webdriver.WebDriver);
503503

504504

505+
/**
506+
* This function is a no-op as file detectors are not supported by this
507+
* implementation.
508+
* @override
509+
*/
510+
Driver.prototype.setFileDetector = function() {
511+
};
512+
513+
505514
// PUBLIC API
506515

507516

javascript/node/selenium-webdriver/firefox/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ var Driver = function(opt_config, opt_flow) {
199199
util.inherits(Driver, webdriver.WebDriver);
200200

201201

202+
/**
203+
* This function is a no-op as file detectors are not supported by this
204+
* implementation.
205+
* @override
206+
*/
207+
Driver.prototype.setFileDetector = function() {
208+
};
209+
210+
202211
/** @override */
203212
Driver.prototype.quit = function() {
204213
return this.call(function() {

javascript/node/selenium-webdriver/lib/test/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ function suite(fn, opt_options) {
184184

185185
if (!!serverJar && !remoteUrl) {
186186
if (!(serverToUse = seleniumServer)) {
187-
serverToUse = seleniumServer = new remote.SeleniumServer();
187+
serverToUse = seleniumServer = new remote.SeleniumServer(serverJar);
188188
}
189189

190190
testing.before(function() {

javascript/node/selenium-webdriver/phantomjs.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,15 @@ var Driver = function(opt_capabilities, opt_flow) {
214214
util.inherits(Driver, webdriver.WebDriver);
215215

216216

217+
/**
218+
* This function is a no-op as file detectors are not supported by this
219+
* implementation.
220+
* @override
221+
*/
222+
Driver.prototype.setFileDetector = function() {
223+
};
224+
225+
217226
/**
218227
* Executes a PhantomJS fragment. This method is similar to
219228
* {@link #executeScript}, except it exposes the

javascript/node/selenium-webdriver/remote/index.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@
1414

1515
'use strict';
1616

17-
var path = require('path'),
17+
var AdmZip = require('adm-zip'),
18+
fs = require('fs'),
19+
path = require('path'),
1820
url = require('url'),
1921
util = require('util');
2022

21-
var promise = require('../').promise,
23+
var _base = require('../_base'),
24+
webdriver = require('../'),
25+
promise = require('../').promise,
2226
httpUtil = require('../http/util'),
2327
exec = require('../io/exec'),
2428
net = require('../net'),
@@ -305,7 +309,40 @@ util.inherits(SeleniumServer, DriverService);
305309
SeleniumServer.Options;
306310

307311

312+
313+
/**
314+
* @constructor
315+
* @extends {webdriver.FileDetector}
316+
* @final
317+
*/
318+
var FileDetector = function() {};
319+
util.inherits(_base.require('webdriver.FileDetector'), FileDetector);
320+
321+
322+
/** @override */
323+
FileDetector.prototype.handleFile = function(driver, filePath) {
324+
return promise.checkedNodeCall(fs.stat, filePath).then(function(stats) {
325+
if (stats.isDirectory()) {
326+
throw TypeError('Uploading directories is not supported: ' + filePath);
327+
}
328+
329+
var zip = new AdmZip();
330+
zip.addLocalFile(filePath);
331+
332+
var command = new webdriver.Command(webdriver.CommandName.UPLOAD_FILE)
333+
.setParameter('file', zip.toBuffer().toString('base64'));
334+
return driver.schedule(command,
335+
'remote.FileDetector.handleFile(' + filePath + ')');
336+
}, function(err) {
337+
if (err.code === 'ENOENT') {
338+
return filePath; // Not a file; return original input.
339+
}
340+
throw err;
341+
});
342+
};
343+
308344
// PUBLIC API
309345

310346
exports.DriverService = DriverService;
347+
exports.FileDetector = FileDetector;
311348
exports.SeleniumServer = SeleniumServer;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2015 Selenium committers
2+
// Copyright 2015 Software Freedom Conservancy
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
'use strict';
17+
18+
var fs = require('fs');
19+
20+
var Browser = require('..').Browser,
21+
By = require('..').By,
22+
until = require('..').until,
23+
io = require('../io'),
24+
remote = require('../remote'),
25+
assert = require('../testing/assert'),
26+
test = require('../lib/test'),
27+
Pages = test.Pages;
28+
29+
test.suite(function(env) {
30+
var LOREM_IPSUM_TEXT = 'lorem ipsum dolor sit amet';
31+
var FILE_HTML = '<!DOCTYPE html><div>' + LOREM_IPSUM_TEXT + '</div>';
32+
33+
var fp;
34+
test.before(function() {
35+
return fp = io.tmpFile().then(function(fp) {
36+
fs.writeFileSync(fp, FILE_HTML);
37+
return fp;
38+
});
39+
})
40+
41+
var driver;
42+
test.before(function() {
43+
driver = env.builder().build();
44+
});
45+
46+
test.after(function() {
47+
driver.quit();
48+
});
49+
50+
test.ignore(env.browsers(
51+
Browser.IPAD, Browser.IPHONE,
52+
Browser.OPERA, Browser.SAFARI)).
53+
it('can upload files', function() {
54+
driver.setFileDetector(new remote.FileDetector);
55+
56+
driver.get(Pages.uploadPage);
57+
58+
var fp = driver.call(function() {
59+
return io.tmpFile().then(function(fp) {
60+
fs.writeFileSync(fp, FILE_HTML);
61+
return fp;
62+
});
63+
});
64+
65+
driver.findElement(By.id('upload')).sendKeys(fp);
66+
driver.findElement(By.id('go')).submit();
67+
68+
// Uploading files across a network may take a while, even if they're small.
69+
var label = driver.findElement(By.id('upload_label'));
70+
driver.wait(until.elementIsNotVisible(label),
71+
10 * 1000, 'File took longer than 10 seconds to upload!');
72+
73+
driver.switchTo().frame('upload_target');
74+
assert(driver.findElement(By.css('body')).getText())
75+
.equalTo(LOREM_IPSUM_TEXT);
76+
});
77+
});

javascript/webdriver/command.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,10 @@ webdriver.CommandName = {
216216

217217
GET_AVAILABLE_LOG_TYPES: 'getAvailableLogTypes',
218218
GET_LOG: 'getLog',
219-
GET_SESSION_LOGS: 'getSessionLogs'
219+
GET_SESSION_LOGS: 'getSessionLogs',
220+
221+
// Non-standard commands used by the standalone Selenium server.
222+
UPLOAD_FILE: 'uploadFile'
220223
};
221224

222225

javascript/webdriver/http/http.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ webdriver.http.Executor.COMMAND_MAP_ = (function() {
318318
put(webdriver.CommandName.GET_AVAILABLE_LOG_TYPES,
319319
get('/session/:sessionId/log/types')).
320320
put(webdriver.CommandName.GET_SESSION_LOGS, post('/logs')).
321+
put(webdriver.CommandName.UPLOAD_FILE, post('/session/:sessionId/file')).
321322
build();
322323

323324
/** @constructor */

javascript/webdriver/test/webdriver_test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ goog.require('webdriver.Capabilities');
2424
goog.require('webdriver.Command');
2525
goog.require('webdriver.CommandExecutor');
2626
goog.require('webdriver.CommandName');
27+
goog.require('webdriver.FileDetector');
2728
goog.require('webdriver.WebDriver');
2829
goog.require('webdriver.Serializable');
2930
goog.require('webdriver.Session');
@@ -1945,6 +1946,29 @@ function testSendKeysConvertsVarArgsIntoStrings_promisedArgs() {
19451946
return waitForIdle();
19461947
}
19471948

1949+
1950+
function testSendKeysWithAFileDetector() {
1951+
var testHelper = new TestHelper().
1952+
expect(CName.FIND_ELEMENT, {'using':'id', 'value':'foo'}).
1953+
andReturnSuccess({'ELEMENT':'one'}).
1954+
expect(CName.SEND_KEYS_TO_ELEMENT, {'id':{'ELEMENT':'one'},
1955+
'value':['modified/path']}).
1956+
andReturnSuccess().
1957+
replayAll();
1958+
1959+
var driver = testHelper.createDriver();
1960+
1961+
var mockDetector = mockControl.createStrictMock(webdriver.FileDetector);
1962+
mockDetector.handleFile(driver, 'original/path').
1963+
$returns(webdriver.promise.fulfilled('modified/path'));
1964+
mockDetector.$replay();
1965+
1966+
driver.setFileDetector(mockDetector);
1967+
1968+
var element = driver.findElement(By.id('foo'));
1969+
element.sendKeys('original/', 'path');
1970+
}
1971+
19481972
function testElementEquality_isReflexive() {
19491973
var a = new webdriver.WebElement(STUB_DRIVER, 'foo');
19501974
return webdriver.WebElement.equals(a, a).then(assertTrue);

0 commit comments

Comments
 (0)