Symfony PHPUnit tests fail in parallel in GitHub Actions

I’m encountering an issue with my PHPUnit paratest configuration… or maybe my CI, Docker, or even my code — I’m not sure.

I have some tests for my Symfony web application, and I’m facing a problem where the user does not remain logged in. When I log in the user using $this->client->login(), no errors occur, and the assertion following the login confirms success. However, as soon as I make a subsequent request, the user appears to be logged out and is redirected to the login page.

If this were happening with every request, I’d have a better idea of where to start troubleshooting, but it only occurs intermittently. Additionally, this issue only happens in the GitHub Actions runner. When I run the tests locally, everything works fine — whether I use paratest or plain PHPUnit.

However, I recently discovered that if I run the tests sequentially on CI, everything works as expected.

Has anyone experienced this issue or know of a fix?

Here is the section of my checks.yml which triggers the test

tests:
  name: Tests
  runs-on: ubuntu-latest
  steps:
    - name: Check out code
      uses: actions/checkout@v4

    - name: Docker Compose Up
      run: docker compose up -d

    - name: Wait for services
      run: sleep 30

    - name: Setup Test Environment
      run: |
        docker compose exec app bash -c "
          rm -rf var/cache/*
          mkdir -p var/cache/test
          chmod -R 777 var/
          composer dump-autoload
          php bin/console cache:clear --env=test
          APP_ENV=test php bin/console cache:warmup
          chmod -R 777 var/
        "

    - name: Paratest
      run: |
        docker compose exec app bash -c "
          APP_ENV=test vendor/bin/paratest --configuration=phpunit.xml.dist --runner=WrapperRunner --testdox --verbose
          vendor/bin/phpunit --configuration=phpunit.xml.dist
        "

    - name: Docker Compose Down
      if: always()
      run: docker compose down

And here is an example test, here the test testActive always fails…

<?php

namespace AppTestsController;

use AppEntityTutorProfile;
use AppEntityUser;
use AppFactoryPermissionFactory;
use AppFactoryStudentProfileFactory;
use AppFactoryTutorProfileFactory;
use AppFactoryUserFactory;
use DoctrineORMEntityManagerInterface;
use SymfonyBundleFrameworkBundleKernelBrowser;
use SymfonyBundleFrameworkBundleTestWebTestCase;
use ZenstruckFoundryTestFactories;
use ZenstruckFoundryTestResetDatabase;

final class StudentControllerTest extends WebTestCase
{
    use Factories;
    use ResetDatabase;

    private KernelBrowser $client;
    private EntityManagerInterface $entityManager;
    private User $user;
    private TutorProfile $profile;

    protected function setUp(): void
    {
        $this->client = static::createClient();
        $this->entityManager = static::getContainer()->get(EntityManagerInterface::class);

        $this->user = UserFactory::createOne()->_real();
        $this->profile = TutorProfileFactory::createOne(['user_entity' => $this->user])->_real();
        $permission = PermissionFactory::createOne(['name' => 'CAN_VIEW_STUDENT_LIST'])->_real();
        $this->profile->addPermission($permission);
        $this->entityManager->flush();

        $this->client->loginUser($this->user);
        $this->client->request('GET', '/select-profile');
        $this->client->followRedirects();
    }

    public function testActive(): void
    {
        StudentProfileFactory::createMany(5, [
            'archived' => false,
            'deactivated' => false,
            'school' => $this->profile->getSchool(),
        ]);

        $this->client->request('GET', '/students');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('body > div.flex.min-h-screen > div.flex-1.flex.flex-col > main > div > h2', 'Schülerliste');

        $this->assertCount(5, $this->client->getCrawler()->filter('tbody tr'));
    }

    public function testArchived(): void
    {
        StudentProfileFactory::createMany(5, [
            'archived' => true,
            'deactivated' => false,
            'school' => $this->profile->getSchool(),
        ]);

        $this->client->request('GET', '/students/archived');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('body > div.flex.min-h-screen > div.flex-1.flex.flex-col > main > div > h2', 'Schülerliste');

        $this->assertCount(5, $this->client->getCrawler()->filter('tbody tr'));
    }

    public function testDeactivated(): void
    {
        StudentProfileFactory::createMany(5, [
            'archived' => false,
            'deactivated' => true,
            'school' => $this->profile->getSchool(),
        ]);

        $this->client->request('GET', '/students/deactivated');

        $this->assertResponseIsSuccessful();
        $this->assertSelectorTextContains('body > div.flex.min-h-screen > div.flex-1.flex.flex-col > main > div > h2', 'Schülerliste');
    }

    # ...

}

And here is the error:

1) AppTestsControllerStudentControllerTest::testActive
Failed asserting that SymfonyComponentDomCrawlerCrawler Object &0000000000000bf90000000000000000 (
    'defaultNamespacePrefix' => 'default'
    'namespaces' => Array &0 ()
    'cachedNamespaces' => ArrayObject Object &0000000000000f200000000000000000 ()
    'baseHref' => 'http://localhost/login'
    'document' => DOMDocument Object &0000000000000f240000000000000000 ()
    'nodes' => Array &1 (
        0 => DOMElement Object &0000000000000f220000000000000000 (
            'schemaTypeInfo' => null
        )
    )
    'isHtml' => true
    'html5Parser' => MastermindsHTML5 Object &0000000000000aab0000000000000000 (
        'defaultOptions' => Array &2 (
            'encode_entities' => false
            'disable_html_ns' => true
        )
        'errors' => Array &3 ()
    )
    'uri' => 'http://localhost/login'
) matches selector "body > div.flex.min-h-screen > div.flex-1.flex.flex-col > main > div > h2" and the Crawler has a node matching selector "body > div.flex.min-h-screen > div.flex-1.flex.flex-col > main > div > h2".
/var/www/html/vendor/symfony/framework-bundle/Test/DomCrawlerAssertionsTrait.php:44
/var/www/html/tests/Controller/StudentControllerTest.php:54