phpbehat

How to replace URL and pass data in behat


I'm just learning behat so apologies if this is pretty basic. I have scenarios like this:

Scenario: Create Task
    Given I have the JSON payload:
    """
    {
            "task_list_id" : 3,
            "title" : "From Behat",
            "display_order" : 1
    }
    """
    When I send a POST request to task
    Then one SQL ident is created

Scenario: Get the Task
  When I send a GET request to "tasklist/{id}/tasks"
  Then The response code should be 200
  And The response content type should be "application/json"

So the first scenario makes the connection and then JSON comes back with an integer value. I now want that value to be substituted into the next scenario where the URL has the {id} placeholder.

I tried setting $this->output to the body (the returned integer) in the FeatureContext.php file for the first scenario, and then did a preg_replace in the second to change {id} to the integer. It appears that when the second scenario is run the output is blanked out before that scenario is called.

These are my context methods for the above:

  /**
   * @Then One SQL ident is created
   */
  public function theResponseBodyShouldBeAnInteger() {
    $this->theResponseContentTypeShouldBe('application/json');
    $this->theResponseCodeShouldBe(201);

      $body = $this->response->getBody()->getContents();
    if (!ctype_digit($body)) {
            throw New Exception(sprintf('Expected integer response but got "%s".', $body));
    }

    $this->output = $body;
    echo "Output is '$this->output'\n";
  }

  /**
   * @When I send a :method request to :uri
   *
   * @param $method
   * @param $uri
   */
  public function iSendARequestTo($method, $uri)
  {
    echo "Output is '$this->output'\n";
    $uri = str_replace('{id}', $this->output, $uri);

    try {
            if ($method == 'POST' || $method == 'PATCH') {
                    $this->response = $this->client->request($method, $uri, ['json' => $this->requestPayload]);
            } else {
                    $this->response = $this->client->request($method, $uri);
            }
    } catch (GuzzleHttp\Exception\ClientException $ex) {
            throw new Exception($uri . "\n" . $ex->getResponse()->getBody()->getContents());
    }
  }

Solution

  • Of course is blank, the scenarios are and should be independent, whatever you save in the first scenario will be lost after the scenario is done.

    One way of doing this is to write to a file and read from file.

    Anyway I see that the validation from the first scenario include the validations from the second, the only difference is that in the first one you are saving the body of the response, not a very good idea and not a good practice to save data in validation steps.

    Try to reuse as much as possible.

    Scenarios hold be independent.You should able to run the second scenario without the first one.

    High level example, just an opinion:

    Scenario: Api - check response of the created task
       Given I have the JSON payload
       When I create a task using POST request -> create request, make sure is successful and save response
       And I send a GET request to created task -> use saved response to do what you need
       Then the response code should be 200
       And the response code should be "application/json" 

    Another example:

    Scenario: Api - check response of the created task
       Given I have have a task based on JSON: -> create request, make sure is successful and save response
       When I send a GET request to created task -> use saved response to do what you need
       Then the response code should be 200
       And the response code should be "application/json" 

    These are just some examples, I don't know the functionality, I am sure you cane do much better, always create steps keeping in mind your project business language in order to understand them later.

    taskList approach You need to make sure you have a taskList, as is required and what you need to is to check if a taskList is available (by title for example) if yes then do nothing else create the task list.