Nightwatch: File Upload with Selenium Grid

Created on 7 Mar 2016  路  23Comments  路  Source: nightwatchjs/nightwatch

Is it now possible to implement file uploading using LocalFileDetector?

After some quick googling I found this. But I'm not familiar enough with the selenium project to node if it has any true impact.

This issue provide a method for uploading files and it works locally, but fails when using selenium grid as the remote node is unaware of the local file.

enhancement

Most helpful comment

I created a custom command that will perform the upload without having to clone the repo if anyone else is interested: https://gist.github.com/Bunk/6c384fbe15556f7702d32aa8aa7a7521

All 23 comments

I looked through the implementation in the WebDriverJS Bindings.

Based on that, I implemented a custom action in protocol.js which uploads the file and returns the remote path. But it does not provide the other piece of functionality ("Replacing local path with remote path automatically").

    /**
     * Uploads a file to the remote server, returning the path to the remote file.
     * 
     * @param  {[String]} file The path to the file.
     * @param  {Function} [callback] Optional callback function to be called when the command finishes.
     * @return {[String]}  The path to the file on the remote server.
     */
    Actions.uploadFileToSeleniumServer = function( filePath, callback ) {
        //TODO Validate the file.
        var AdmZip = require('adm-zip');

        var zip = new AdmZip();
        zip.addLocalFile(filePath);

        return postRequest( '/file', { file : zip.toBuffer().toString('base64') }, callback );

    };

protractor implemented setFileDetector :(

@straris The custom action I posted seems to work pretty well. We are running a private forked version of nightwatch with this change and haven't had any failures.

Thank you @scrawfor
How do you actually use your custom command?
I am getting postRequest is not defined

You would need to fork the repository and add the command to protocol.js.

You could then use it like any standard nightwatch action. Personally I defined a custom command which looks something like this:

exports.command = function (localFilepath, callback) {
    var browser = this;

    // First upload the file to the selenium server. This allows our code to work with selenium grid.
    browser.uploadFileToSeleniumServer(localFilepath, function (result) {

        if (result.status === -1) {
            console.error(result);
            return;
        }

        // Extract the new remote path of the file
        var remotePath = result.value || "";

        // Now, begin uploading the file to the website being tested.
        browser.setValue("#someInput", remotePath, function () {

          // Upload started, continue code.  Wait for upload complete if necessary.
          callback();

        });

    });

    return this; // allows the command to be chained.
};

I should create a PR for this but I haven't had the chance yet.

Thank you for that @scrawfor
Next error would be:
{ status: -1, value: { localizedMessage: 'invalid code lengths set', cause: null, suppressed: [], message: 'invalid code lengths set', hCode: 1876464331, class: 'java.util.zip.ZipException', screen: null }, errorStatus: 13, error: 'An unknown server-side error occurred while processing the command.' }

I don't think I have run into that issue. Seems like the zip file you are sending is corrupt in some way.

  1. How are you calling the custom command? Are you sure the file exists on the machine you are running nightwatch on?
  2. Try to zip the same file in some scratch code, but just save the zip file to the disk. Then try to unzip it.

ok, this helped me out:
https://github.com/SeleniumHQ/selenium/issues/640

It seems to be a problem with adm-zip, I replaced it with archiver and it worked

@scrawfor How would you send a file without compressing it?

As far as I know you have to zip the file since that is expected by the server. Is that causing issues for you?

@scrawfor problem is that the file is being uploaded as a zip and in my case the test fails because the website expects an image file, should the server unzip it?

Yeah the server should unzip it. My guess is the file isn't being properly zipped, or you've got some other issues going on. Maybe try running the job locally or on another server?

thank you for the explanation! will give it a try

@scrawfor thanks this works for me are these changes merged to the master?

+1 we are blocked on this.

+1 as well, would be great to have this.

I've had to fork nightwatch and pull in the the above protocal.js changes and usage example, but this is working for us as well.

I created a custom command that will perform the upload without having to clone the repo if anyone else is interested: https://gist.github.com/Bunk/6c384fbe15556f7702d32aa8aa7a7521

The custom command work great for running the tests on sauselabs, i only have a problem when i try to run the test using the safari browser ( both locally and via sauslabs).

I posted the error message below, any ideas on how i should go about fixing this ?

`Error processing the server response:



Error 500 Server Error

HTTP ERROR 500


Problem accessing /wd/hub/session/undefined/file. Reason:

    Server Error

Caused by:

org.openqa.selenium.injector.UnableToInstaniateInstanceException: Unable to find required matches for constructor of: class org.openqa.selenium.remote.server.commandhandler.UploadFile
        at org.openqa.selenium.injector.Injector.newInstance(Injector.java:81)
        at org.openqa.selenium.remote.server.AllHandlers.lambda$handler$3(AllHandlers.java:139)
        at org.openqa.selenium.remote.server.AllHandlers.lambda$match$0(AllHandlers.java:87)
        at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        at java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:958)
        at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
        at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
        at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
        at org.openqa.selenium.remote.server.AllHandlers.match(AllHandlers.java:89)
        at org.openqa.selenium.remote.server.WebDriverServlet.handle(WebDriverServlet.java:210)
        at org.openqa.selenium.remote.server.WebDriverServlet.doPost(WebDriverServlet.java:169)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at org.openqa.selenium.remote.server.WebDriverServlet.service(WebDriverServlet.java:129)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.seleniumhq.jetty9.servlet.ServletHolder.handle(ServletHolder.java:860)
        at org.seleniumhq.jetty9.servlet.ServletHandler.doHandle(ServletHandler.java:535)
        at org.seleniumhq.jetty9.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.seleniumhq.jetty9.security.SecurityHandler.handle(SecurityHandler.java:548)
        at org.seleniumhq.jetty9.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.seleniumhq.jetty9.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
        at org.seleniumhq.jetty9.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
        at org.seleniumhq.jetty9.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
        at org.seleniumhq.jetty9.servlet.ServletHandler.doScope(ServletHandler.java:473)
        at org.seleniumhq.jetty9.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
        at org.seleniumhq.jetty9.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
        at org.seleniumhq.jetty9.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.seleniumhq.jetty9.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
        at org.seleniumhq.jetty9.server.Server.handle(Server.java:530)
        at org.seleniumhq.jetty9.server.HttpChannel.handle(HttpChannel.java:347)
        at org.seleniumhq.jetty9.server.HttpConnection.onFillable(HttpConnection.java:256)
        at org.seleniumhq.jetty9.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
        at org.seleniumhq.jetty9.io.FillInterest.fillable(FillInterest.java:102)
        at org.seleniumhq.jetty9.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
        at org.seleniumhq.jetty9.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
        at org.seleniumhq.jetty9.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
        at org.seleniumhq.jetty9.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
        at org.seleniumhq.jetty9.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:382)
        at org.seleniumhq.jetty9.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)
        at org.seleniumhq.jetty9.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)
        at java.lang.Thread.run(Thread.java:748)


`

@ConnorStroomberg did you end up solving what caused this issue? I am having a similar problem

@ConnorStroomberg What version of Safari? I wonder if this is a problem with the new WebDriver implementation... Or the Older one, which didn't support remote file uploads at all.

@Bunk Do you have an updated version of that gist, it no longer seems to work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sgleonardoopitz picture sgleonardoopitz  路  3Comments

manjero picture manjero  路  4Comments

danielbentov picture danielbentov  路  4Comments

betweenbrain picture betweenbrain  路  4Comments

bushev picture bushev  路  4Comments