Skip to content

Instantly share code, notes, and snippets.

@Bunk
Created November 21, 2017 21:45
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save Bunk/6c384fbe15556f7702d32aa8aa7a7521 to your computer and use it in GitHub Desktop.
Save Bunk/6c384fbe15556f7702d32aa8aa7a7521 to your computer and use it in GitHub Desktop.
Nightwatch — Upload local files to remote selenium grid
const path = require('path')
const util = require('util')
const events = require('events')
const archiver = require('archiver')
const handleResult = cb => result => {
if (result.status !== 0) throw new Error(result.value.message)
cb(result.value)
}
function uploadLocalFile () { events.EventEmitter.call(this) }
util.inherits(uploadLocalFile, events.EventEmitter)
/**
* uploadLocalFile is responsible for using webdriver protocol to upload a local
* file to a remote Selenium server for use in testing uploads.
*
* @argument filePath Local path to the file used for uploading
* @argument inputSelector Input selector for the file input to upload with
*/
uploadLocalFile.prototype.command = function uploadLocalFile (filePath, inputSelector) {
const self = this
const Nightwatch = this.client
const api = this.api
const uploadRemote = cb => {
let buffers = []
let zip = archiver('zip')
zip
.on('data', data => { buffers.push(data) })
.on('error', err => { throw err })
.on('finish', () => {
const file = Buffer.concat(buffers).toString('base64')
api.session(session => {
const opt = {
path: `/session/${session.sessionId}/file`,
method: 'POST',
data: { file }
}
Nightwatch.runProtocolAction(opt, handleResult(cb)).send()
})
})
const name = path.basename(filePath)
zip.file(filePath, { name })
zip.finalize()
}
uploadRemote(tempUrl => {
api.setValue(inputSelector, tempUrl, () => self.emit('complete'))
})
return self
}
module.exports = uploadLocalFile
@RomLAURENT
Copy link

Hello,
you save me a lot of time!
I exchanged arguments (filePath, inputSelector) to comply with the core commands.

Thank you very much.

@wixyvir
Copy link

wixyvir commented Dec 14, 2017

Thanks a lot

@abyBaby05
Copy link

Hi,
Where is the file, that is being uploaded, originally downloaded from?
Can you please provide a sample to use the above utility?
Thanks,
Abe

@Sraleik
Copy link

Sraleik commented Mar 27, 2018

Works perfectly
Thank you so much !

@unlok
Copy link

unlok commented Apr 18, 2018

Thank you!!!

@santhoshrenga
Copy link

santhoshrenga commented Apr 24, 2018

how can I use this function to Nightwatch page object? It's the correct way to put into globals.js or could you guys give the example?

@uofmmike
Copy link

To answer the above from @santhoshrenga

We set our paths in our nightwatch config to:

  src_folders: ["e2e/tests"],
  page_objects_path: ["e2e/pages"],
  globals_path: "./e2e/globals.js",
  custom_commands_path: "e2e/custom_commands",

and the custom commands directory to be roughly like this:

e2e
--custom_commands
-- --uploadLocalFile.js

Shoutout to @kxhsing for finding and crushing this one, and obviously @Bunk for the initial build!

@atrunelle
Copy link

It worth noting it doesn't work with version 1 and above. Nightwatch.runProtocolAction doesn't exist anymore. It took me a while to realise it wasn't working for because of the version.

@omicollier
Copy link

omicollier commented Jan 11, 2019

Hello, is there way to make it work for version 1?

@straris
Copy link

straris commented Jan 28, 2019

@atrunelle looks like Nightwatch.runProtocolAction still exists but it now implements promises, forked the repository to make it work with v1.
@omicollier there is :)
https://gist.github.com/straris/a940bd27959b38775042f9a1b2ca58ca

@omicollier
Copy link

@straris that's awesome, thank you!

@GerryFudd
Copy link

I adapted the above snippet to work with the new API for runProtocolAction. Line 40 should now be:

          Nightwatch.transport.runProtocolAction(opt).then(handleResult(cb))

Copy link

ghost commented Oct 3, 2019

@uofmmike and @santhoshrenga

To answer the above from @santhoshrenga

We set our paths in our nightwatch config to:

  src_folders: ["e2e/tests"],
  page_objects_path: ["e2e/pages"],
  globals_path: "./e2e/globals.js",
  custom_commands_path: "e2e/custom_commands",

and the custom commands directory to be roughly like this:

e2e
--custom_commands
-- --uploadLocalFile.js

Need help on Implementing this in the code any sample/example code for the usage will be helpful

@santhoshrenga
Copy link

@vinodryaka use the following line into your script,

browser.uploadLocalFile(path.resolve('path'), "input[type='file']");

Copy link

ghost commented Oct 3, 2019

@santhoshrenga pls help me
Error: There was an error while trying to load the file uploadLocalFile.js: Cannot find module 'archiver'

@santhoshrenga
Copy link

use npm install archiver

@DineshChopra
Copy link

DineshChopra commented Apr 15, 2020

Hi, I also use same code. Its working fine for chrome, but for Firefox its not working
When I try to log session object value at line 34 it gives me something like that
{ status: -1, value: 'HTTP method not allowed', errorStatus: -1, error: 'An unknown error has occurred.', httpStatusCode: 405 }

So session.sessionId become undefined and end to end test case gets failed.

I try to upload file on SauceLab environment.

@rosariosm
Copy link

@DineshChopra to make it working in Firefox I removed the session callback (line 34) and used api.sessionId directly:

.on('finish', async () => {
  const file = Buffer.concat(buffers).toString('base64');

  const opt = {
    path: `/session/${api.sessionId}/file`,
    method: 'POST',
    data: { file },
  };

  Nightwatch.transport.runProtocolAction(opt).then(handleResult(cb));
});

@vkrish40
Copy link

@rosariosm still not working for me for firefox. Working fine for chrome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment