Introduction
Creating functional tests for controllers that have forms with complex field types can be hard to understand at first, but once you understand the basic concepts, they become easier. This article explains a simple example that I had to test with an application I developed.
Client Crawler and Redirects
For my application, I needed to click on a link to get to the authentication page, and then after authentication succeeds, that controller redirects back to the homepage (with cookies created). Since a typical test case looks for a 200 response code, when redirected, you will actually get a 302 response code instead. To workaround this in Symfony, you’ll need to follow redirects. The sample client code would look like the following:
...
public function testLogin(){
$client = static::createClient();
$client->followRedirects();
...
So in the above code, the followRedirects()
method is used when your client is expecting to be redirected on a successful response as per the documentation.
Getting Form Page and Node
After creating the client, I needed to click a link to go to the login page and then assert that it is the correct page and get a crawler node (the login button). Example code is as follows:
...
$crawler = $client->request('GET', '/');
$loginLink = $crawler->selectLink('Login link')->link();
$crawler = $client->click( $loginLink );
$this->assertContains(
'Enter your details',
$client->getResponse()->getContent()
);
$authCrawlerNode = $crawler->selectButton('Login');
...
The above code gets the homepage content, looks for a link called “Login link” then clicks it; and then finally asserts the resultant page contains “Enter your details”. Then it gets the crawler node a button labeled “Login”.
The Login Form
My form is interesting in that it asks for first & last names and the person’s date of birth. See the screenshot below:
Notice the date of birth is a drop-down list. This is a complex type of input I was mentioning at the beginning of this article.
The Symfony testing documentation only briefly describes how to perform testing on some complex form input types, so you really have to experiment to figure things out. For example, in my case, based on the documentation, I could write the following example code:
...
$form = $authCrawlerNode->form();
$form['form[f_name]'] = 'John';
$form['form[l_name]'] = 'Doe';
$form['form[dob][day]']->select('2');
$form['form[dob][month]']->select('7');
$form['form[dob][year]']->select('1981');
...
However, that’s not the easiest way to write the code.
You may wonder how I figured out the form input names to use and the values. If you use FireFox, right-click on the day drop-down list element and select “Inspect element
” and you’ll see something like the following:
Notice the name
value. You can copy and paste that into your code. The name is a composite of the form name + form field type name + list item. So in my case, my form was called “form
”, and the field type name is “dob
”, and the list item is the “day
” field.
Easier Way to Write Code
An easier way to write the code is put the values you want to enter in the form in an array, and use the crawler node to do this like so:
...
$form = $authCrawlerNode->form(array(
'form[f_name]' => 'John',
'form[l_name]' => 'Doe',
'form[dob][day]' => '2',
'form[dob][month]' => '7',
'form[dob][year]' => '1981'
));
$crawler = $client->submit( $form );
...
Notice you don’t call the select
method on the drop-down list items, but just enter the correct values you need.
You can simplify even further by just using similar code and the client submit
method like so:
...
$client->submit( $authCrawlerNode->form(array(
'form[f_name]' => 'John',
'form[l_name]' => 'Doe',
'form[dob][day]' => '2',
'form[dob][month]' => '1',
'form[dob][year]' => '1981'
)));
...
Verifying Submission
Finally after submitting the form, you need to assert that the user was indeed authenticated. The code would look like the following:
...
$client->submit( $authCrawlerNode->form(array(...
...
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
Since the follow redirects has been enabled, the then expected response code of 200 should be expected. You should verify any failures of the test case. A lot of times, it will be the incorrect array values specified. All the above code is from working real examples.
I hope this is a good example for someone to use.