Skip to content

Commit

Permalink
Add functional tests for all actions
Browse files Browse the repository at this point in the history
  • Loading branch information
core23 committed Mar 10, 2024
1 parent a64984a commit 9a06d30
Show file tree
Hide file tree
Showing 10 changed files with 331 additions and 5 deletions.
2 changes: 2 additions & 0 deletions composer.json
Expand Up @@ -69,12 +69,14 @@
},
"require-dev": {
"ext-mongodb": "*",
"dama/doctrine-test-bundle": "^8.0",
"doctrine/doctrine-bundle": "^2.4",
"doctrine/mongodb-odm": "^2.3",
"doctrine/mongodb-odm-bundle": "^4.4 || ^5.0",
"doctrine/orm": "^2.18 || ^3.0",
"ergebnis/composer-normalize": "^2.0.1",
"symfony/browser-kit": "^6.4 || ^7.0",
"symfony/css-selector": "^6.4 || ^7.0",
"symfony/doctrine-bridge": "^6.4 || ^7.0",
"symfony/yaml": "^6.4 || ^7.0"
},
Expand Down
7 changes: 7 additions & 0 deletions phpunit.xml.dist
Expand Up @@ -3,12 +3,19 @@
<coverage/>
<php>
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[self]=0"/>
<env name="APP_DEBUG" value="false"/>
<env name="APP_ENV" value="test"/>
<env name="KERNEL_CLASS" value="Nucleos\UserBundle\Tests\App\AppKernel"/>
<ini name="date.timezone" value="UTC"/>
</php>
<testsuites>
<testsuite name="UserBundle Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<extensions>
<bootstrap class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/>
</extensions>
<source>
<include>
<directory suffix=".php">./src/</directory>
Expand Down
10 changes: 8 additions & 2 deletions tests/App/AppKernel.php
Expand Up @@ -13,6 +13,8 @@

namespace Nucleos\UserBundle\Tests\App;

use DAMA\DoctrineTestBundle\DAMADoctrineTestBundle;
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Nucleos\UserBundle\NucleosUserBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
Expand All @@ -26,9 +28,9 @@ final class AppKernel extends Kernel
{
use MicroKernelTrait;

public function __construct()
public function __construct(string $environment = 'test', bool $debug = false)
{
parent::__construct('test', false);
parent::__construct($environment, $debug);
}

public function registerBundles(): iterable
Expand All @@ -39,6 +41,10 @@ public function registerBundles(): iterable

yield new SecurityBundle();

yield new DoctrineBundle();

yield new DAMADoctrineTestBundle();

yield new NucleosUserBundle();
}

Expand Down
12 changes: 11 additions & 1 deletion tests/App/Entity/TestGroup.php
Expand Up @@ -13,6 +13,16 @@

namespace Nucleos\UserBundle\Tests\App\Entity;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Nucleos\UserBundle\Model\Group;

class TestGroup extends Group {}
#[ORM\Entity]
#[ORM\Table(name: 'user__group')]
class TestGroup extends Group
{
#[ORM\Id]
#[ORM\Column(type: Types::INTEGER)]
#[ORM\GeneratedValue]
protected ?int $id = null;
}
38 changes: 37 additions & 1 deletion tests/App/Entity/TestUser.php
Expand Up @@ -13,10 +13,46 @@

namespace Nucleos\UserBundle\Tests\App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Nucleos\UserBundle\Model\GroupInterface;
use Nucleos\UserBundle\Model\User;

/**
* @phpstan-extends User<GroupInterface>
*/
class TestUser extends User {}
#[ORM\Entity]
#[ORM\Table(name: 'user__user')]
class TestUser extends User
{
#[ORM\Id]
#[ORM\Column(type: Types::INTEGER)]
#[ORM\GeneratedValue]
protected ?int $id = null;

/**
* @var Collection<array-key, GroupInterface>
*/
#[ORM\ManyToMany(targetEntity: TestGroup::class)]
#[ORM\JoinTable(name: 'user__user_group')]
protected Collection $groups;

public function __construct()
{
parent::__construct();

$this->groups = new ArrayCollection();
}

public function getId(): ?int
{
return $this->id;
}

public function setId(?int $id): void
{
$this->id = $id;
}
}
31 changes: 30 additions & 1 deletion tests/App/config/config.php
Expand Up @@ -30,7 +30,14 @@
$containerConfigurator->extension('twig', ['exception_controller' => null]);

$securityConfig = [
'firewalls' => ['main' => ['security' => true]],
'firewalls' => ['main' => [
'security' => true,
'form_login' => [
'login_path' => 'nucleos_user_security_login',
'check_path' => 'nucleos_user_security_check',
'default_target_path' => '/profile',
],
]],
];

// TODO: Remove if when dropping support of Symfony 5.4
Expand All @@ -50,6 +57,23 @@
'algorithm' => 'plaintext',
]]]);

$containerConfigurator->extension('doctrine', ['dbal' => ['url' => 'sqlite:///%kernel.cache_dir%/data.db', 'logging' => false, 'use_savepoints' => true]]);

$containerConfigurator->extension('doctrine', ['orm' => [
'auto_mapping' => true,
'mappings' => [
'App' => [
'is_bundle' => false,
'type' => 'attribute',
'dir' => '%kernel.project_dir%/Entity',
'prefix' => 'Nucleos\UserBundle\Tests\App\Entity',
'alias' => 'App',
],
],
]]);

