You are here

protected function WebTestBase::drupalPostForm in Drupal 8

Executes a form submission.

It will be done as usual POST request with SimpleBrowser.

Parameters

\Drupal\Core\Url|string $path: Location of the post form. Either a Drupal path or an absolute path or NULL to post to the current page. For multi-stage forms you can set the path to NULL and have it post to the last received page. Example:


  // First step in form.
  $edit = array(...);
  $this->drupalPostForm('some_url', $edit, t('Save'));

  // Second step in form.
  $edit = array(...);
  $this->drupalPostForm(NULL, $edit, t('Save'));
  

$edit: Field data in an associative array. Changes the current input fields (where possible) to the values indicated.

When working with form tests, the keys for an $edit element should match the 'name' parameter of the HTML of the form. For example, the 'body' field for a node has the following HTML:


  <textarea id="edit-body-und-0-value" class="text-full form-textarea
   resize-vertical" placeholder="" cols="60" rows="9"
   name="body[0][value]"></textarea>
  

When testing this field using an $edit parameter, the code becomes:

$edit["body[0][value]"] = 'My test value';

A checkbox can be set to TRUE to be checked and should be set to FALSE to be unchecked. Multiple select fields can be tested using 'name[]' and setting each of the desired values in an array:

$edit = array();
$edit['name[]'] = array(
  'value1',
  'value2',
);

$submit: Value of the submit button whose click is to be emulated. For example, t('Save'). The processing of the request depends on this value. For example, a form may have one button with the value t('Save') and another button with the value t('Delete'), and execute different code depending on which one is clicked.

This function can also be called to emulate an Ajax submission. In this case, this value needs to be an array with the following keys:

  • path: A path to submit the form values to for Ajax-specific processing.
  • triggering_element: If the value for the 'path' key is a generic Ajax processing path, this needs to be set to the name of the element. If the name doesn't identify the element uniquely, then this should instead be an array with a single key/value pair, corresponding to the element name and value. The \Drupal\Core\Form\FormAjaxResponseBuilder uses this to find the #ajax information for the element, including which specific callback to use for processing the request.

This can also be set to NULL in order to emulate an Internet Explorer submission of a form with a single text field, and pressing ENTER in that textfield: under these conditions, no button information is added to the POST data.

$options: Options to be forwarded to the url generator.

$headers: An array containing additional HTTP request headers, each formatted as "name: value".

$form_html_id: (optional) HTML ID of the form to be submitted. On some pages there are many identical forms, so just using the value of the submit button is not enough. For example: 'trigger-node-presave-assign-form'. Note that this is not the Drupal $form_id, but rather the HTML ID of the form, which is typically the same thing but with hyphens replacing the underscores.

$extra_post: (optional) A string of additional data to append to the POST submission. This can be used to add POST data for which there are no HTML fields, as is done by drupalPostAjaxForm(). This string is literally appended to the POST data, so it must already be urlencoded and contain a leading "&" (e.g., "&extra_var1=hello+world&extra_var2=you%26me").

32 calls to WebTestBase::drupalPostForm()
AggregatorTestBase::createFeed in core/modules/aggregator/src/Tests/AggregatorTestBase.php
Creates an aggregator feed.
AggregatorTestBase::createSampleNodes in core/modules/aggregator/src/Tests/AggregatorTestBase.php
Creates sample article nodes.
AggregatorTestBase::deleteFeed in core/modules/aggregator/src/Tests/AggregatorTestBase.php
Deletes an aggregator feed.
AggregatorTestBase::deleteFeedItems in core/modules/aggregator/src/Tests/AggregatorTestBase.php
Confirms an item removal from a feed.
BrokenSetUpTest::testMethod in core/modules/simpletest/src/Tests/BrokenSetUpTest.php
Runs this test case from within the simpletest child site.

... See full list

File

core/modules/simpletest/src/WebTestBase.php, line 971

Class

WebTestBase
Test case for typical Drupal tests.

Namespace

Drupal\simpletest

Code

