3

I am trying to run some functional tests in DDEV that check functions of protected routes. I can log in the first couple of users fine, but after that drupaLogin() fails to generate a logged in session.

Example:

$this->drupalGet(Url::fromRoute('mymodule.secondary_login'));
$this->submitForm([
  'name' => '[email protected]',
  'pass' => 'test',
], 'Log in');

// Try to go to /user.
$this->drupalGet('/user');
$this->assertSession()->addressEquals('member');

// More navigation and assertion checks here

// Make the cookie stale and test the redirect.
$this->getSession()->setCookie('session', NULL);
$this->drupalGet('/');
$this->assertSession()->addressEquals('member/login');
$this->drupalGet(Url::fromRoute('mymodule.secondary_logout'));
$this->assertFalse($this->loggedInUser);

// User is anon and session should be clear at this point, but drupalLogin fails
$authenticated_user = $this->drupalCreateUser([], 'Authenticated User', FALSE);
$this->drupalLogin($authenticated_user);
$this->drupalGet('/member');
$this->drupalGet(Url::fromRoute('mos_ticketure.logout'));
$this->assertSession()->statusCodeEquals(403);

Url::fromRoute('mymodule.secondary_login') is a login form that handles setting a cookie and registering a new user with ExternalAuth. secondary_logout handles destroying the user session (copied from Drupal core logout()) as well as cleaning up custom cookies.

By the time it gets down to log in the Authenticated User, drupalLogin fails an assert check with:

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

If I move it to a brand new test method, this simple test works fine:

$this->drupalGet(Url::fromRoute('mymodule.login'));
$this->submitForm([
  'name' => '[email protected]',
  'pass' => 'test',
], 'Log in');
$this->drupalGet(Url::fromRoute('mymodule.logout'));

$authenticated_user = $this->drupalCreateUser([], 'Authenticated User', FALSE);
$this->drupalLogin($authenticated_user);
$this->drupalGet('/member');
$this->drupalGet(Url::fromRoute('mymodule.logout'));
$this->assertSession()->statusCodeEquals(403);

If I click through these scenarios manually, the custom functionality does indeed appear to do what it should. Is this some sort of weird behavior with PHPUnit Functional tests with Mink unable to properly track cookies and session data in larger tests?

1 Answer 1

0

I was able to narrow it down to this block of code in an EventSubscriber:

if ($this->currentUser->isAnonymous() && $this->requestStack->getCurrentRequest()->cookies->has('session')) {
  $options = $this->sessionConfiguration->getOptions($event->getRequest());
  $cookie_domain = $options['cookie_domain'];

  $response = new RedirectResponse('/member/login', 302);
  $response->headers->clearCookie('session', '/', $cookie_domain);
  $response->headers->clearCookie('session_expires', '/', $cookie_domain);
  $event->setResponse($response);
}

Under test, Mink does not seem to be entirely eradicating cookies even though I have a logout hook and request event that sets them (and does erase them) in that certain condition. However, for anonymous users without that cookie this keeps being triggered, so I think functional tests may have some issue with custom cookies or clearing them properly in this regard with the Mink driver. Even calling ->drupalLogout() had no further effect.

I wound up having to do $this->getSession()->reset(); then I could do this in tests that do various types of user logins (custom or core):

$this->getSession()->reset();
    $authenticated_user = $this->drupalCreateUser([], 'Authenticated User', FALSE);
    $this->drupalLogin($authenticated_user);

It does seem to be an issue with Mink, based on some findings:

https://github.com/ariya/phantomjs/issues/11768

there are similar reported issues in various libraries... the tests will only work in this regard with a reset. Unsure of where the deeper issue lies, actual usage works (real person, real browser).

Added it here for tracking: https://www.drupal.org/project/drupal/issues/3398145

2
  • 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() ?
    – pbonnefoi
    Commented Dec 14, 2023 at 11:38
  • 1
    Yes, I did. The session data is not fully clearing otherwise.
    – Kevin
    Commented Dec 14, 2023 at 14:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.