ux: [Twig Component] Test helper traits don't play nicely with CSRF, sessions and authentication

Thank you @kbond for the awesome test helper traits for Live and Twig components.

However, in some of my new tests that use these traits, I’m running into some issues. All this is PHP 8.2 on Symfony 6.3, with Live/Twig components on the latest 2.11.2 version.

All these tests extend Symfony’s KernelTestCase via my own KernelTestCase wrapper, where I add a setUp method to run before all tests cases:

abstract class KernelTestCase extends \Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
{
    /** @var TestContainer */
    public Container|ContainerInterface $container;

    protected function setUp(): void
    {
        self::bootKernel();
        $this->container = static::getContainer();
    }
}

I think this is quite a normal configuration.

However, then with some tests I’m running into the following issues:

1) Session not found

Any Twig or Live Component that touches the session, either in PHP or in the template, will throw SessionNotFoundException: There is currently no session available. when the test is run.

For me this is usually because I have e.g. a Date Range filter stored in the session, and this is then used inside the component to filter e.g. a repository query.

The solution to this is to pass in the value from the session when placing the component in the parent template. i.e.

{{ component('report_income_by_client', { dateRange: app.session.get('dateRange') }) }}

This is actually more elegant in a way, as it keeps the concerns of the component itself to a bare minimum.

Then, in the test, we just pass in the “dateRange” as a parameter that we control from inside the test:

$rendered = $this->renderTwigComponent(
    name: ReportIncomeByClientComponent::class,
    data: [
        'dateRange' => $dateRange, // define this elsewhere in the test
    ],
);

So this is a working solution that I’m more posting here for future reference than anything else. However, it leads nicely on to the second problem:

2) CSRF token not found

If any of the components under test are rending a form, then I get failures with the following exception:

Symfony\Component\HttpFoundation\Exception\SessionNotFoundException: There is currently no session available.

/var/www/app/vendor/symfony/http-foundation/RequestStack.php:107
/var/www/app/vendor/symfony/security-csrf/TokenStorage/SessionTokenStorage.php:110
/var/www/app/vendor/symfony/security-csrf/TokenStorage/SessionTokenStorage.php:74
/var/www/app/vendor/symfony/security-csrf/CsrfTokenManager.php:69
/var/www/app/vendor/symfony/form/Extension/Csrf/Type/FormTypeCsrfExtension.php:82
/var/www/app/vendor/symfony/form/ResolvedFormType.php:134
/var/www/app/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php:95
/var/www/app/vendor/symfony/form/ResolvedFormType.php:128
/var/www/app/vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php:95
/var/www/app/vendor/symfony/form/Form.php:908
/var/www/app/vendor/symfony/ux-live-component/src/ComponentWithFormTrait.php:120
/var/www/app/vendor/symfony/ux-live-component/src/ComponentWithFormTrait.php:95
/var/www/app/vendor/symfony/ux-twig-component/src/ComponentFactory.php:198
/var/www/app/vendor/symfony/ux-twig-component/src/ComponentFactory.php:91
/var/www/app/vendor/symfony/ux-twig-component/src/ComponentFactory.php:65
/var/www/app/vendor/symfony/ux-live-component/src/Test/TestLiveComponent.php:45
/var/www/app/vendor/symfony/ux-live-component/src/Test/InteractsWithLiveComponents.php:36
/var/www/app/tests/integration/ReportIncomeByClientComponentTest.php:22

The way I have sorted this is to disable CSRF protection across the entire “test” environment, but this is not great as I do want it enabled for WebTestCase but not for KernelTestCase etc.

// config/packages/framework.php

if ($container->env() === 'test')
{
    $framework->test(true);
    $framework->csrfProtection()->enabled(false);
}

Is there a sensible way to disable the CSRF protection only inside KernelTestCase tests? Or indeed just to create a CSRF token that is accepted?

3) Authenticated Users seem to be ignored

The final issue I’m seeing is that these tests seem to ignore any authenticated users I have. In my extended KernelTestCase base class, I have something like:

public function loginAs(string $username): void
{
    $user = $this->container->get(UserRepository::class)->findByUsername($username);
    $tokenStorage = $this->container->get(TokenStorageInterface::class);
    $token = new TestBrowserToken(roles: [Role::SUPER_ADMIN, Role::USER], user: $user);
    $tokenStorage->setToken($token);
}

This works fine in normal tests but seems to be ignored completely during the Twig/Live Component tests, and I just get Symfony\Component\Security\Core\Exception\AccessDeniedException : Access Denied. on any component that has an IsGranted attribute defined.

Again, a solution to this is to disable access control across the entire “test” environment, but I don’t want to do this as the security restrictions also need to be part of the tested behaviour.

Sorry for the long post - but I figure that all these things are going to be a common issue when testing components, and I have a feeling they are all related together somehow.

Thanks!

About this issue

  • Original URL
  • State: open
  • Created 9 months ago
  • Comments: 17 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Do you think this is something that should be incorporated directly in to the Live/Twig Component test helpers?

I’m not sure… I don’t like the idea of blindly pushing mock requests/sessions onto the request stack service. Especially for twig components, these aren’t necessarily rendered in the browser.

Let’s keep this issue open and gather some more feedback from users using these test helpers. When digging into the code, I realized that logging in a user with the client before initiating the test component might not work as expected.