OK sure
OK sure

Reputation: 2656

Behat Mink file upload not finding file on submit

I'm trying to test an image upload using Selenium/Mink with Behat in a Symfony application. The application is running in a Docker container.

I'm attaching the file directly to the NodeElement of the input rather than use $driver->attachFileToField('#id-of-input', $filePath) because we're dealing with a lot of inputs in the context and already have the input in the method being called:

$input->attachFile($this->filesPath . '1.jpg');

The resulting path is:

/var/www/html/src/Resources/TestImages/1.jpg

This file certainly exists at that path in the docker container but when the form is submitted, this error is thrown:

Your file was not found

There are no helpful logs.

I've tried setting the files_path parameter in behat.yml but then I get error during the test running:

unknown error: path is not absolute: 3.jpg

Am I missing something? Is that file path incorrect for the container?

I've tried using the abs path on my machine to no avail (though this approach has serious drawbacks so I'm glad it wasn't the solution):

/Users/its.me/Sites/kbs/src/Resources/TestImages/1.jpg

The local Users dir is mounted into my docker-machine too so that abs path works on the host. I thought it might be permissions related so I set them all to read/write/execute but no cigar! Relative paths don't work.

Where are my images?

Upvotes: 2

Views: 2745

Answers (3)

kenorb
kenorb

Reputation: 166457

Make sure to include files_path in your Behat.yml file under MinkExtension section, e.g.

default:
    extensions:
        Behat\MinkExtension\Extension:
            files_path: %behat.paths.base%/build/dummy/

Also make sure that you have the right folder structure, e.g.

# Your application
football
   build
      dummy
         document
            hello.doc
            world.xls
         image
            test.jpg

Example Behat Feature:

Feature: Example feature

  Scenario: I can upload image
    Given I am on "/"
    When I attach the file "image/test.jpg" to "league_flag"
    And I press "Submit"
    Then I should see "Succeeded."

Here is the actual MinkExtension built method:

/**
 * Attaches file to field with specified id|name|label|value
 * Example: When I attach "bwayne_profile.png" to "profileImageUpload"
 * Example: And I attach "bwayne_profile.png" to "profileImageUpload"
 *
 * @When /^(?:|I )attach the file "(?P<path>[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/
 */
public function attachFileToField($field, $path)
{
    $field = $this->fixStepArgument($field);
    if ($this->getMinkParameter('files_path')) {
        $fullPath = rtrim(realpath($this->getMinkParameter('files_path')), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$path;
        if (is_file($fullPath)) {
            $path = $fullPath;
        }
    }
    $this->getSession()->getPage()->attachFileToField($field, $path);
}

See: File uploading with Behat.

Upvotes: 1

OK sure
OK sure

Reputation: 2656

Based on the issue posted by @lauda at GitHub, the MinkSeleniumDriver needs some file preparation to work properly. Namely, turning it into a zip file. This comment helped:

$localFile = $this->filesPath . '01.jpg';
$tempZip = tempnam('', 'WebDriverZip');
$zip = new \ZipArchive();
$zip->open($tempZip, \ZipArchive::CREATE);
$zip->addFile($localFile, basename($localFile));
$zip->close();

$remotePath = $this->getSession()->getDriver()->getWebDriverSession()->file([
    'file' => base64_encode(file_get_contents($tempZip))
]);

$input->attachFile($remotePath);
unlink($tempZip);

The above code is based on the upload() method from facebook/php-webdriver:

 /**
   * Upload a local file to the server
   *
   * @param string $local_file
   *
   * @throws WebDriverException
   * @return string The remote path of the file.
   */
  private function upload($local_file) {
    if (!is_file($local_file)) {
      throw new WebDriverException("You may only upload files: " . $local_file);
    }
    // Create a temporary file in the system temp directory.
    $temp_zip = tempnam('', 'WebDriverZip');
    $zip = new ZipArchive();
    if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) {
      return false;
    }
    $info = pathinfo($local_file);
    $file_name = $info['basename'];
    $zip->addFile($local_file, $file_name);
    $zip->close();
    $params = array(
      'file' => base64_encode(file_get_contents($temp_zip)),
    );
    $remote_path = $this->executor->execute(
      DriverCommand::UPLOAD_FILE,
      $params
    );
    unlink($temp_zip);
    return $remote_path;
  }

Upvotes: 2

lauda
lauda

Reputation: 4173

Add the file in your behat directory and set files_path under Behat\MinkExtension\Extension:

The files_path should be something like: files_path: %behat.paths.features%/bootstrap

Upvotes: 1

Related Questions