125 lines
4.2 KiB
PHP
125 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Htmx;
|
|
|
|
use App\Htmx\HxRedirectResponse;
|
|
use App\Htmx\HxTrait;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class HxTraitTest extends TestCase
|
|
{
|
|
public function testHtmxRequestsGetAnHxRedirectInsteadOfA302(): void
|
|
{
|
|
$response = $this->controller()->redirectTo($this->request(['HTTP_HX-Request' => 'true']), '/bookings');
|
|
|
|
self::assertInstanceOf(HxRedirectResponse::class, $response);
|
|
self::assertSame('/bookings', $response->headers->get('HX-Redirect'));
|
|
// A 3xx would be followed by the browser and swapped as a whole page into the fragment.
|
|
self::assertSame(Response::HTTP_OK, $response->getStatusCode());
|
|
}
|
|
|
|
public function testOrdinaryRequestsGetANormalRedirect(): void
|
|
{
|
|
$response = $this->controller()->redirectTo($this->request(), '/bookings');
|
|
|
|
self::assertInstanceOf(RedirectResponse::class, $response);
|
|
self::assertSame('/bookings', $response->getTargetUrl());
|
|
}
|
|
|
|
public function testOobResponseConcatenatesEveryRequestedBlock(): void
|
|
{
|
|
$controller = $this->controller();
|
|
|
|
$response = $controller->oob('booking/index.html.twig', ['grid', 'floorplan']);
|
|
|
|
self::assertSame('[grid][floorplan]', $response->getContent());
|
|
self::assertSame(
|
|
[['booking/index.html.twig', 'grid'], ['booking/index.html.twig', 'floorplan']],
|
|
$controller->renderedBlocks,
|
|
);
|
|
}
|
|
|
|
public function testOobResponseFlagsTheContextSoBlocksCanEmitHxSwapOob(): void
|
|
{
|
|
$controller = $this->controller();
|
|
|
|
$controller->oob('booking/index.html.twig', ['grid'], ['date' => '2026-09-13']);
|
|
|
|
self::assertSame(['date' => '2026-09-13', 'htmx_oob_swap' => true], $controller->renderedContext);
|
|
}
|
|
|
|
public function testCallerSuppliedContextWinsOverTheInjectedFlag(): void
|
|
{
|
|
$controller = $this->controller();
|
|
|
|
$controller->oob('booking/index.html.twig', ['grid'], ['htmx_oob_swap' => false]);
|
|
|
|
self::assertFalse($controller->renderedContext['htmx_oob_swap']);
|
|
}
|
|
|
|
public function testPushUrlIsOptional(): void
|
|
{
|
|
$controller = $this->controller();
|
|
|
|
self::assertFalse($controller->oob('t.html.twig', ['b'])->headers->has('HX-Push-Url'));
|
|
self::assertSame(
|
|
'/bookings?date=2026-09-13',
|
|
$controller->oob('t.html.twig', ['b'], [], '/bookings?date=2026-09-13')->headers->get('HX-Push-Url'),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, string> $server
|
|
*/
|
|
private function request(array $server = []): Request
|
|
{
|
|
return Request::create('/bookings', server: $server);
|
|
}
|
|
|
|
private function controller(): object
|
|
{
|
|
return new class extends AbstractController {
|
|
use HxTrait;
|
|
|
|
/** @var list<array{0: string, 1: string}> */
|
|
public array $renderedBlocks = [];
|
|
|
|
/** @var array<string, mixed> */
|
|
public array $renderedContext = [];
|
|
|
|
/**
|
|
* @param string[] $blockNames
|
|
* @param array<string, mixed> $context
|
|
*/
|
|
public function oob(string $template, array $blockNames, array $context = [], ?string $pushUrl = null): Response
|
|
{
|
|
return $this->htmxOobResponse($template, $blockNames, $context, $pushUrl);
|
|
}
|
|
|
|
public function redirectTo(Request $request, string $url): Response
|
|
{
|
|
return $this->htmxRedirect($request, $url);
|
|
}
|
|
|
|
/**
|
|
* Stands in for Twig so the trait's own behaviour can be tested without a kernel.
|
|
*
|
|
* @param array<string, mixed> $parameters
|
|
*/
|
|
protected function renderBlockView(string $view, string $block, array $parameters = []): string
|
|
{
|
|
$this->renderedBlocks[] = [$view, $block];
|
|
$this->renderedContext = $parameters;
|
|
|
|
return \sprintf('[%s]', $block);
|
|
}
|
|
};
|
|
}
|
|
}
|