Files
ephub/tests/Controller/FloorPlanTest.php
T

189 lines
6.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Tests\Controller;
use App\Booking\TimeRange;
use App\Entity\Booking;
use App\Entity\Resource;
use App\Entity\ResourceType;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/**
* What a shape on the floor plan says.
*
* Who holds what is listed inside the box rather than in an SVG <title>: a tooltip only shows on
* hover, which is useless on touch and invisible when scanning the plan.
*/
class FloorPlanTest extends WebTestCase
{
private KernelBrowser $client;
private EntityManagerInterface $em;
protected function setUp(): void
{
$this->client = self::createClient();
$this->client->disableReboot();
$this->em = self::getContainer()->get(EntityManagerInterface::class);
$this->em->getConnection()->beginTransaction();
}
protected function tearDown(): void
{
$this->em->getConnection()->rollBack();
parent::tearDown();
}
public function testNoShapeCarriesATooltip(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Bea Kranz'), 540, 780);
$crawler = $this->board();
self::assertCount(0, $crawler->filter('svg title'));
self::assertCount(0, $crawler->filter('svg g title'));
}
public function testABookingIsListedInsideTheShape(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Bea Kranz'), 540, 780);
self::assertSame(
['Schreibtisch 01', 'Bea K. 09:00–13:00', 'frei 13:00–24:00'],
$this->linesOf($this->board()),
);
}
/**
* Full names do not fit a 140px box at this size, so they are shortened.
*/
public function testALongNameIsShortenedToAFirstNameAndInitial(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Maximilian Wolkenstein'), 0, 1440);
self::assertContains('Maximilian W.', $this->linesOf($this->board()));
}
public function testASingleWordNameIsLeftAlone(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Cher'), 0, 1440);
self::assertContains('Cher', $this->linesOf($this->board()));
}
public function testYourOwnBookingReadsAsDu(): void
{
$desk = $this->desk('desk-01');
$me = $this->user('[email protected]', 'Anna Berger');
$this->book($desk, $me, 540, 780);
self::assertContains('du 09:00–13:00', $this->linesOf($this->board($me)));
}
public function testAnAllDayBookingOmitsTheTimes(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Bea Kranz'), 0, 1440);
self::assertSame(['Schreibtisch 01', 'Bea K.'], $this->linesOf($this->board()));
}
/**
* A box fits three lines. More than that is summarised rather than allowed to spill out --
* and the counter has to account for the line the counter itself occupies.
*/
public function testTooManyBookingsAreSummarised(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Ann Alpha'), 0, 360);
$this->book($desk, $this->user('[email protected]', 'Bea Beta'), 360, 720);
$this->book($desk, $this->user('[email protected]', 'Cem Gamma'), 720, 1080);
$this->book($desk, $this->user('[email protected]', 'Dia Delta'), 1080, 1440);
$lines = $this->linesOf($this->board());
self::assertSame(
['Schreibtisch 01', 'Ann A. 00:00–06:00', 'Bea B. 06:00–12:00', '+2 weitere'],
$lines,
);
// Label plus MAX_LINES, never more.
self::assertLessThanOrEqual(4, \count($lines));
}
public function testAFreeShapeShowsOnlyItsLabel(): void
{
$this->desk('desk-01');
self::assertSame(['Schreibtisch 01'], $this->linesOf($this->board()));
}
/**
* Screen readers get the same information the box shows, because role="img" on the <svg>
* would otherwise hide every one of those <text> elements.
*/
public function testTheShapeCarriesAnAccessibleLabel(): void
{
$desk = $this->desk('desk-01');
$this->book($desk, $this->user('[email protected]', 'Bea Kranz'), 540, 780);
$label = $this->board()->filter('svg g[aria-label]')->attr('aria-label');
self::assertSame('Schreibtisch 01 — Bea K. 09:00–13:00, frei 13:00–24:00', $label);
}
/**
* @return list<string>
*/
private function linesOf(\Symfony\Component\DomCrawler\Crawler $crawler): array
{
return $crawler->filter('svg g text')->each(
static fn (\Symfony\Component\DomCrawler\Crawler $node): string => trim($node->text()),
);
}
private function board(?User $as = null): \Symfony\Component\DomCrawler\Crawler
{
$this->client->loginUser($as ?? $this->user('[email protected]', 'Anna Berger'));
return $this->client->request('GET', '/book/desk?date=2026-10-01');
}
private function desk(string $svgElementId): Resource
{
$resource = new Resource(ResourceType::DESK, 'Schreibtisch 01', $svgElementId);
$this->em->persist($resource);
$this->em->flush();
return $resource;
}
private function book(Resource $resource, User $user, int $start, int $end): void
{
$this->em->persist(new Booking($user, $resource, new \DateTimeImmutable('2026-10-01'), TimeRange::fromMinutes($start, $end)));
$this->em->flush();
}
private function user(string $email, string $name): User
{
$existing = $this->em->getRepository(User::class)->findOneBy(['email' => $email]);
if (null !== $existing) {
return $existing;
}
$user = new User($email, $name);
$user->setRoles(['ROLE_EMPLOYEE']);
$this->em->persist($user);
$this->em->flush();
return $user;
}
}