Consider resetting the session when calling drupalLogout() for functional tests

Created on 31 October 2023, about 1 year ago

Problem/Motivation

I tried looking for an existing issue but couldn't quite locate one. I recently ran into an issue when testing custom code around cookies and logging in/out with functional tests, outlined here:

https://drupal.stackexchange.com/questions/317324/drupal-unable-to-login...

It came down to the Mink driver not properly clearing cookies / session related data when logging out a user until I used $this->getSession()->reset();

drupalLogout does not seem to account for this:

  protected function drupalLogout() {
    // Make a request to the logout page, and redirect to the user page, the
    // idea being if you were properly logged out you should be seeing a login
    // screen.
    $assert_session = $this->assertSession();
    $destination = Url::fromRoute('user.page')->toString();
    $this->drupalGet(Url::fromRoute('user.logout', [], ['query' => ['destination' => $destination]]));
    $assert_session->fieldExists('name');
    $assert_session->fieldExists('pass');

    // @see BrowserTestBase::drupalUserIsLoggedIn()
    unset($this->loggedInUser->sessionId);
    $this->loggedInUser = FALSE;
    \Drupal::currentUser()->setAccount(new AnonymousUserSession());
  }

Steps to reproduce

With code that sets cookies, trying to log in a user that gets those cookies, logging them out and then using drupalLogin will produce the following error:

User <em class="placeholder">NAME</em> successfully logged in.
Failed asserting that false is true.

In my case I am doing a redirect because of the logic required and so the assert in drupalLogin fails, whereas the drupalGet/submitForm method works.

Proposed resolution

Ensure the session is reset/cleared cleanly when using drupalLogout for functional tests or provide a note in the docs on this behavior to know to call $this->getSession()->reset() in certain scenarios.

Feature request
Status

Active

Version

10.1

Component
Base 

Last updated 1 day ago

Created by

🇺🇸United States kevinquillen

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @kevinquillen
  • 🇫🇷France pbonnefoi

    I have a similar problem trying to fix a unit test on a contrib module, but adding $this->getSession()->reset(); did not work. Do you add it right after drupalLogout() ?

    An improvement on the error message would be very nice as well because it does not make much sense.

    The unit test causing problem is from the redirect_after_login contrib module.

  • 🇺🇸United States kevinquillen

    Calling drupalLogout() in this scenario is the problem because assert() fails (its in one of the test traits) - it thinks the session is still authenticated. This does not happen outside of a test.

    I believe if the test method was updated to this, it would resolve the issue:

      protected function drupalLogout() {
        // Make a request to the logout page, and redirect to the user page, the
        // idea being if you were properly logged out you should be seeing a login
        // screen.
        $assert_session = $this->assertSession();
        $destination = Url::fromRoute('user.page')->toString();
        $this->drupalGet(Url::fromRoute('user.logout', [], ['query' => ['destination' => $destination]]));
        $assert_session->fieldExists('name');
        $assert_session->fieldExists('pass');
    
        // @see BrowserTestBase::drupalUserIsLoggedIn()
        unset($this->loggedInUser->sessionId);
        $this->loggedInUser = FALSE;
        $this->getSession()->reset();
        \Drupal::currentUser()->setAccount(new AnonymousUserSession());
      }
    

    Multiple login/logouts in a single test method that alters or adds to user session data or cookie data is otherwise problematic to test.

  • 🇫🇷France pbonnefoi

    Ok good to know, thank you very much for the insights !

  • 🇦🇺Australia fenstrat Australia

    Just noting here that I saw these same odd failures, especially when running multiple drupalLogin() calls:

    User <em class="placeholder">NAME</em> successfully logged in.
    Failed asserting that false is true.
    

    And that calling $this->getSession()->reset() didn't solve it.

    Instead it was related to dumping the container, and the container differing while under test. In my case this was using Drupal Test Traits, see
    🐛 DTT can use different cached container than running site causing issues with testing Fixed .

Production build 0.71.5 2024