nightwatchjs / nightwatch

Integrated end-to-end testing framework written in Node.js and using W3C Webdriver API. Developed at @browserstack
https://nightwatchjs.org
MIT License
11.85k stars 1.35k forks source link

File Upload with Selenium Grid #890

Open scrawfor opened 8 years ago

scrawfor commented 8 years ago

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.

scrawfor commented 8 years ago

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 );

    };
straris commented 8 years ago

protractor implemented setFileDetector :(

scrawfor commented 8 years ago

@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.

straris commented 8 years ago

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

scrawfor commented 8 years ago

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.

straris commented 8 years ago

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.' }

scrawfor commented 8 years ago

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.
straris commented 8 years ago

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

straris commented 8 years ago

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

scrawfor commented 8 years ago

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

straris commented 8 years ago

@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?

scrawfor commented 8 years ago

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?

straris commented 8 years ago

thank you for the explanation! will give it a try

nareng commented 7 years ago

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

mdharamadas commented 7 years ago

+1 we are blocked on this.

jakejuby commented 7 years ago

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

MHenley commented 7 years ago

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.

Bunk commented 7 years ago

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

ConnorStroomberg commented 6 years ago

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)

`

drussell13 commented 5 years ago

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

DylanLacey commented 5 years ago

@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.

benjy commented 5 years ago

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

RohanImmanuel commented 4 years ago

Created a custom command for v1.4 https://github.com/RohanImmanuel/NightwatchJS-Remote-File-Upload

tim-yao commented 2 years ago

For anyone before V2 has this issue. Maybe this will help you to bypass the issue: https://www.browserstack.com/docs/automate/selenium/test-file-upload#uploading-pre-loaded-files

BTW, none of above custom commands work for me. I guess the API has changed.