From 73f692cf9a6157c087b48864a50b9e8b2ff8ffe3 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Mon, 5 May 2025 14:39:18 +0200 Subject: [PATCH 01/15] Add assert in test live component --- .../src/Test/InteractsWithLiveComponents.php | 20 ++++++++++++ .../src/Test/TestLiveComponent.php | 32 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index 377fbad1f34..a3d6418491e 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -44,4 +44,24 @@ protected function createLiveComponent(string $name, array $data = [], ?KernelBr self::getContainer()->get('router'), ); } + + protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $eventName, ?array $parameters = null): void + { + $eventData = $testLiveComponent->getEmittedEvent($testLiveComponent->render(), $eventName); + + $this->assertNotNull($eventData, \sprintf('Event %s not emitted', $eventName)); + + if (null === $parameters) { + return; + } + + foreach ($parameters as $key => $value) { + $this->assertSame($value, $eventData['data'][$key], \sprintf('EventData (%s) is not valid', $key)); + } + } + + protected function assertComponentNotEmitEvent(TestLiveComponent $testLiveComponent, string $eventName): void + { + $this->assertNull($this->testLiveComponent($testLiveComponent->render(), $eventName), \sprintf('Event %s emitted', $eventName)); + } } diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index 0e587a38256..54a9ece127f 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -229,4 +229,36 @@ private function flattenFormValues(array $values, string $prefix = ''): array return $result; } + + /** + * @return ?array{data: array, event: string} + */ + public function getEmittedEvent(RenderedComponent $render, string $eventName): ?array + { + $eventsData = $this->getEmittedEvents($render); + + foreach ($eventsData as $eventData) { + if ($eventData['event'] === $eventName) { + return $eventData; + } + } + + return null; + } + + /** + * @return array, event: string}> + */ + public function getEmittedEvents(RenderedComponent $render): array + { + $div = $render->crawler()->filter('div'); + + $emit = $div->attr('data-live-events-to-emit-value'); + + if (null === $emit) { + return []; + } + + return \json_decode($emit, true); + } } From 03c08b59e0370757c5a5ed19056bafcbc493cdde Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:18:25 +0200 Subject: [PATCH 02/15] Quality code --- src/LiveComponent/src/Test/TestLiveComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index 54a9ece127f..82deea2e792 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -259,6 +259,6 @@ public function getEmittedEvents(RenderedComponent $render): array return []; } - return \json_decode($emit, true); + return json_decode($emit, true); } } From 97efa07e6a88fffc1e9eb09564faeeda116a0340 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Tue, 10 Jun 2025 14:31:13 +0200 Subject: [PATCH 03/15] Add tests --- .../src/Test/InteractsWithLiveComponents.php | 4 +-- .../Test/InteractsWithLiveComponentsTest.php | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index a3d6418491e..192555a1734 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -56,12 +56,12 @@ protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent } foreach ($parameters as $key => $value) { - $this->assertSame($value, $eventData['data'][$key], \sprintf('EventData (%s) is not valid', $key)); + $this->assertSame($value, $eventData['data'][$key] ?? null, \sprintf('EventData (%s) is not valid', $key)); } } protected function assertComponentNotEmitEvent(TestLiveComponent $testLiveComponent, string $eventName): void { - $this->assertNull($this->testLiveComponent($testLiveComponent->render(), $eventName), \sprintf('Event %s emitted', $eventName)); + $this->assertNull($testLiveComponent->getEmittedEvent($testLiveComponent->render(), $eventName), \sprintf('Event %s emitted', $eventName)); } } diff --git a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php index 097e4d770f7..e7e760a45b2 100644 --- a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php +++ b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php @@ -11,6 +11,7 @@ namespace Symfony\UX\LiveComponent\Tests\Functional\Test; +use PHPUnit\Framework\AssertionFailedError; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\User\InMemoryUser; @@ -217,4 +218,38 @@ public function testSetLocaleRenderLocalizedComponent(): void $testComponent->setRouteLocale('de'); $this->assertStringContainsString('Locale: de', $testComponent->render()); } + + public function testComponentEmitsExpectedEventWithParameters(): void + { + $testComponent = $this->createLiveComponent('component_with_emit'); + + $testComponent->call('actionThatEmits'); + + $this->assertComponentEmitEvent($testComponent, 'event1', [ + 'foo' => 'bar', + ]); + } + + public function testComponentDoesNotEmitUnexpectedEvent(): void + { + $testComponent = $this->createLiveComponent('component_with_emit'); + + $testComponent->call('actionThatEmits'); + + $this->assertComponentNotEmitEvent($testComponent, 'non_emitted_event'); + } + + public function testComponentEmitsEventWithWrongParametersFails(): void + { + $testComponent = $this->createLiveComponent('component_with_emit'); + + $testComponent->call('actionThatEmits'); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('EventData (foo2) is not valid'); + $this->assertComponentEmitEvent($testComponent, 'event1', [ + 'foo' => 'bar', + 'foo2' => 'bar2', + ]); + } } From 33580ad489f19283a3a265fba62fc75f114db4cd Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Tue, 10 Jun 2025 14:44:19 +0200 Subject: [PATCH 04/15] Generalize for components with a tag other than div --- src/LiveComponent/src/Test/TestLiveComponent.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index 82deea2e792..58822479ded 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -251,8 +251,7 @@ public function getEmittedEvent(RenderedComponent $render, string $eventName): ? */ public function getEmittedEvents(RenderedComponent $render): array { - $div = $render->crawler()->filter('div'); - + $div = $render->crawler()->filter('[data-live-name-value]'); $emit = $div->attr('data-live-events-to-emit-value'); if (null === $emit) { From 54116e3f07074ee102f1650b56951ce7bee1b808 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Wed, 11 Jun 2025 17:01:34 +0200 Subject: [PATCH 05/15] Add documentation --- src/LiveComponent/doc/index.rst | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/LiveComponent/doc/index.rst b/src/LiveComponent/doc/index.rst index 290b07bb5dc..87c8a25b904 100644 --- a/src/LiveComponent/doc/index.rst +++ b/src/LiveComponent/doc/index.rst @@ -3829,6 +3829,44 @@ uses Symfony's test client to render and make requests to your components:: The ``InteractsWithLiveComponents`` trait can only be used in tests that extend ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase``. +When testing live components, you can assert whether a specific event has been emitted using new assertion methods provided by the ``InteractsWithLiveComponents`` trait. + +Use the following assertions to verify event emissions from your live component:: + + use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + use Symfony\UX\LiveComponent\Test\InteractsWithLiveComponents; + + class MyComponentTest extends KernelTestCase + { + use InteractsWithLiveComponents; + + public function testEventEmission(): void + { + $testComponent = $this->createLiveComponent( + name: 'MyComponent', + data: ['foo' => 'bar'], + ); + + // Call an action that emits an event + $render = $testComponent->call('triggerEvent')->render(); + + // Assert that the event was emitted with arguments + $this->componentHasEmittedEvent($render, 'event-name', [ + 'eventArg1' => 'value', + ]); + + // Assert that a specific event was *not* emitted + $this->assertComponentNotEmitEvent($render, 'unwanted-event'); + } + } + +.. note:: + + These assertions are only available when using the ``InteractsWithLiveComponents`` trait in a test class that extends + ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase``. + +--- + Test LiveCollectionType ~~~~~~~~~~~~~~~~~~~~~~~ From 6294284f968f60600bf60d07e029704b3e422415 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Wed, 11 Jun 2025 18:02:20 +0200 Subject: [PATCH 06/15] Complete documentation --- src/LiveComponent/doc/index.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/LiveComponent/doc/index.rst b/src/LiveComponent/doc/index.rst index 87c8a25b904..28299518d2a 100644 --- a/src/LiveComponent/doc/index.rst +++ b/src/LiveComponent/doc/index.rst @@ -3781,6 +3781,11 @@ uses Symfony's test client to render and make requests to your components:: ->emit('increaseEvent', ['amount' => 2]) // emit a live event with arguments ; + // Assert that the event was emitted + $this->componentHasEmittedEvent($render, 'increaseEvent', [ + 'amount' => 2, + ]); + // set live props $testComponent ->set('count', 99) @@ -3850,7 +3855,7 @@ Use the following assertions to verify event emissions from your live component: // Call an action that emits an event $render = $testComponent->call('triggerEvent')->render(); - // Assert that the event was emitted with arguments + // Assert that the event was emitted $this->componentHasEmittedEvent($render, 'event-name', [ 'eventArg1' => 'value', ]); From 908b24075318d82d170127fbf78434c004e24055 Mon Sep 17 00:00:00 2001 From: Arkalo <24898676+Arkalo2@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:09:21 +0200 Subject: [PATCH 07/15] Update src/LiveComponent/src/Test/TestLiveComponent.php Co-authored-by: Hugo Alliaume --- src/LiveComponent/src/Test/TestLiveComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index 58822479ded..e16d6c1451d 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -231,7 +231,7 @@ private function flattenFormValues(array $values, string $prefix = ''): array } /** - * @return ?array{data: array, event: string} + * @return ?array{data: array, event: non-empty-string} */ public function getEmittedEvent(RenderedComponent $render, string $eventName): ?array { From 0b06627d056ddc2b397a04a6a60e8d4cfc78944a Mon Sep 17 00:00:00 2001 From: Arkalo <24898676+Arkalo2@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:09:39 +0200 Subject: [PATCH 08/15] Update src/LiveComponent/src/Test/TestLiveComponent.php Co-authored-by: Hugo Alliaume --- src/LiveComponent/src/Test/TestLiveComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index e16d6c1451d..b7cc159d351 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -258,6 +258,6 @@ public function getEmittedEvents(RenderedComponent $render): array return []; } - return json_decode($emit, true); + return json_decode($emit, associative: true, flags: \JSON_THROW_ON_ERROR); } } From 5d73794b529edbf86e7ab9d97e1fcfa7b83e3fa7 Mon Sep 17 00:00:00 2001 From: Arkalo <24898676+Arkalo2@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:11:32 +0200 Subject: [PATCH 09/15] Update src/LiveComponent/src/Test/TestLiveComponent.php Co-authored-by: Hugo Alliaume --- src/LiveComponent/src/Test/TestLiveComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index b7cc159d351..e5dd95d0d9d 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -247,7 +247,7 @@ public function getEmittedEvent(RenderedComponent $render, string $eventName): ? } /** - * @return array, event: string}> + * @return array, event: non-empty-string}> */ public function getEmittedEvents(RenderedComponent $render): array { From 2c5191f32acc0f52b1f4262cec7421d9124dac03 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Thu, 12 Jun 2025 11:54:23 +0200 Subject: [PATCH 10/15] Feedback, add tests and add getName function on TestLiveComponent --- .../src/Test/InteractsWithLiveComponents.php | 25 +++++++++++---- .../src/Test/TestLiveComponent.php | 16 ++++++---- .../Test/InteractsWithLiveComponentsTest.php | 32 ++++++++++++++++--- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index 192555a1734..31fcb7b1f38 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -45,23 +45,34 @@ protected function createLiveComponent(string $name, array $data = [], ?KernelBr ); } - protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $eventName, ?array $parameters = null): void + protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $expectedEventName, ?array $expectedEventData = null): void { - $eventData = $testLiveComponent->getEmittedEvent($testLiveComponent->render(), $eventName); + $event = $testLiveComponent->getEmittedEvent($testLiveComponent->render(), $expectedEventName); - $this->assertNotNull($eventData, \sprintf('Event %s not emitted', $eventName)); + $this->assertNotNull($event, \sprintf('The component "%s" did not emit event "%s".', $testLiveComponent->getName(), $expectedEventName)); - if (null === $parameters) { + if (null === $expectedEventData) { return; } - foreach ($parameters as $key => $value) { - $this->assertSame($value, $eventData['data'][$key] ?? null, \sprintf('EventData (%s) is not valid', $key)); + foreach ($expectedEventData as $key => $value) { + $this->assertArrayHasKey($key, $event['data'], \sprintf('The expected event "%s" data "%s" does not exists', $event['event'], $key)); + $this->assertSame( + $value, + $event['data'][$key], + \sprintf( + 'The expected event "%s" data "%s" expected "%s" but "%s" given', + $event['event'], + $key, + $value, + $event['data'][$key] + ) + ); } } protected function assertComponentNotEmitEvent(TestLiveComponent $testLiveComponent, string $eventName): void { - $this->assertNull($testLiveComponent->getEmittedEvent($testLiveComponent->render(), $eventName), \sprintf('Event %s emitted', $eventName)); + $this->assertNull($testLiveComponent->getEmittedEvent($testLiveComponent->render(), $eventName), \sprintf('The component "%s" did not emit event "%s".', $testLiveComponent->getName(), $eventName)); } } diff --git a/src/LiveComponent/src/Test/TestLiveComponent.php b/src/LiveComponent/src/Test/TestLiveComponent.php index e5dd95d0d9d..580c8f8415f 100644 --- a/src/LiveComponent/src/Test/TestLiveComponent.php +++ b/src/LiveComponent/src/Test/TestLiveComponent.php @@ -235,11 +235,11 @@ private function flattenFormValues(array $values, string $prefix = ''): array */ public function getEmittedEvent(RenderedComponent $render, string $eventName): ?array { - $eventsData = $this->getEmittedEvents($render); + $events = $this->getEmittedEvents($render); - foreach ($eventsData as $eventData) { - if ($eventData['event'] === $eventName) { - return $eventData; + foreach ($events as $event) { + if ($event['event'] === $eventName) { + return $event; } } @@ -251,8 +251,7 @@ public function getEmittedEvent(RenderedComponent $render, string $eventName): ? */ public function getEmittedEvents(RenderedComponent $render): array { - $div = $render->crawler()->filter('[data-live-name-value]'); - $emit = $div->attr('data-live-events-to-emit-value'); + $emit = $render->crawler()->filter('[data-live-name-value]')->attr('data-live-events-to-emit-value'); if (null === $emit) { return []; @@ -260,4 +259,9 @@ public function getEmittedEvents(RenderedComponent $render): array return json_decode($emit, associative: true, flags: \JSON_THROW_ON_ERROR); } + + public function getName(): string + { + return $this->metadata->getName(); + } } diff --git a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php index e7e760a45b2..b671d4bffd9 100644 --- a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php +++ b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php @@ -219,7 +219,7 @@ public function testSetLocaleRenderLocalizedComponent(): void $this->assertStringContainsString('Locale: de', $testComponent->render()); } - public function testComponentEmitsExpectedEventWithParameters(): void + public function testComponentEmitsExpectedEventWithExpectedEventData(): void { $testComponent = $this->createLiveComponent('component_with_emit'); @@ -236,20 +236,44 @@ public function testComponentDoesNotEmitUnexpectedEvent(): void $testComponent->call('actionThatEmits'); - $this->assertComponentNotEmitEvent($testComponent, 'non_emitted_event'); + $this->assertComponentNotEmitEvent($testComponent, 'event2'); } - public function testComponentEmitsEventWithWrongParametersFails(): void + public function testComponentDoesNotEmitUnexpectedEventFails(): void { $testComponent = $this->createLiveComponent('component_with_emit'); $testComponent->call('actionThatEmits'); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('EventData (foo2) is not valid'); + $this->expectExceptionMessage('The component "component_with_emit" did not emit event "event1".'); + $this->assertComponentNotEmitEvent($testComponent, 'event1'); + } + + public function testComponentEmitsEventWithNotFoundExpectedDataFails(): void + { + $testComponent = $this->createLiveComponent('component_with_emit'); + + $testComponent->call('actionThatEmits'); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('The expected event "event1" data "foo2" does not exists'); $this->assertComponentEmitEvent($testComponent, 'event1', [ 'foo' => 'bar', 'foo2' => 'bar2', ]); } + + public function testComponentEmitsEventWithNotValidExpectedDataFails(): void + { + $testComponent = $this->createLiveComponent('component_with_emit'); + + $testComponent->call('actionThatEmits'); + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('The expected event "event1" data "foo" expected "bar2" but "bar" given'); + $this->assertComponentEmitEvent($testComponent, 'event1', [ + 'foo' => 'bar2', + ]); + } } From b433fd1a84d1e0562d9794d4708a0cdbcac33a33 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Thu, 12 Jun 2025 16:27:43 +0200 Subject: [PATCH 11/15] Remove documentation paraph --- src/LiveComponent/doc/index.rst | 38 --------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/LiveComponent/doc/index.rst b/src/LiveComponent/doc/index.rst index 28299518d2a..f19ebb4ac05 100644 --- a/src/LiveComponent/doc/index.rst +++ b/src/LiveComponent/doc/index.rst @@ -3834,44 +3834,6 @@ uses Symfony's test client to render and make requests to your components:: The ``InteractsWithLiveComponents`` trait can only be used in tests that extend ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase``. -When testing live components, you can assert whether a specific event has been emitted using new assertion methods provided by the ``InteractsWithLiveComponents`` trait. - -Use the following assertions to verify event emissions from your live component:: - - use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; - use Symfony\UX\LiveComponent\Test\InteractsWithLiveComponents; - - class MyComponentTest extends KernelTestCase - { - use InteractsWithLiveComponents; - - public function testEventEmission(): void - { - $testComponent = $this->createLiveComponent( - name: 'MyComponent', - data: ['foo' => 'bar'], - ); - - // Call an action that emits an event - $render = $testComponent->call('triggerEvent')->render(); - - // Assert that the event was emitted - $this->componentHasEmittedEvent($render, 'event-name', [ - 'eventArg1' => 'value', - ]); - - // Assert that a specific event was *not* emitted - $this->assertComponentNotEmitEvent($render, 'unwanted-event'); - } - } - -.. note:: - - These assertions are only available when using the ``InteractsWithLiveComponents`` trait in a test class that extends - ``Symfony\Bundle\FrameworkBundle\Test\KernelTestCase``. - ---- - Test LiveCollectionType ~~~~~~~~~~~~~~~~~~~~~~~ From 04d49551fd22df454329c669beb3368c4d66543f Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:05:28 +0200 Subject: [PATCH 12/15] Add withData and withDataSubset functions --- .../src/Test/InteractsWithLiveComponents.php | 46 +++++++++++------- .../Fixtures/Component/ComponentWithEmit.php | 2 +- .../tests/Functional/LiveResponderTest.php | 2 +- .../Test/InteractsWithLiveComponentsTest.php | 48 ++++++++++++------- 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index 31fcb7b1f38..ac87513c4ab 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -45,30 +45,40 @@ protected function createLiveComponent(string $name, array $data = [], ?KernelBr ); } - protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $expectedEventName, ?array $expectedEventData = null): void + protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $expectedEventName): object { $event = $testLiveComponent->getEmittedEvent($testLiveComponent->render(), $expectedEventName); $this->assertNotNull($event, \sprintf('The component "%s" did not emit event "%s".', $testLiveComponent->getName(), $expectedEventName)); - if (null === $expectedEventData) { - return; - } + return new class($this, $event['event'], $event['data']) { + /** + * @param array $data + */ + public function __construct(private KernelTestCase $parent, private readonly string $eventName, private readonly array $data) {} - foreach ($expectedEventData as $key => $value) { - $this->assertArrayHasKey($key, $event['data'], \sprintf('The expected event "%s" data "%s" does not exists', $event['event'], $key)); - $this->assertSame( - $value, - $event['data'][$key], - \sprintf( - 'The expected event "%s" data "%s" expected "%s" but "%s" given', - $event['event'], - $key, - $value, - $event['data'][$key] - ) - ); - } + public function withDataSubset(array $expectedEventData): void + { + foreach ($expectedEventData as $key => $value) { + $this->parent->assertArrayHasKey($key, $this->data, \sprintf('The expected event "%s" data "%s" does not exists', $this->eventName, $key)); + $this->parent->assertSame( + $value, + $this->data[$key], + \sprintf( + 'The expected event "%s" data "%s" expected "%s" but "%s" given', + $this->eventName, + $key, + $value, + $this->data[$key] + ) + ); + } + } + public function withData(array $expectedEventData): void + { + $this->parent->assertEquals($expectedEventData, $this->data, sprintf('The expected event "%s" data does not match.', $this->eventName)); + } + }; } protected function assertComponentNotEmitEvent(TestLiveComponent $testLiveComponent, string $eventName): void diff --git a/src/LiveComponent/tests/Fixtures/Component/ComponentWithEmit.php b/src/LiveComponent/tests/Fixtures/Component/ComponentWithEmit.php index 2b8325c81c4..14753bfbf66 100644 --- a/src/LiveComponent/tests/Fixtures/Component/ComponentWithEmit.php +++ b/src/LiveComponent/tests/Fixtures/Component/ComponentWithEmit.php @@ -29,7 +29,7 @@ final class ComponentWithEmit #[LiveAction] public function actionThatEmits(): void { - $this->emit('event1', ['foo' => 'bar']); + $this->emit('event1', ['foo' => 'bar', 'bar' => 'foo']); $this->events = $this->liveResponder->getEventsToEmit(); } diff --git a/src/LiveComponent/tests/Functional/LiveResponderTest.php b/src/LiveComponent/tests/Functional/LiveResponderTest.php index 8d533164eb9..992a42ecef3 100644 --- a/src/LiveComponent/tests/Functional/LiveResponderTest.php +++ b/src/LiveComponent/tests/Functional/LiveResponderTest.php @@ -35,7 +35,7 @@ public function testComponentCanEmitEvents(): void ]) ->assertSuccessful() ->assertSee('Event: event1') - ->assertSee('Data: {"foo":"bar"}'); + ->assertSee('Data: {"foo":"bar","bar":"foo"}'); } public function testComponentCanDispatchBrowserEvents(): void diff --git a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php index b671d4bffd9..b01eb1af335 100644 --- a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php +++ b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php @@ -219,61 +219,73 @@ public function testSetLocaleRenderLocalizedComponent(): void $this->assertStringContainsString('Locale: de', $testComponent->render()); } - public function testComponentEmitsExpectedEventWithExpectedEventData(): void + public function testComponentEmitsExpectedEventData(): void { $testComponent = $this->createLiveComponent('component_with_emit'); $testComponent->call('actionThatEmits'); - $this->assertComponentEmitEvent($testComponent, 'event1', [ + $this->assertComponentEmitEvent($testComponent, 'event1')->withData([ 'foo' => 'bar', + 'bar' => 'foo', ]); } - public function testComponentDoesNotEmitUnexpectedEvent(): void + public function testComponentEmitsExpectedEventDataFails(): void { $testComponent = $this->createLiveComponent('component_with_emit'); $testComponent->call('actionThatEmits'); - $this->assertComponentNotEmitEvent($testComponent, 'event2'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('The expected event "event1" data does not match'); + $this->assertComponentEmitEvent($testComponent, 'event1')->withData([ + 'foo' => 'bar', + ]); } - public function testComponentDoesNotEmitUnexpectedEventFails(): void + public function testComponentEmitsExpectedPartialEventData(): void { $testComponent = $this->createLiveComponent('component_with_emit'); $testComponent->call('actionThatEmits'); - $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('The component "component_with_emit" did not emit event "event1".'); - $this->assertComponentNotEmitEvent($testComponent, 'event1'); + $this->assertComponentEmitEvent($testComponent, 'event1')->withDataSubset([ + 'foo' => 'bar', + ]); + } + + public function testComponentDoesNotEmitUnexpectedEvent(): void + { + $testComponent = $this->createLiveComponent('component_with_emit'); + + $testComponent->call('actionThatEmits'); + + $this->assertComponentNotEmitEvent($testComponent, 'event2'); } - public function testComponentEmitsEventWithNotFoundExpectedDataFails(): void + public function testComponentDoesNotEmitUnexpectedEventFails(): void { $testComponent = $this->createLiveComponent('component_with_emit'); $testComponent->call('actionThatEmits'); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('The expected event "event1" data "foo2" does not exists'); - $this->assertComponentEmitEvent($testComponent, 'event1', [ - 'foo' => 'bar', - 'foo2' => 'bar2', - ]); + $this->expectExceptionMessage('The component "component_with_emit" did not emit event "event1".'); + $this->assertComponentNotEmitEvent($testComponent, 'event1'); } - public function testComponentEmitsEventWithNotValidExpectedDataFails(): void + public function testComponentEmitsEventWithIncorrectDataFails(): void { $testComponent = $this->createLiveComponent('component_with_emit'); $testComponent->call('actionThatEmits'); $this->expectException(AssertionFailedError::class); - $this->expectExceptionMessage('The expected event "event1" data "foo" expected "bar2" but "bar" given'); - $this->assertComponentEmitEvent($testComponent, 'event1', [ - 'foo' => 'bar2', + $this->expectExceptionMessage('The expected event "event1" data does not match.'); + $this->assertComponentEmitEvent($testComponent, 'event1')->withData([ + 'foo' => 'bar', + 'foo2' => 'bar2', ]); } } From ffbac6b6a7cc0d8b9b25b8c8c285c0c3050954ee Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:19:48 +0200 Subject: [PATCH 13/15] Edit documentation --- src/LiveComponent/src/Test/InteractsWithLiveComponents.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index ac87513c4ab..0e1c71af48b 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -55,7 +55,9 @@ protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent /** * @param array $data */ - public function __construct(private KernelTestCase $parent, private readonly string $eventName, private readonly array $data) {} + public function __construct(private KernelTestCase $parent, private readonly string $eventName, private readonly array $data) + { + } public function withDataSubset(array $expectedEventData): void { @@ -74,9 +76,10 @@ public function withDataSubset(array $expectedEventData): void ); } } + public function withData(array $expectedEventData): void { - $this->parent->assertEquals($expectedEventData, $this->data, sprintf('The expected event "%s" data does not match.', $this->eventName)); + $this->parent->assertEquals($expectedEventData, $this->data, \sprintf('The expected event "%s" data does not match.', $this->eventName)); } }; } From 608c24dcca45add7a2339b78d239fdd663f245ea Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:36:29 +0200 Subject: [PATCH 14/15] Fix documentation --- src/LiveComponent/doc/index.rst | 7 ++++--- .../src/Test/InteractsWithLiveComponents.php | 17 +++++++++++++++-- .../Test/InteractsWithLiveComponentsTest.php | 7 ++++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/LiveComponent/doc/index.rst b/src/LiveComponent/doc/index.rst index f19ebb4ac05..14753abde14 100644 --- a/src/LiveComponent/doc/index.rst +++ b/src/LiveComponent/doc/index.rst @@ -3782,9 +3782,10 @@ uses Symfony's test client to render and make requests to your components:: ; // Assert that the event was emitted - $this->componentHasEmittedEvent($render, 'increaseEvent', [ - 'amount' => 2, - ]); + $this->componentHasEmittedEvent($testComponent->render(), 'increaseEvent') + ->withData(['amount' => 2]) + ->withDataSubset(['amount' => 2]) // test partial parameters + ; // set live props $testComponent diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index 0e1c71af48b..c5be27dfdfa 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -45,6 +45,9 @@ protected function createLiveComponent(string $name, array $data = [], ?KernelBr ); } + /** + * @return object{withData: callable(array): object, withDataSubset: callable(array): object} + */ protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $expectedEventName): object { $event = $testLiveComponent->getEmittedEvent($testLiveComponent->render(), $expectedEventName); @@ -59,7 +62,10 @@ public function __construct(private KernelTestCase $parent, private readonly str { } - public function withDataSubset(array $expectedEventData): void + /** + * @return self + */ + public function withDataSubset(array $expectedEventData): object { foreach ($expectedEventData as $key => $value) { $this->parent->assertArrayHasKey($key, $this->data, \sprintf('The expected event "%s" data "%s" does not exists', $this->eventName, $key)); @@ -75,11 +81,18 @@ public function withDataSubset(array $expectedEventData): void ) ); } + + return $this; } - public function withData(array $expectedEventData): void + /** + * @return self + */ + public function withData(array $expectedEventData): object { $this->parent->assertEquals($expectedEventData, $this->data, \sprintf('The expected event "%s" data does not match.', $this->eventName)); + + return $this; } }; } diff --git a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php index b01eb1af335..91a6b6f0909 100644 --- a/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php +++ b/src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php @@ -250,9 +250,10 @@ public function testComponentEmitsExpectedPartialEventData(): void $testComponent->call('actionThatEmits'); - $this->assertComponentEmitEvent($testComponent, 'event1')->withDataSubset([ - 'foo' => 'bar', - ]); + $this->assertComponentEmitEvent($testComponent, 'event1') + ->withDataSubset(['foo' => 'bar']) + ->withDataSubset(['bar' => 'foo']) + ; } public function testComponentDoesNotEmitUnexpectedEvent(): void From a014fecd8184298c1c6d9997ae197d839d2303e2 Mon Sep 17 00:00:00 2001 From: Arkalo2 <24898676+Arkalo2@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:46:52 +0200 Subject: [PATCH 15/15] withData is void --- .../src/Test/InteractsWithLiveComponents.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php index c5be27dfdfa..2462f81694c 100644 --- a/src/LiveComponent/src/Test/InteractsWithLiveComponents.php +++ b/src/LiveComponent/src/Test/InteractsWithLiveComponents.php @@ -46,7 +46,7 @@ protected function createLiveComponent(string $name, array $data = [], ?KernelBr } /** - * @return object{withData: callable(array): object, withDataSubset: callable(array): object} + * @return object{withData: callable(array): void, withDataSubset: callable(array): object} */ protected function assertComponentEmitEvent(TestLiveComponent $testLiveComponent, string $expectedEventName): object { @@ -85,14 +85,9 @@ public function withDataSubset(array $expectedEventData): object return $this; } - /** - * @return self - */ - public function withData(array $expectedEventData): object + public function withData(array $expectedEventData): void { $this->parent->assertEquals($expectedEventData, $this->data, \sprintf('The expected event "%s" data does not match.', $this->eventName)); - - return $this; } }; }