Symfony phpunit functional test edit confirm inconsistent

Viewed 20

I added some functionality where if you edit an item that somebody edited in the meantime, you go to an "edit confirm" page where you can select which changes you want to overwrite.

How it's done:

if ($request->isMethod('GET')) {
    $session->set('overwriteDate', $language->getUpdatedAt()?->format('Y-m-d H:i:s'));
    $session->set('language_referer',  $request->headers->get('referer'));
}

$form = $this->createForm(LanguageFormType::class, $language);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
    var_dump($language->getUpdatedAt());
    var_dump($session->get('overwriteDate'));
    if ($session->get('overwriteDate') !== $language->getUpdatedAt()?->format('Y-m-d H:i:s')) {
        $session->set('overwriteItem', $language);

        return $this->redirectToRoute('languages_edit_confirm', ['id' => $language->getId()]);
    } else {
        $baseEntityService->save($language);

        return $this->redirect($session->get('language_referer'));
    }
}

return $this->render('admin/language/edit.html.twig', [
    'language' => $language,
    'form' => $form->createView()
]);

If the overwriteDate in the session doesn't match the updatedAt from the object, it will redirect to the edit confirm page. This all works fine in the browser (tested it manually a lot, never had an issue).

However, now I try to write a functional test for this, and it's inconsistent. This is the begin of the test:

$crawler1 = $this->client->request('GET', '/admin/languages');
$crawler1 = $this->filterTable($crawler1, $originalEnglishName);
$crawler1 = $this->client->click($crawler1->filter('a.edit-language')->link());

$crawler2 = $this->client->request('GET', '/admin/languages');
$crawler2 = $this->filterTable($crawler2, $originalEnglishName);
$crawler2 = $this->client->click($crawler2->filter('a.edit-language')->link());

$form = $crawler1->selectButton('saveLanguage')->form();
$form['language_form[abbreviation]'] = $firstEditAbbreviation;
$form['language_form[englishName]'] = $firstEditEnglishName;
$form['language_form[name]'] = $firstEditName;
$form['language_form[flag]'] = $firstEditFlag;

$form2 = $crawler2->selectButton('saveLanguage')->form();
$form2['language_form[abbreviation]'] = $secondEditAbbreviation;
$form2['language_form[englishName]'] = $secondEditEnglishName;
$form2['language_form[name]'] = $secondEditName;
$form2['language_form[flag]'] = $secondEditFlag;

$this->client->submit($form);
$this->client->submit($form2);
$crawler2 = $this->client->followRedirect();

$tbody = $crawler2->filter('table#difference-table tbody')->first();

After this I try to assert some stuff from $tbody however sometimes the test works fine but sometimes it gives errors because it acts like a normal edit and redirects to the homepage and the data from $tbody I search on doesn't exist.

Edit:

I tried changing the session stuff to putting it in the form as hidden input, but this gives the same issues.

1 Answers

You'll need to preserve the session cookie between then requests in your test(s).

The Symfony HTTPClient does not do this by default.

The HTTP client provided by this component is stateless but handling cookies requires a stateful storage (because responses can update cookies and they must be used for subsequent requests). That's why this component doesn't handle cookies automatically.

You can either handle cookies yourself using the Cookie HTTP header or use the BrowserKit component which provides this feature and integrates seamlessly with the HttpClient component.

Example usage:

// Request using the client
$crawler = $client->request('GET', '/');

// Get the cookie Jar
$cookieJar = $client->getCookieJar();

// Get the history
$history = $client->getHistory();

// Get a cookie by name
$sessionCookie = $cookieJar->get('PHPSESSID');

// create cookies and add to cookie jar
$cookie = new Cookie('PHPSESSID', 'XYZ', strtotime('+1 day'));
$cookieJar = new CookieJar();
$cookieJar->set($cookie);

// create a client and set the cookies
$client = new Client([], null, $cookieJar);
Related