Skip to content

Commit 59e07f0

Browse files
committed
LiveUrlSubscriberTest
1 parent d005f12 commit 59e07f0

File tree

2 files changed

+232
-14
lines changed

2 files changed

+232
-14
lines changed

src/LiveComponent/src/EventListener/LiveUrlSubscriber.php

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadataFactory;
1919
use Symfony\UX\LiveComponent\Util\UrlFactory;
2020

21+
/**
22+
* @internal
23+
*/
2124
class LiveUrlSubscriber implements EventSubscriberInterface
2225
{
2326
private const URL_HEADER = 'X-Live-Url';
@@ -41,13 +44,12 @@ public function onKernelResponse(ResponseEvent $event): void
4144
$newUrl = null;
4245
if ($previousLocation = $request->headers->get(self::URL_HEADER)) {
4346
$liveProps = $this->getLivePropsToMap($request);
44-
if (!empty($liveProps)) {
45-
$newUrl = $this->urlFactory->createFromPreviousAndProps(
46-
$previousLocation,
47-
$liveProps['path'],
48-
$liveProps['query']
49-
);
50-
}
47+
$newUrl = $this->urlFactory->createFromPreviousAndProps(
48+
$previousLocation,
49+
$liveProps['path'],
50+
$liveProps['query']
51+
);
52+
5153
}
5254

5355
if ($newUrl) {
@@ -71,20 +73,20 @@ private function getLivePropsToMap(Request $request): array
7173
$component = $request->attributes->get('_mounted_component');
7274
$metadata = $this->metadataFactory->getMetadata($componentName);
7375

74-
$liveData = $request->attributes->get('_live_request_data') ?? [];
76+
$liveRequestData = $request->attributes->get('_live_request_data') ?? [];
7577
$values = array_merge(
76-
$liveData['props'] ?? [],
77-
$liveData['updated'] ?? [],
78-
$liveData['responseProps'] ?? []
78+
$liveRequestData['props'] ?? [],
79+
$liveRequestData['updated'] ?? [],
80+
$liveRequestData['responseProps'] ?? []
7981
);
8082

8183
$urlLiveProps = [
8284
'path' => [],
8385
'query' => [],
8486
];
85-
foreach ($metadata->getAllLivePropsMetadata($component) as $liveProp) {
86-
$name = $liveProp->getName();
87-
$urlMapping = $liveProp->urlMapping();
87+
foreach ($metadata->getAllLivePropsMetadata($component) as $livePropMetadata) {
88+
$name = $livePropMetadata->getName();
89+
$urlMapping = $livePropMetadata->urlMapping();
8890
if (isset($values[$name]) && $urlMapping) {
8991
$urlLiveProps[$urlMapping->mapPath ? 'path' : 'query'][$urlMapping->as ?? $name] =
9092
$values[$name];
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\LiveComponent\Tests\Unit\EventListener;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\HttpKernel\Event\ResponseEvent;
18+
use Symfony\Component\HttpKernel\HttpKernelInterface;
19+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
20+
use Symfony\UX\LiveComponent\EventListener\LiveUrlSubscriber;
21+
use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadata;
22+
use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadataFactory;
23+
use Symfony\UX\LiveComponent\Metadata\LivePropMetadata;
24+
use Symfony\UX\LiveComponent\Metadata\UrlMapping;
25+
use Symfony\UX\LiveComponent\Util\UrlFactory;
26+
27+
class LiveUrlSubscriberTest extends TestCase
28+
{
29+
//@todo also do functionnal test ?
30+
31+
public function getIgnoreData(): iterable
32+
{
33+
yield 'not_a_live_component' => [
34+
'attributes' => [],
35+
'requestType' => HttpKernelInterface::MAIN_REQUEST,
36+
'headers' => ['X-Live-Url' => '/foo/bar'],
37+
];
38+
yield 'not_main_request' => [
39+
'attributes' => ['_live_component' => 'componentName'],
40+
'requestType' => HttpKernelInterface::SUB_REQUEST,
41+
'headers' => ['X-Live-Url' => '/foo/bar'],
42+
];
43+
yield 'no_previous_url' => [
44+
'attributes' => ['_live_component' => 'componentName'],
45+
'requestType' => HttpKernelInterface::MAIN_REQUEST,
46+
'headers' => [],
47+
];
48+
}
49+
50+
/**
51+
* @dataProvider getIgnoreData
52+
*/
53+
public function testDoNothing(
54+
array $attributes = ['_live_component' => 'componentName'],
55+
int $requestType = HttpKernelInterface::MAIN_REQUEST,
56+
array $headers = ['X-Live-Url' => '/foo/bar']
57+
): void {
58+
$request = new Request();
59+
$request->attributes->add($attributes);
60+
$request->headers->add($headers);
61+
$response = new Response();
62+
$event = new ResponseEvent(
63+
$this->createMock(HttpKernelInterface::class),
64+
$request,
65+
$requestType,
66+
$response
67+
);
68+
69+
$metadataFactory = $this->createMock(LiveComponentMetadataFactory::class);
70+
$metadataFactory->expects(self::never())->method('getMetadata');
71+
$urlFactory = $this->createMock(UrlFactory::class);
72+
$urlFactory->expects(self::never())->method('createFromPreviousAndProps');
73+
$liveUrlSubscriber = new LiveUrlSubscriber($metadataFactory, $urlFactory);
74+
75+
$liveUrlSubscriber->onKernelResponse($event);
76+
$this->assertNull($response->headers->get('X-Live-Url'));
77+
}
78+
79+
public function getData(): iterable
80+
{
81+
yield 'prop_without_matching_property' => [
82+
'liveRequestData' => [
83+
'props' => ['notMatchingProp' => 0]
84+
],
85+
];
86+
yield 'prop_matching_non_mapped_property' => [
87+
'liveRequestData' => [
88+
'props' => ['nonMappedProp' => 0]
89+
],
90+
];
91+
yield 'props_matching_query_mapped_properties' => [
92+
'liveRequestData' => [
93+
'props' => ['queryMappedProp1' => 1],
94+
'updated' => ['queryMappedProp2' => 2],
95+
'responseProps' => ['queryMappedProp3' => 3]
96+
],
97+
'expectedPathProps' => [],
98+
'expectedQueryProps' => [
99+
'queryMappedProp1' => 1,
100+
'queryMappedProp2' => 2,
101+
'queryMappedProp3' => 3,
102+
],
103+
];
104+
yield 'props_matching_path_mapped_properties' => [
105+
'liveRequestData' => [
106+
'props' => ['pathMappedProp1' => 1],
107+
'updated' => ['pathMappedProp2' => 2],
108+
'responseProps' => ['pathMappedProp3' => 3]
109+
],
110+
'expectedPathProps' => [
111+
'pathMappedProp1' => 1,
112+
'pathMappedProp2' => 2,
113+
'pathMappedProp3' => 3,
114+
],
115+
'expectedQueryProps' => []
116+
];
117+
yield 'props_matching_properties_with_alias' => [
118+
'liveRequestData' => [
119+
'props' => ['pathMappedPropWithAlias' => 1, 'queryMappedPropWithAlias' => 2]
120+
],
121+
'expectedPathProps' => ['pathAlias' => 1],
122+
'expectedQueryProps' => ['queryAlias' => 2],
123+
];
124+
yield 'responseProps_have_highest_priority' => [
125+
'liveRequestData' => [
126+
'props' => ['queryMappedProp1' => 1],
127+
'updated' => ['queryMappedProp1' => 2],
128+
'responseProps' => ['queryMappedProp1' => 3]
129+
],
130+
'expectedPathProps' => [],
131+
'expectedQueryProps' => ['queryMappedProp1' => 3],
132+
];
133+
yield 'updated_have_second_priority' => [
134+
'liveRequestData' => [
135+
'props' => ['queryMappedProp1' => 1],
136+
'updated' => ['queryMappedProp1' => 2],
137+
],
138+
'expectedPathProps' => [],
139+
'expectedQueryProps' => ['queryMappedProp1' => 2],
140+
];
141+
}
142+
143+
/**
144+
* @dataProvider getData
145+
*/
146+
public function testProps(
147+
array $liveRequestData,
148+
array $expectedPathProps = [],
149+
array $expectedQueryProps = []
150+
): void {
151+
$previousLocation = '/foo/bar';
152+
$newLocation = '/foo/baz';
153+
$componentName = 'componentName';
154+
$component = $this->createMock(\stdClass::class);
155+
$metaData = $this->createMock(LiveComponentMetadata::class);
156+
$metaData->expects(self::once())
157+
->method('getAllLivePropsMetadata')
158+
->with($component)
159+
->willReturn([
160+
$this->createLivePropMetadata('nonMappedProp'),
161+
$this->createLivePropMetadata('queryMappedProp1', true),
162+
$this->createLivePropMetadata('queryMappedProp2', true),
163+
$this->createLivePropMetadata('queryMappedProp3', true),
164+
$this->createLivePropMetadata('pathMappedProp1', true, true),
165+
$this->createLivePropMetadata('pathMappedProp2', true, true),
166+
$this->createLivePropMetadata('pathMappedProp3', true, true),
167+
$this->createLivePropMetadata('queryMappedPropWithAlias', true, false, 'queryAlias'),
168+
$this->createLivePropMetadata('pathMappedPropWithAlias', true, true, 'pathAlias'),
169+
]);
170+
$request = new Request();
171+
$request->attributes->add([
172+
'_live_component' => $componentName,
173+
'_mounted_component' => $component,
174+
'_live_request_data' => $liveRequestData,
175+
]);
176+
$request->headers->add(['X-Live-Url' => $previousLocation]);
177+
$response = new Response();
178+
$event = new ResponseEvent(
179+
$this->createMock(HttpKernelInterface::class),
180+
$request,
181+
HttpKernelInterface::MAIN_REQUEST,
182+
$response
183+
);
184+
185+
$metadataFactory = $this->createMock(LiveComponentMetadataFactory::class);
186+
$metadataFactory->expects(self::once())->method('getMetadata')->with($componentName)->willReturn($metaData);
187+
$urlFactory = $this->createMock(UrlFactory::class);
188+
$liveUrlSubscriber = new LiveUrlSubscriber($metadataFactory, $urlFactory);
189+
190+
$urlFactory->expects(self::once())
191+
->method('createFromPreviousAndProps')
192+
->with($previousLocation, $expectedPathProps, $expectedQueryProps)
193+
->willReturn($newLocation);
194+
$liveUrlSubscriber->onKernelResponse($event);
195+
$this->assertEquals($newLocation, $response->headers->get('X-Live-Url'));
196+
197+
}
198+
199+
private function createLivePropMetadata(
200+
string $name,
201+
bool $url = false,
202+
bool $mapPath = false,
203+
?string $as = null,
204+
): LivePropMetadata {
205+
return new LivePropMetadata(
206+
$name,
207+
new LiveProp(
208+
url: $url ? new UrlMapping($as, $mapPath) : false
209+
),
210+
null,
211+
true,
212+
true,
213+
null
214+
);
215+
}
216+
}

0 commit comments

Comments
 (0)