$containerConfigurator->extension('nucleos_user', ['db_driver' => 'orm']);

$containerConfigurator->extension('nucleos_user', ['firewall_name' => 'main']);

$containerConfigurator->extension('nucleos_user', ['from_email' => 'no-reply@localhost']);
Expand All @@ -59,4 +83,9 @@
$containerConfigurator->extension('nucleos_user', ['group' => ['group_class' => TestGroup::class]]);

$containerConfigurator->extension('nucleos_user', ['loggedin' => ['route' => 'home']]);

$containerConfigurator->extension('nucleos_user', ['deletion' => [
]]);

$containerConfigurator->extension('dama_doctrine_test', ['enable_static_connection' => true, 'enable_static_meta_data_cache' => true, 'enable_static_query_cache' => true]);
};
75 changes: 75 additions & 0 deletions tests/Functional/Action/AccountDeletionWebTest.php
@@ -0,0 +1,75 @@
<?php

/*
* This file is part of the NucleosUserBundle package.
*
* (c) Christian Gripp <mail@core23.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nucleos\UserBundle\Tests\Functional\Action;

use Nucleos\UserBundle\Action\AccountDeletionAction;
use Nucleos\UserBundle\Tests\App\Entity\TestUser;
use Nucleos\UserBundle\Tests\Functional\DoctrineSetupTrait;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

#[CoversClass(AccountDeletionAction::class)]
final class AccountDeletionWebTest extends WebTestCase
{
use DoctrineSetupTrait;

#[Test]
public function execute(): void
{
$client = self::createClient();

$this->persist(
$user = self::createUser(),
);

$client->loginUser($user);
$client->request('GET', '/delete');

self::assertResponseIsSuccessful();

$client->submitForm('account_deletion_form[delete]', [
'account_deletion_form[current_password]' => $user->getPlainPassword(),
'account_deletion_form[confirm]' => true,
]);

self::assertResponseRedirects('/logout');

self::assertNull($this->getEntityManager()->find(TestUser::class, $user->getId()));
}

#[Test]
public function executeWithInvalidPassword(): void
{
$client = self::createClient();

$this->persist(
$user = self::createUser(),
);

$client->loginUser($user);
$client->request('GET', '/delete');

self::assertResponseIsSuccessful();

$client->submitForm('account_deletion_form[delete]', [
'account_deletion_form[current_password]' => 'wrong',
'account_deletion_form[confirm]' => true,
]);

self::assertResponseIsSuccessful();

self::assertSelectorTextContains('#account_deletion_form', 'The entered password is invalid');

self::assertNotNull($this->getEntityManager()->find(TestUser::class, $user->getId()));
}
}
67 changes: 67 additions & 0 deletions tests/Functional/Action/LoginWebTest.php
@@ -0,0 +1,67 @@
<?php

/*
* This file is part of the NucleosUserBundle package.
*
* (c) Christian Gripp <mail@core23.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nucleos\UserBundle\Tests\Functional\Action;

use Nucleos\UserBundle\Action\LoginAction;
use Nucleos\UserBundle\Tests\Functional\DoctrineSetupTrait;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

#[CoversClass(LoginAction::class)]
final class LoginWebTest extends WebTestCase
{
use DoctrineSetupTrait;

#[Test]
public function execute(): void
{
$client = self::createClient();

$this->persist(
$user = self::createUser(),
);

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

self::assertResponseIsSuccessful();

$client->submitForm('save', [
'_username' => $user->getUsername(),
'_password' => $user->getPlainPassword(),
]);

self::assertResponseRedirects('/profile');
}

#[Test]
public function executeWithInvalidPassword(): void
{
$client = self::createClient();

$this->persist(
$user = self::createUser(),
);

$client->request('GET', '/login');
$client->followRedirects();

self::assertResponseIsSuccessful();

$client->submitForm('save', [
'_username' => $user->getUsername(),
'_password' => 'wrong',
]);

self::assertSelectorTextContains('li', 'Invalid credentials.');
}
}
61 changes: 61 additions & 0 deletions tests/Functional/DoctrineSetupTrait.php
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

/*
* This file is part of the NucleosUserBundle package.
*
* (c) Christian Gripp <mail@core23.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nucleos\UserBundle\Tests\Functional;

use Doctrine\ORM\EntityManagerInterface;
use Nucleos\UserBundle\Tests\App\Entity\TestUser;

trait DoctrineSetupTrait
{
private static int $index = 1;

/**
* @param string[] $roles
*/
public static function createUser(
string $username = null,
array $roles = []
): TestUser {
$username ??= ('my-user'.self::$index++);

$entity = new TestUser();
$entity->setId(random_int(1, 9999999));
$entity->setUsername($username);
$entity->setPlainPassword('password');
$entity->setEmail(sprintf('%s@localhost', $username));
$entity->setRoles($roles);

return $entity;
}

protected function persist(object ...$objects): void
{
$manager = $this->getEntityManager();

foreach ($objects as $object) {
$manager->persist($object);
}

$manager->flush();
}

private function getEntityManager(): EntityManagerInterface
{
$manager = self::getContainer()->get('doctrine.orm.entity_manager');

\assert($manager instanceof EntityManagerInterface);

return $manager;
}
}

0 comments on commit 9a06d30

Please sign in to comment.