Add test for MyInvitationsController.php

This commit is contained in:
2025-09-30 15:45:26 +02:00
parent e6a799abc4
commit f93c7e014f
5 changed files with 301 additions and 4 deletions

View File

@@ -13,7 +13,7 @@ namespace Chill\CalendarBundle\Controller;
use Chill\CalendarBundle\Entity\Calendar; use Chill\CalendarBundle\Entity\Calendar;
use Chill\CalendarBundle\Repository\InviteRepository; use Chill\CalendarBundle\Repository\InviteRepository;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository; use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorFactory;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -24,7 +24,7 @@ use Symfony\Component\Routing\Annotation\Route;
class MyInvitationsController extends AbstractController class MyInvitationsController extends AbstractController
{ {
public function __construct(private readonly InviteRepository $inviteRepository, private readonly PaginatorFactory $paginator, private readonly DocGeneratorTemplateRepository $docGeneratorTemplateRepository) {} public function __construct(private readonly InviteRepository $inviteRepository, private readonly PaginatorFactory $paginator, private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository) {}
#[Route(path: '/{_locale}/calendar/invitations/my', name: 'chill_calendar_invitations_list_my')] #[Route(path: '/{_locale}/calendar/invitations/my', name: 'chill_calendar_invitations_list_my')]
public function myInvitations(Request $request): Response public function myInvitations(Request $request): Response

View File

@@ -16,7 +16,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository; use Doctrine\Persistence\ObjectRepository;
readonly class InviteRepository implements ObjectRepository class InviteRepository implements ObjectRepository
{ {
private EntityRepository $entityRepository; private EntityRepository $entityRepository;

View File

@@ -0,0 +1,292 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Tests\Controller;
use Chill\CalendarBundle\Controller\MyInvitationsController;
use Chill\CalendarBundle\Entity\Calendar;
use Chill\CalendarBundle\Entity\Invite;
use Chill\CalendarBundle\Repository\InviteRepository;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Pagination\PaginatorInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Twig\Environment;
/**
* @internal
*
* @coversNothing
*/
final class MyInvitationsControllerTest extends TestCase
{
use ProphecyTrait;
private MyInvitationsController $controller;
protected function setUp(): void
{
// Create prophecies for dependencies
$inviteRepository = $this->prophesize(InviteRepository::class);
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
// Create controller instance
$this->controller = new MyInvitationsController(
$inviteRepository->reveal(),
$paginatorFactory->reveal(),
$docGeneratorTemplateRepository->reveal()
);
// Set up necessary services for AbstractController
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
$tokenStorage = $this->prophesize(TokenStorageInterface::class);
$twig = $this->prophesize(Environment::class);
// Use reflection to set the container
$reflection = new \ReflectionClass($this->controller);
$containerProperty = $reflection->getParentClass()->getProperty('container');
$containerProperty->setAccessible(true);
// Create a mock container
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
$container->has('security.authorization_checker')->willReturn(true);
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
$container->has('security.token_storage')->willReturn(true);
$container->get('security.token_storage')->willReturn($tokenStorage->reveal());
$container->has('twig')->willReturn(true);
$container->get('twig')->willReturn($twig->reveal());
$containerProperty->setValue($this->controller, $container->reveal());
}
public function testMyInvitationsReturnsCorrectAmountOfInvitations(): void
{
// Create test user
$user = new User();
$user->setUsername('testuser');
// Create test invitations
$invite1 = new Invite();
$invite1->setUser($user);
$invite1->setStatus(Invite::PENDING);
$invite2 = new Invite();
$invite2->setUser($user);
$invite2->setStatus(Invite::ACCEPTED);
$invite3 = new Invite();
$invite3->setUser($user);
$invite3->setStatus(Invite::DECLINED);
$allInvitations = [$invite1, $invite2, $invite3];
$paginatedInvitations = [$invite1, $invite2]; // First page with 2 items per page
// Set up repository prophecies
$inviteRepository = $this->prophesize(InviteRepository::class);
$inviteRepository->findBy(['user' => $user])->willReturn($allInvitations);
$inviteRepository->findBy(
['user' => $user],
['createdAt' => 'DESC'],
2, // items per page
0 // offset
)->willReturn($paginatedInvitations);
// Set up paginator prophecies
$paginator = $this->prophesize(PaginatorInterface::class);
$paginator->getItemsPerPage()->willReturn(2);
$paginator->getCurrentPageFirstItemNumber()->willReturn(0);
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
$paginatorFactory->create(3)->willReturn($paginator->reveal());
// Set up doc generator repository
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
$docGeneratorTemplateRepository->findByEntity(Calendar::class)->willReturn([]);
// Create controller with mocked dependencies
$controller = new MyInvitationsController(
$inviteRepository->reveal(),
$paginatorFactory->reveal(),
$docGeneratorTemplateRepository->reveal()
);
// Set up authorization checker to return true for ROLE_USER
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
$authorizationChecker->isGranted('ROLE_USER', null)->willReturn(true);
// Set up token storage to return user
$token = $this->prophesize(TokenInterface::class);
$token->getUser()->willReturn($user);
$tokenStorage = $this->prophesize(TokenStorageInterface::class);
$tokenStorage->getToken()->willReturn($token->reveal());
// Set up twig to return a response
$twig = $this->prophesize(Environment::class);
$twig->render('@ChillCalendar/Invitations/listByUser.html.twig', [
'invitations' => $paginatedInvitations,
'paginator' => $paginator->reveal(),
'templates' => [],
])->willReturn('rendered content');
// Set up container
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
$container->has('security.authorization_checker')->willReturn(true);
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
$container->has('security.token_storage')->willReturn(true);
$container->get('security.token_storage')->willReturn($tokenStorage->reveal());
$container->has('twig')->willReturn(true);
$container->get('twig')->willReturn($twig->reveal());
// Use reflection to set the container
$reflection = new \ReflectionClass($controller);
$containerProperty = $reflection->getParentClass()->getProperty('container');
$containerProperty->setAccessible(true);
$containerProperty->setValue($controller, $container->reveal());
// Create request
$request = new Request();
// Execute the action
$response = $controller->myInvitations($request);
// Assert that response is successful
self::assertInstanceOf(Response::class, $response);
self::assertSame(200, $response->getStatusCode());
self::assertSame('rendered content', $response->getContent());
}
public function testMyInvitationsPageLoads(): void
{
// Create test user
$user = new User();
$user->setUsername('testuser');
// Set up repository prophecies - no invitations
$inviteRepository = $this->prophesize(InviteRepository::class);
$inviteRepository->findBy(['user' => $user])->willReturn([]);
$inviteRepository->findBy(
['user' => $user],
['createdAt' => 'DESC'],
20, // default items per page
0 // offset
)->willReturn([]);
// Set up paginator prophecies
$paginator = $this->prophesize(PaginatorInterface::class);
$paginator->getItemsPerPage()->willReturn(20);
$paginator->getCurrentPageFirstItemNumber()->willReturn(0);
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
$paginatorFactory->create(0)->willReturn($paginator->reveal());
// Set up doc generator repository
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
$docGeneratorTemplateRepository->findByEntity(Calendar::class)->willReturn([]);
// Create controller with mocked dependencies
$controller = new MyInvitationsController(
$inviteRepository->reveal(),
$paginatorFactory->reveal(),
$docGeneratorTemplateRepository->reveal()
);
// Set up authorization checker to return true for ROLE_USER
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
$authorizationChecker->isGranted('ROLE_USER', null)->willReturn(true);
// Set up token storage to return user
$token = $this->prophesize(TokenInterface::class);
$token->getUser()->willReturn($user);
$tokenStorage = $this->prophesize(TokenStorageInterface::class);
$tokenStorage->getToken()->willReturn($token->reveal());
// Set up twig to return a response
$twig = $this->prophesize(Environment::class);
$twig->render('@ChillCalendar/Invitations/listByUser.html.twig', [
'invitations' => [],
'paginator' => $paginator->reveal(),
'templates' => [],
])->willReturn('empty page content');
// Set up container
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
$container->has('security.authorization_checker')->willReturn(true);
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
$container->has('security.token_storage')->willReturn(true);
$container->get('security.token_storage')->willReturn($tokenStorage->reveal());
$container->has('twig')->willReturn(true);
$container->get('twig')->willReturn($twig->reveal());
// Use reflection to set the container
$reflection = new \ReflectionClass($controller);
$containerProperty = $reflection->getParentClass()->getProperty('container');
$containerProperty->setAccessible(true);
$containerProperty->setValue($controller, $container->reveal());
// Create request
$request = new Request();
// Execute the action
$response = $controller->myInvitations($request);
// Assert that page loads successfully
self::assertInstanceOf(Response::class, $response);
self::assertSame(200, $response->getStatusCode());
self::assertSame('empty page content', $response->getContent());
}
public function testMyInvitationsRequiresAuthentication(): void
{
// Create controller with minimal dependencies
$inviteRepository = $this->prophesize(InviteRepository::class);
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
$controller = new MyInvitationsController(
$inviteRepository->reveal(),
$paginatorFactory->reveal(),
$docGeneratorTemplateRepository->reveal()
);
// Set up authorization checker to return false for ROLE_USER
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
$authorizationChecker->isGranted('ROLE_USER')->willReturn(false);
$authorizationChecker->isGranted('ROLE_USER', null)->willReturn(false);
// Set up container
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
$container->has('security.authorization_checker')->willReturn(true);
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
// Use reflection to set the container
$reflection = new \ReflectionClass($controller);
$containerProperty = $reflection->getParentClass()->getProperty('container');
$containerProperty->setAccessible(true);
$containerProperty->setValue($controller, $container->reveal());
// Create request
$request = new Request();
// Expect AccessDeniedException
$this->expectException(\Symfony\Component\Security\Core\Exception\AccessDeniedException::class);
// Execute the action
$controller->myInvitations($request);
}
}

View File

@@ -20,4 +20,9 @@ use Doctrine\Persistence\ObjectRepository;
interface DocGeneratorTemplateRepositoryInterface extends ObjectRepository interface DocGeneratorTemplateRepositoryInterface extends ObjectRepository
{ {
public function countByEntity(string $entity): int; public function countByEntity(string $entity): int;
/**
* @return array|DocGeneratorTemplate[]
*/
public function findByEntity(string $entity, ?int $start = 0, ?int $limit = 50): array;
} }

View File

@@ -17,7 +17,7 @@ use Symfony\Component\Routing\RouterInterface;
/** /**
* Create paginator instances. * Create paginator instances.
*/ */
final readonly class PaginatorFactory implements PaginatorFactoryInterface class PaginatorFactory implements PaginatorFactoryInterface
{ {
final public const DEFAULT_CURRENT_PAGE_KEY = 'page'; final public const DEFAULT_CURRENT_PAGE_KEY = 'page';