Simon

Testing image and file fields with Behat

Behat has become one of the most popular integration testing libraries for Drupal, thanks in no small part to the Drupal Behat Extension. This extensions Drupal API driver provides helpful steps such as:

Scenario: Create and view a node with fields
    Given I am viewing an "Article" content:
    | title | My article with fields! |
    | body  | A placeholder           |

These allow you to quickly create nodes for testing. However what if you want to create a node that has an image field? It’s possible to specify a file fields value the same way as a text field:

Scenario: Create and view a node with fields
   Given I am viewing an "Article" content:
  | title | My article with fields! |
  | body | A placeholder |
  | field_image | rabbit.jpg |

However that won’t work as the API driver is expecting a file id, not the name of a file. To get around this you can use the @beforeNodeCreate hook, this hook allows you to modify a nodes values before it gets sent to be created. So this way we are able to create a file based on a provided file name and path and send the file id through to node creation. See below for an example Scenario and the full step function:

Scenario: View a blog post
Given I am an anonymous user And I am viewing a 'post' content:
| title | Test post one |
| body | Test post one body content |
| field_background_image | file;tests/files/black_rabbit.jpg;black_rabbit.jpg
| Then I should see "Test post one"
And I should see "Test post one body content"
Then the ".main-page-content" element should contain "/sites/default/files/black_rabbit.jpg"
/**
 * Before nodeCreate check field value for file, if present create file and replace with fid
 * Field should be in format 'file;__file_source__;__file_name_
 * @beforeNodeCreate
 */
public function nodeCreateAlter(EntityScope $scope) {
 $node = $scope->getEntity();
 foreach ($node as $key => $value) {
 if (strpos($value, 'file;') !== FALSE) {
  $file_info = explode(';', $value);
  $file_source = $file_info[1];
  $file_name = $file_info[2];
  $uri = file_unmanaged_copy($file_source, "public://$file_name", FILE_EXISTS_REPLACE);
  $file = \Drupal\file\Entity\File::create(['uri' => $uri]);
  $file->save();
  $fid = $file->id();
  $node->$key = $fid;
 }
}
}

You can find the full context file as well as behat.yml here.