protected function drupalPostForm($path, $edit, $submit, array $options = [], array $headers = [], $form_html_id = NULL, $extra_post = NULL) {
  if (is_object($submit)) {

    // Cast MarkupInterface objects to string.
    $submit = (string) $submit;
  }
  if (is_array($edit)) {
    $edit = $this
      ->castSafeStrings($edit);
  }
  $submit_matches = FALSE;
  $ajax = is_array($submit);
  if (isset($path)) {
    $this
      ->drupalGet($path, $options);
  }
  if ($this
    ->parse()) {
    $edit_save = $edit;

    // Let's iterate over all the forms.
    $xpath = "//form";
    if (!empty($form_html_id)) {
      $xpath .= "[@id='" . $form_html_id . "']";
    }
    $forms = $this
      ->xpath($xpath);
    foreach ($forms as $form) {

      // We try to set the fields of this form as specified in $edit.
      $edit = $edit_save;
      $post = [];
      $upload = [];
      $submit_matches = $this
        ->handleForm($post, $edit, $upload, $ajax ? NULL : $submit, $form);
      $action = isset($form['action']) ? $this
        ->getAbsoluteUrl((string) $form['action']) : $this
        ->getUrl();
      if ($ajax) {
        if (empty($submit['path'])) {
          throw new \Exception('No #ajax path specified.');
        }
        $action = $this
          ->getAbsoluteUrl($submit['path']);

        // Ajax callbacks verify the triggering element if necessary, so while
        // we may eventually want extra code that verifies it in the
        // handleForm() function, it's not currently a requirement.
        $submit_matches = TRUE;
      }

      // We post only if we managed to handle every field in edit and the
      // submit button matches.
      if (!$edit && ($submit_matches || !isset($submit))) {
        $post_array = $post;
        if ($upload) {
          foreach ($upload as $key => $file) {
            if (is_array($file) && count($file)) {

              // There seems to be no way via php's API to cURL to upload
              // several files with the same post field name. However, Drupal
              // still sees array-index syntax in a similar way.
              for ($i = 0; $i < count($file); $i++) {
                $postfield = str_replace('[]', '', $key) . '[' . $i . ']';
                $file_path = $this->container
                  ->get('file_system')
                  ->realpath($file[$i]);
                $post[$postfield] = curl_file_create($file_path);
              }
            }
            else {
              $file = $this->container
                ->get('file_system')
                ->realpath($file);
              if ($file && is_file($file)) {
                $post[$key] = curl_file_create($file);
              }
            }
          }
        }
        else {
          $post = $this
            ->serializePostValues($post) . $extra_post;
        }
        $out = $this
          ->curlExec([
          CURLOPT_URL => $action,
          CURLOPT_POST => TRUE,
          CURLOPT_POSTFIELDS => $post,
          CURLOPT_HTTPHEADER => $headers,
        ]);

        // Ensure that any changes to variables in the other thread are picked
        // up.
        $this
          ->refreshVariables();

        // Replace original page output with new output from redirected
        // page(s).
        if ($new = $this
          ->checkForMetaRefresh()) {
          $out = $new;
        }
        if ($path instanceof Url) {
          $path = $path
            ->toString();
        }
        $verbose = 'POST request to: ' . $path;
        $verbose .= '<hr />Ending URL: ' . $this
          ->getUrl();
        if ($this->dumpHeaders) {
          $verbose .= '<hr />Headers: <pre>' . Html::escape(var_export(array_map('trim', $this->headers), TRUE)) . '</pre>';
        }
        $verbose .= '<hr />Fields: ' . highlight_string('<?php ' . var_export($post_array, TRUE), TRUE);
        $verbose .= '<hr />' . $out;
        $this
          ->verbose($verbose);
        return $out;
      }
    }

    // We have not found a form which contained all fields of $edit.
    foreach ($edit as $name => $value) {
      $this
        ->fail(new FormattableMarkup('Failed to set field @name to @value', [
        '@name' => $name,
        '@value' => $value,
      ]));
    }
    if (!$ajax && isset($submit)) {
      $this
        ->assertTrue($submit_matches, new FormattableMarkup('Found the @submit button', [
        '@submit' => $submit,
      ]));
    }
    $this
      ->fail(new FormattableMarkup('Found the requested form fields at @path', [
      '@path' => $path instanceof Url ? $path
        ->toString() : $path,
    ]));
  }
}