Repository: symfony/ux
Pull request #1967 (2024-07-07 07:02:45)

[LazyImage] Webperfs and LCP considerations
| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Issues        | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT

<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - For new features, provide some code snippets to help understand usage.
 - Features and deprecations must be submitted against branch main.
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
 - Never break backward compatibility (see https://symfony.com/bc).
-->

Added some documentation to the LazyImage component, about LCP and webperfs considerations.

tl;dr: using the LazyImage _in its initial way_ on the LCP image, will decrease your LCP, lower the user experience, and lower the ranking of your website on Google.

Using the `style="background-image: url(...)"` trick solves this issue, since it allows the browser to download and render the HD image the fastest as possible, while showing the blurhash during the loading.

This is something I've implemented ~1 month ago on our website wamiz.com, and did some comparaison:
- Before, with the LazyImage Stimulus Controller solution, the blured image is not shown at all, and the LCP image discovered too much late: ![image](https://github.com/symfony/ux/assets/2103975/f61ae408-1e70-47ba-9b00-93fa5c85b56b)
- After, with the `style="background-image: url(...)"` trick, we can see the blured image and the LCP image discovered faster: ![image](https://github.com/symfony/ux/assets/2103975/d8402267-c67b-44a8-ae0f-8eaf2eaeb35c)


seb-jean: Good idea!
Will it also change with the `srcset` attribute? Is it a good idea to use the `srcset` attribute?
Kocal: The attribute `srcset` won't be changed. With the new code added in the documentation, there is no `<img>` attribute manipulation during execution, the browser simply _reads and executes_ `src` and `style` attributes.

But if you want to use `srcset` attributes, with preloading, I believe you can use something like this:

```twig
<img
    src="{{ preload(asset('image/large.png'), {
        as: 'image', 
        fetchpriority: 'high',
        imagesrcset: asset('image/large.png') ~ ' 1x, ' ~ asset('image/large2x.png') ~ ' 2x',
        imagesizes: '100vw'
    }) }}"
    srcset="{{ asset('image/large.png') }} 1x, {{ asset('image/large2x.png') }} 2x"
    sizes="100vw"

    style="background-image: url('{{ data_uri_thumbnail('public/image/large.png', 20, 15) }}')"
    fetchpriority="high"

    {# Using BlurHash, the size is required #}
    width="200"
    height="150"
/>
```

> Is it a good idea to use the `srcset` attribute?

In the context of LazyImage and Blurhash image generation, nope, you can generate the Blurhash image with very very low dimensions:
- here I've used 20x15 pixels for an original image of 200x150 pixels
- on our app, I've used 10x5 pixels for original images of ~665x370 pixels, and it's really fine!

But more generally, yes, you don't want to load a 1200px wide image on a smartphone (~400/500px). You will prefer to load an image adapted to the device in order to reduce bandwidth consumption and increase download/display speed (especially true on mobiles with _slow_ connections).

You can achieve that by using `srcset` attributes, or in a more naughty way, render an `<img src="...">` depending on the user's device, [and put your page in cache (by device type)](https://developers.cloudflare.com/automatic-platform-optimization/reference/cache-device-type/).
smnandre: ⚠️  very opiniated... opinion.

The follow message only concerns _today_ and the future (a lot have changed since this package release).

---

I personally think this package/method in general should not be recommanded today.

First thing: the browsers are doing a much better job that any JS script will allow, so i'd recommand to use their optimisations. 

`loading=lazy` with size/height attributes  is de facto the most recommanded method to load images today.. and offer the best results in term of performances, accessibility, HTML weight, SEO.. 

If you have to wait more than 100ms for an image to load, you probably have other problems (an image over-sized, not in the best format, not compressed ...). First use srcset / picture sources attributes and you'll have done 99% of the job.

And if you absolutely (why?) need to display _something_ in this tiny moment before the image is loaded, you can set some background svg, a gradient, a color..

To be complete, even the blurhash feels generally to me overkill (bringing itself some avoidable JS execution)

--- 

I'm very open to debate all this and ear your opinions :) 



seb-jean: So for you, the following code is not recommended?

```twig
<img
    src="{{ asset('image/small.png') }}"
    srcset="{{ asset('image/small.png') }} 1x, {{ asset('image/small2x.png') }} 2x"

    {{ stimulus_controller('symfony/ux-lazy-image/lazy-image', {
        src: asset('image/large.png'),
        srcset: {
            '1x': asset('image/large.png'),
            '2x': asset('image/large2x.png')
        }
    }) }}
/>
```
smnandre: I _**personnaly**_ won't recommand it, _today_.

Main reason: why use a stimulus controller instead of loading lazy ?

Using native HTML provides better results in term of performance, accessibility, SEO... 

javiereguiluz: I agree with @smnandre. I think that the LazyImage UX package should be deprecated in favor of using the native HTML/browser features to lazy-load images.
Kocal: Hi everyone, I think everyone here is right here, but alse I think we don't speak about the same thing 😅

I didn't speak about image lazy-loading, which **yes**, should be done natively by the browser, without any JavaScript layer.

I'm speaking about the LCP image which **should not be lazy-loaded**, it should be loaded and displayed as soon as possible. 
In this PR, I explain how we can hijack the initial Symfony UX BlurHash usage, to create a small placeholder image that is displayed when the real image is loaded, without any webperf costs.
The goal here is, thanks to this small placeholder image inlined in the HTML, to give the user a visual result instead of nothing. 

Patch:
diff --git a/src/Dropzone/assets/dist/controller.d.ts b/src/Dropzone/assets/dist/controller.d.ts
index 5c834d44..ace00ae3 100644
--- a/src/Dropzone/assets/dist/controller.d.ts
+++ b/src/Dropzone/assets/dist/controller.d.ts
@@ -7,9 +7,7 @@ export default class extends Controller {
     readonly previewFilenameTarget: HTMLDivElement;
     readonly previewImageTarget: HTMLDivElement;
     static targets: string[];
-    initialize(): void;
     connect(): void;
-    disconnect(): void;
     clear(): void;
     onInputChange(event: any): void;
     _populateImagePreview(file: Blob): void;
diff --git a/src/Dropzone/assets/dist/controller.js b/src/Dropzone/assets/dist/controller.js
index c11635c5..d92d8c90 100644
--- a/src/Dropzone/assets/dist/controller.js
+++ b/src/Dropzone/assets/dist/controller.js
@@ -1,20 +1,12 @@
 import { Controller } from '@hotwired/stimulus';
 
 class default_1 extends Controller {
-    initialize() {
-        this.clear = this.clear.bind(this);
-        this.onInputChange = this.onInputChange.bind(this);
-    }
     connect() {
         this.clear();
-        this.previewClearButtonTarget.addEventListener('click', this.clear);
-        this.inputTarget.addEventListener('change', this.onInputChange);
+        this.previewClearButtonTarget.addEventListener('click', () => this.clear());
+        this.inputTarget.addEventListener('change', (event) => this.onInputChange(event));
         this.dispatchEvent('connect');
     }
-    disconnect() {
-        this.previewClearButtonTarget.removeEventListener('click', this.clear);
-        this.inputTarget.removeEventListener('change', this.onInputChange);
-    }
     clear() {
         this.inputTarget.value = '';
         this.inputTarget.style.display = 'block';
diff --git a/src/Dropzone/assets/src/controller.ts b/src/Dropzone/assets/src/controller.ts
index a113aa86..f27702f3 100644
--- a/src/Dropzone/assets/src/controller.ts
+++ b/src/Dropzone/assets/src/controller.ts
@@ -21,29 +21,19 @@ export default class extends Controller {
 
     static targets = ['input', 'placeholder', 'preview', 'previewClearButton', 'previewFilename', 'previewImage'];
 
-    initialize() {
-        this.clear = this.clear.bind(this);
-        this.onInputChange = this.onInputChange.bind(this);
-    }
-
     connect() {
         // Reset when connecting to work with Turbolinks
         this.clear();
 
         // Clear on click on clear button
-        this.previewClearButtonTarget.addEventListener('click', this.clear);
+        this.previewClearButtonTarget.addEventListener('click', () => this.clear());
 
         // Listen on input change and display preview
-        this.inputTarget.addEventListener('change', this.onInputChange);
+        this.inputTarget.addEventListener('change', (event) => this.onInputChange(event));
 
         this.dispatchEvent('connect');
     }
 
-    disconnect() {
-        this.previewClearButtonTarget.removeEventListener('click', this.clear);
-        this.inputTarget.removeEventListener('change', this.onInputChange);
-    }
-
     clear() {
         this.inputTarget.value = '';
         this.inputTarget.style.display = 'block';
diff --git a/src/Icons/config/services.php b/src/Icons/config/services.php
index 02a8ed7e..218ec30d 100644
--- a/src/Icons/config/services.php
+++ b/src/Icons/config/services.php
@@ -50,8 +50,6 @@ return static function (ContainerConfigurator $container): void {
             ])
             ->tag('twig.runtime')
 
-        ->alias('Symfony\UX\Icons\IconRendererInterface', '.ux_icons.icon_renderer')
-
         ->set('.ux_icons.icon_finder', IconFinder::class)
             ->args([
                 service('twig'),
diff --git a/src/Icons/doc/index.rst b/src/Icons/doc/index.rst
index f1ee241e..8b07ee60 100644
--- a/src/Icons/doc/index.rst
+++ b/src/Icons/doc/index.rst
@@ -180,7 +180,7 @@ tag:
     <!-- you can also add any HTML attributes -->
     <twig:ux:icon name="user-profile" height="16" width="16" aria-hidden="true" />
 
-.. tip::
+.. note::
 
     To use the HTML syntax, the ``symfony/ux-twig-component`` package must be
     installed in your project.
diff --git a/src/Icons/src/IconRenderer.php b/src/Icons/src/IconRenderer.php
index 95edf56d..c65613b3 100644
--- a/src/Icons/src/IconRenderer.php
+++ b/src/Icons/src/IconRenderer.php
@@ -16,7 +16,7 @@ namespace Symfony\UX\Icons;
  *
  * @internal
  */
-final class IconRenderer implements IconRendererInterface
+final class IconRenderer
 {
     public function __construct(
         private readonly IconRegistryInterface $registry,
@@ -32,6 +32,8 @@ final class IconRenderer implements IconRendererInterface
      *
      * Precedence order:
      *   Icon file < Renderer configuration < Renderer invocation
+     *
+     * @param array<string,string|bool> $attributes
      */
     public function renderIcon(string $name, array $attributes = []): string
     {
diff --git a/src/Icons/src/IconRendererInterface.php b/src/Icons/src/IconRendererInterface.php
deleted file mode 100644
index 8465e7b8..00000000
--- a/src/Icons/src/IconRendererInterface.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\UX\Icons;
-
-use Symfony\UX\Icons\Exception\IconNotFoundException;
-
-/**
- * @author Simon André <smn.andre@gmail.com>
- * @author Kevin Bond <kevinbond@gmail.com>
- */
-interface IconRendererInterface
-{
-    /**
-     * Renders an icon by its name and returns the SVG string.
-     *
-     * @param string                     $name       the icon name, optionally prefixed with the icon set
-     * @param array<string, string|bool> $attributes an array of HTML attributes
-     *
-     * @throws IconNotFoundException
-     *
-     * @example
-     *  $iconRenderer->renderIcon('arrow-right');
-     *  // Renders the "arrow-right" icon from the default icons directory.
-     *
-     *  $iconRenderer->renderIcon('lucide:heart', ['class' => 'color-red']);
-     *  // Renders the "heart" icon from the "lucide" icon set, with the "color-red" class.
-     */
-    public function renderIcon(string $name, array $attributes = []): string;
-}
diff --git a/src/Icons/src/Twig/UXIconComponentListener.php b/src/Icons/src/Twig/UXIconComponentListener.php
index 8ccf4df1..87a01b8d 100644
--- a/src/Icons/src/Twig/UXIconComponentListener.php
+++ b/src/Icons/src/Twig/UXIconComponentListener.php
@@ -11,7 +11,7 @@
 
 namespace Symfony\UX\Icons\Twig;
 
-use Symfony\UX\Icons\IconRendererInterface;
+use Symfony\UX\Icons\IconRenderer;
 use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent;
 
 /**
@@ -22,7 +22,7 @@ use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent;
 final class UXIconComponentListener
 {
     public function __construct(
-        private IconRendererInterface $iconRenderer,
+        private IconRenderer $iconRenderer,
     ) {
     }
 
diff --git a/src/LazyImage/doc/index.rst b/src/LazyImage/doc/index.rst
index fcda5935..cea3f0e4 100644
--- a/src/LazyImage/doc/index.rst
+++ b/src/LazyImage/doc/index.rst
@@ -205,6 +205,41 @@ Then in your template, add your controller to the HTML attribute:
     controller so that it is executed before and can listen on the
     ``lazy-image:connect`` event properly.
 
+Largest Contentful Paint (LCP) and Web performance considerations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The `Largest Contentful Paint (LCP)`_ is a key metric for web performance, it measures the time
+it takes for the largest image or text block to be rendered on the page, and should be less 
+than 2.5 seconds.
+It's part of the `Core Web Vitals`_ and is used by Google to evaluate the user experience 
+of a website, and impacts the Search ranking.
+
+Using the Symfony UX LazyImage for your LCP image can be a good idea at first, 
+but in the reality it will lower your LCP score because:
+- `The progressive loading (through blurhash) is not taken into account in the LCP calculation`_
+- event if you eagerly load the LazyImage Stimulus controller, a small delay will be added to the 
+  LCP calculation
+- if you `didn't preload the image`_, the browser will waits for the Stimulus controller to 
+  load the image, which add another delay to the LCP calculation
+
+A solution is to not use the Stimulus controller for the LCP image, but use ``src`` and ``style`` 
+attributes instead, and preload the image as well: 
+
+.. code-block:: html+twig
+
+    <img
+        src="{{ preload(asset('image/large.png'), { as: 'image', fetchpriority: 'high' }) }}"
+        style="background-image: url('{{ data_uri_thumbnail('public/image/large.png', 20, 15) }}')"
+        fetchpriority="high"
+
+        {# Using BlurHash, the size is required #}
+        width="200"
+        height="150"
+    />
+    
+This way, the browser will display the BlurHash image as soon as possible, and will load the HD 
+image at the same time, without waiting for the Stimulus controller to be loaded.
+
 Backward Compatibility promise
 ------------------------------
 
@@ -217,4 +252,8 @@ https://symfony.com/doc/current/contributing/code/bc.html
 .. _`StimulusBundle`: https://symfony.com/bundles/StimulusBundle/current/index.html
 .. _StimulusBundle configured in your app: https://symfony.com/bundles/StimulusBundle/current/index.html
 .. _`file_get_contents`: https://www.php.net/manual/en/function.file-get-contents.php
-.. _`Flysystem`: https://flysystem.thephpleague.com
\ No newline at end of file
+.. _`Flysystem`: https://flysystem.thephpleague.com
+.. _`Largest Contentful Paint (LCP)`: https://web.dev/lcp/
+.. _`Core Web Vitals`: https://web.dev/vitals/
+.. _`The progressive loading (through blurhash) is not taken into account in the LCP calculation`: https://github.com/w3c/largest-contentful-paint/issues/71_
+.. _`didn't preload the image`: https://symfony.com/doc/current/web_link.html
diff --git a/src/LiveComponent/src/EventListener/DeferLiveComponentSubscriber.php b/src/LiveComponent/src/EventListener/DeferLiveComponentSubscriber.php
index e7348b18..6de25904 100644
--- a/src/LiveComponent/src/EventListener/DeferLiveComponentSubscriber.php
+++ b/src/LiveComponent/src/EventListener/DeferLiveComponentSubscriber.php
@@ -29,10 +29,6 @@ final class DeferLiveComponentSubscriber implements EventSubscriberInterface
     public function onPostMount(PostMountEvent $event): void
     {
         $data = $event->getData();
-        if (!$event->getMetadata()->get('live', false)) {
-            // Not a live component
-            return;
-        }
 
         if (\array_key_exists('defer', $data)) {
             trigger_deprecation('symfony/ux-live-component', '2.17', 'The "defer" attribute is deprecated and will be removed in 3.0. Use the "loading" attribute instead set to the value "defer".');
diff --git a/src/LiveComponent/src/LiveComponentHydrator.php b/src/LiveComponent/src/LiveComponentHydrator.php
index 547106fa..c5ec39b9 100644
--- a/src/LiveComponent/src/LiveComponentHydrator.php
+++ b/src/LiveComponent/src/LiveComponentHydrator.php
@@ -370,7 +370,6 @@ final class LiveComponentHydrator
         foreach ($parts as $part) {
             if (\is_array($currentValue)) {
                 $finalPropertyPath .= \sprintf('[%s]', $part);
-                $currentValue = $this->propertyAccessor->getValue($rawPropertyValue, $finalPropertyPath);
 
                 continue;
             }
@@ -380,10 +379,6 @@ final class LiveComponentHydrator
             }
 
             $finalPropertyPath .= $part;
-
-            if (null !== $currentValue) {
-                $currentValue = $this->propertyAccessor->getValue($rawPropertyValue, $finalPropertyPath);
-            }
         }
 
         return $finalPropertyPath;
@@ -457,7 +452,7 @@ final class LiveComponentHydrator
                 $collectionClass = $propMetadata->collectionValueType()->getClassName();
                 foreach ($value as $key => $objectItem) {
                     if (!$objectItem instanceof $collectionClass) {
-                        throw new \LogicException(\sprintf('The LiveProp "%s" on component "%s" is an array. We determined the array is full of %s objects, but at least one key had a different value of %s', $propMetadata->getName(), $parentObject::class, $collectionClass, get_debug_type($objectItem)));
+                        throw new \LogicException(\sprintf('The LiveProp "%s" on component "%s" is an array. We determined the array is full of %s objects, but at least on key had a different value of %s', $propMetadata->getName(), $parentObject::class, $collectionClass, get_debug_type($objectItem)));
                     }
 
                     $value[$key] = $this->dehydrateObjectValue($objectItem, $collectionClass, $propMetadata->getFormat(), $parentObject);
diff --git a/src/React/doc/index.rst b/src/React/doc/index.rst
index e894f6a4..42b97640 100644
--- a/src/React/doc/index.rst
+++ b/src/React/doc/index.rst
@@ -82,7 +82,7 @@ For example:
     {% extends 'base.html.twig' %}
 
     {% block body %}
-        <div {{ react_component('Hello', { fullName: 'Fabien' }) }}>
+        <div {{ react_component('Hello', { 'fullName': number }) }}>
             Loading... <i class="fas fa-cog fa-spin fa-3x"></i>
         </div>
 
diff --git a/src/Translator/CHANGELOG.md b/src/Translator/CHANGELOG.md
index b8d13254..62f7ae26 100644
--- a/src/Translator/CHANGELOG.md
+++ b/src/Translator/CHANGELOG.md
@@ -1,9 +1,5 @@
 # CHANGELOG
 
-## 2.19.0
-
--   Add configuration to filter dumped translations by domain.
-
 ## 2.16.0
 
 -   Increase version range of `intl-messageformat` to `^10.5.11`, in order to see
diff --git a/src/Translator/doc/index.rst b/src/Translator/doc/index.rst
index 0b36da69..4872d569 100644
--- a/src/Translator/doc/index.rst
+++ b/src/Translator/doc/index.rst
@@ -65,34 +65,12 @@ After installing the bundle, the following file should be created, thanks to the
 Usage
 -----
 
-When warming up the Symfony cache, your translations will be dumped as JavaScript into the ``var/translations/`` directory.
+When warming up the Symfony cache, all of your translations will be dumped as JavaScript into the ``var/translations/`` directory.
 For a better developer experience, TypeScript types definitions are also generated aside those JavaScript files.
 
 Then, you will be able to import those JavaScript translations in your assets.
 Don't worry about your final bundle size, only the translations you use will be included in your final bundle, thanks to the `tree shaking <https://webpack.js.org/guides/tree-shaking/>`_.
 
-.. note::
-
-    This package requires the `translator` to be enabled in your Symfony application. If you don't use the `translator` service, the warmup command will not generate any translations.
-
-Configuring the dumped translations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-By default, all your translations will be exported. You can restrict the dumped messages by either
-including or excluding translation domains in your ``config/packages/ux_translator.yaml`` file:
-
-.. code-block:: yaml
-
-    ux_translator:
-            domains: ~    # Include all the domains
-
-            domains: foo  # Include only domain 'foo'
-            domains: '!foo' # Include all domains, except 'foo'
-
-            domains: [foo, bar]   # Include only domains 'foo' and 'bar'
-            domains: ['!foo', '!bar'] # Include all domains, except 'foo' and 'bar'
-
-
 Configuring the default locale
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/src/Translator/src/DependencyInjection/Configuration.php b/src/Translator/src/DependencyInjection/Configuration.php
index 5f2e31a3..485c1bdc 100644
--- a/src/Translator/src/DependencyInjection/Configuration.php
+++ b/src/Translator/src/DependencyInjection/Configuration.php
@@ -13,7 +13,6 @@ namespace Symfony\UX\Translator\DependencyInjection;
 
 use Symfony\Component\Config\Definition\Builder\TreeBuilder;
 use Symfony\Component\Config\Definition\ConfigurationInterface;
-use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
 
 /**
  * @author Hugo Alliaume <hugo@alliau.me>
@@ -29,59 +28,6 @@ class Configuration implements ConfigurationInterface
         $rootNode
             ->children()
                 ->scalarNode('dump_directory')->defaultValue('%kernel.project_dir%/var/translations')->end()
-                ->arrayNode('domains')
-                    ->info('List of domains to include/exclude from the generated translations. Prefix with a `!` to exclude a domain.')
-                    ->children()
-                        ->scalarNode('type')
-                            ->validate()
-                                ->ifNotInArray(['inclusive', 'exclusive'])
-                                ->thenInvalid('The type of domains has to be inclusive or exclusive')
-                            ->end()
-                        ->end()
-                        ->arrayNode('elements')
-                            ->scalarPrototype()->end()
-                        ->end()
-                    ->end()
-                    ->canBeUnset()
-                    ->beforeNormalization()
-                        ->ifString()
-                        ->then(fn ($v) => ['elements' => [$v]])
-                    ->end()
-                    ->beforeNormalization()
-                        ->ifTrue(function ($v) { return \is_array($v) && is_numeric(key($v)); })
-                        ->then(function ($v) { return ['elements' => $v]; })
-                    ->end()
-                    ->validate()
-                        ->always(function ($v) {
-                            $isExclusive = null;
-                            $elements = [];
-                            if (isset($v['type'])) {
-                                $isExclusive = 'exclusive' === $v['type'];
-                            }
-                            foreach ($v['elements'] as $domain) {
-                                if (str_starts_with($domain, '!')) {
-                                    if (false === $isExclusive) {
-                                        throw new InvalidConfigurationException('You cannot mix included and excluded domains.');
-                                    }
-                                    $isExclusive = true;
-                                    $elements[] = substr($domain, 1);
-                                } else {
-                                    if (true === $isExclusive) {
-                                        throw new InvalidConfigurationException('You cannot mix included and excluded domains.');
-                                    }
-                                    $isExclusive = false;
-                                    $elements[] = $domain;
-                                }
-                            }
-
-                            if (!\count($elements)) {
-                                return null;
-                            }
-
-                            return ['type' => $isExclusive ? 'exclusive' : 'inclusive', 'elements' => array_unique($elements)];
-                        })
-                    ->end()
-                ->end()
             ->end()
         ;
 
diff --git a/src/Translator/src/DependencyInjection/TranslatorCompilerPass.php b/src/Translator/src/DependencyInjection/TranslatorCompilerPass.php
deleted file mode 100644
index 9262c137..00000000
--- a/src/Translator/src/DependencyInjection/TranslatorCompilerPass.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace Symfony\UX\Translator\DependencyInjection;
-
-use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\Translation\TranslatorBagInterface;
-
-class TranslatorCompilerPass implements CompilerPassInterface
-{
-    public function process(ContainerBuilder $container): void
-    {
-        if (!$this->hasValidTranslator($container)) {
-            $container->removeDefinition('ux.translator.cache_warmer.translations_cache_warmer');
-        }
-    }
-
-    private function hasValidTranslator(ContainerBuilder $containerBuilder): bool
-    {
-        if (!$containerBuilder->hasDefinition('translator')) {
-            return false;
-        }
-
-        $translator = $containerBuilder->getDefinition('translator');
-        if (!is_subclass_of($translator->getClass(), TranslatorBagInterface::class)) {
-            return false;
-        }
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php
index 9ba3a029..65a15484 100644
--- a/src/Translator/src/DependencyInjection/UxTranslatorExtension.php
+++ b/src/Translator/src/DependencyInjection/UxTranslatorExtension.php
@@ -35,15 +35,7 @@ class UxTranslatorExtension extends Extension implements PrependExtensionInterfa
         $loader = (new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/../config')));
         $loader->load('services.php');
 
-        $dumperDefinition = $container->getDefinition('ux.translator.translations_dumper');
-        $dumperDefinition->setArgument(0, $config['dump_directory']);
-
-        if (isset($config['domains'])) {
-            $method = 'inclusive' === $config['domains']['type'] ? 'addIncludedDomain' : 'addExcludedDomain';
-            foreach ($config['domains']['elements'] as $domainName) {
-                $dumperDefinition->addMethodCall($method, [$domainName]);
-            }
-        }
+        $container->getDefinition('ux.translator.translations_dumper')->setArgument(0, $config['dump_directory']);
     }
 
     public function prepend(ContainerBuilder $container)
diff --git a/src/Translator/src/TranslationsDumper.php b/src/Translator/src/TranslationsDumper.php
index cba61117..751f4203 100644
--- a/src/Translator/src/TranslationsDumper.php
+++ b/src/Translator/src/TranslationsDumper.php
@@ -32,9 +32,6 @@ use function Symfony\Component\String\s;
  */
 class TranslationsDumper
 {
-    private array $excludedDomains = [];
-    private array $includedDomains = [];
-
     public function __construct(
         private string $dumpDir,
         private MessageParametersExtractor $messageParametersExtractor,
@@ -87,22 +84,6 @@ TS
         );
     }
 
-    public function addExcludedDomain(string $domain): void
-    {
-        if ($this->includedDomains) {
-            throw new \LogicException('You cannot set both "excluded_domains" and "included_domains" at the same time.');
-        }
-        $this->excludedDomains[] = $domain;
-    }
-
-    public function addIncludedDomain(string $domain): void
-    {
-        if ($this->excludedDomains) {
-            throw new \LogicException('You cannot set both "excluded_domains" and "included_domains" at the same time.');
-        }
-        $this->includedDomains[] = $domain;
-    }
-
     /**
      * @return array<MessageId, array<Domain, array<Locale, string>>>
      */
@@ -113,12 +94,6 @@ TS
         foreach ($catalogues as $catalogue) {
             $locale = $catalogue->getLocale();
             foreach ($catalogue->getDomains() as $domain) {
-                if (\in_array($domain, $this->excludedDomains, true)) {
-                    continue;
-                }
-                if ($this->includedDomains && !\in_array($domain, $this->includedDomains, true)) {
-                    continue;
-                }
                 foreach ($catalogue->all($domain) as $id => $message) {
                     $realDomain = $catalogue->has($id, $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)
                         ? $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX
diff --git a/src/Translator/src/UxTranslatorBundle.php b/src/Translator/src/UxTranslatorBundle.php
index ff6c7492..91fa829a 100644
--- a/src/Translator/src/UxTranslatorBundle.php
+++ b/src/Translator/src/UxTranslatorBundle.php
@@ -11,9 +11,7 @@
 
 namespace Symfony\UX\Translator;
 
-use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
-use Symfony\UX\Translator\DependencyInjection\TranslatorCompilerPass;
 
 /**
  * @author Hugo Alliaume <hugo@alliau.me>
@@ -28,9 +26,4 @@ class UxTranslatorBundle extends Bundle
     {
         return \dirname(__DIR__);
     }
-
-    public function build(ContainerBuilder $container): void
-    {
-        $container->addCompilerPass(new TranslatorCompilerPass());
-    }
 }
diff --git a/src/TwigComponent/doc/index.rst b/src/TwigComponent/doc/index.rst
index f58c1dbb..1c0bbde0 100644
--- a/src/TwigComponent/doc/index.rst
+++ b/src/TwigComponent/doc/index.rst
@@ -293,19 +293,7 @@ prefix the attribute with ``:`` or use the normal ``{{ }}`` syntax:
     <twig:Alert message="hello!" user="{{ user.id }}" />
 
     // pass object, array, or anything you imagine
-    <twig:Alert :foo="{col: ['foo', 'oof']}" />
-
-Boolean props require using the dynamic syntax:
-
-.. code-block:: html+twig
-
-    {# in this example, the 'false' value is passed as a string
-       (so it's converted automatically to the true boolean value) #}
-    <twig:Alert message="..." withCloseButton="false" />
-
-    {# in the following examples, the 'false' value is passed as a boolean property #}
-    <twig:Alert message="..." :withCloseButton="false" />
-    <twig:Alert message="..." withCloseButton="{{ false }}" />
+    <twig:Alert :foo="['col' => ['foo', 'oof']]" />
 
 Don't forget that you can mix and match props with attributes that you
 want to render on the root element:
@@ -495,20 +483,17 @@ component use a ``PreMount`` hook::
 
 .. note::
 
-    In its default configuration, the OptionsResolver treats all props.
-    However, if more props are passed than the options defined in the OptionsResolver,
-    an error will be prompted, indicating that one or more options do not exist.
-    To avoid this, use the ``ignoreUndefined()`` method with ``true``.
-    See `ignore not defined options`_ for more info::
+   In its default configuration, the OptionsResolver treats all props.
+   However, if more props are passed than the options defined in the OptionsResolver, an error will be prompted, indicating that one or more options do not exist.
+   To avoid this, use the `ignoreUndefined()` method with `true`. See `ignore not defined options`_ for more info.
    
-        $resolver->setIgnoreUndefined(true);
+      $resolver->setIgnoreUndefined(true);
    
-    The major drawback of this configuration is that the OptionsResolver will
-    remove every non-defined option when resolving data. To maintain props that
-    have not been defined within the OptionsResolver, combine the data from the
-    hook with the resolved data::
+   The major drawback of this configuration is that the OptionsResolver will remove every non-defined option when resolving data. 
+   To maintain props that have not been defined within the OptionsResolver, combine the data from the hook with the resolved data.
    
-        return $resolver->resolve($data) + $data;
+      return $resolver->resolve($data) + $data;
+
 
 The data returned from ``preMount()`` will be used as the props for mounting.
 
diff --git a/src/TwigComponent/src/Twig/PropsNode.php b/src/TwigComponent/src/Twig/PropsNode.php
index 97f98d51..70b35d64 100644
--- a/src/TwigComponent/src/Twig/PropsNode.php
+++ b/src/TwigComponent/src/Twig/PropsNode.php
@@ -35,10 +35,6 @@ class PropsNode extends Node
             ->write('$propsNames = [];')
         ;
 
-        if (!$this->getAttribute('names')) {
-            return;
-        }
-
         foreach ($this->getAttribute('names') as $name) {
             $compiler
                 ->write('if (isset($context[\'__props\'][\''.$name.'\'])) {')
@@ -77,23 +73,7 @@ class PropsNode extends Node
                 ->raw(";\n")
                 ->outdent()
                 ->write('}')
-                ->write("\n")
-            ;
-
-            // overwrite the context value if a props with a similar name and a default value exist
-            if ($this->hasNode($name)) {
-                $compiler
-                    ->write('if (isset($context[\'__context\'][\''.$name.'\'])) {')
-                    ->raw("\n")
-                    ->indent()
-                    ->write('$context[\''.$name.'\'] = ')
-                    ->subcompile($this->getNode($name))
-                    ->raw(";\n")
-                    ->outdent()
-                    ->write('}')
-                    ->raw("\n")
-                ;
-            }
+                ->write("\n");
         }
 
         $compiler
@@ -114,5 +94,20 @@ class PropsNode extends Node
             ->write('}')
             ->raw("\n")
         ;
+
+        // overwrite the context value if a props with a similar name and a default value exist
+        if ($this->hasNode($name)) {
+            $compiler
+                ->write('if (isset($context[\'__context\'][\''.$name.'\'])) {')
+                ->raw("\n")
+                ->indent()
+                ->write('$context[\''.$name.'\'] = ')
+                ->subcompile($this->getNode($name))
+                ->raw(";\n")
+                ->outdent()
+                ->write('}')
+                ->raw("\n")
+            ;
+        }
     }
 }
diff --git a/ux.symfony.com/.php-cs-fixer.dist.php b/ux.symfony.com/.php-cs-fixer.dist.php
index 840416ce..c5a5e790 100644
--- a/ux.symfony.com/.php-cs-fixer.dist.php
+++ b/ux.symfony.com/.php-cs-fixer.dist.php
@@ -23,8 +23,6 @@ file that was distributed with this source code.
 EOF;
 
 return (new PhpCsFixer\Config())
-    // @see https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/7777
-    ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
     ->setRules([
         '@PHPUnit75Migration:risky' => true,
         '@Symfony' => true,


Test patch:
diff --git a/src/Icons/tests/Integration/IconRendererTest.php b/src/Icons/tests/Integration/IconRendererTest.php
deleted file mode 100644
index 9a6d8c5f..00000000
--- a/src/Icons/tests/Integration/IconRendererTest.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\UX\Icons\Tests\Integration;
-
-use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
-use Symfony\UX\Icons\IconRenderer;
-use Symfony\UX\Icons\IconRendererInterface;
-
-/**
- * @author Simon André <smn.andre@gmail.com>
- */
-final class IconRendererTest extends KernelTestCase
-{
-    public function testIconRenderService(): void
-    {
-        $this->assertTrue(self::getContainer()->has(IconRendererInterface::class));
-    }
-
-    public function testIconRendererAlias(): void
-    {
-        $renderer = self::getContainer()->get(IconRendererInterface::class);
-        $this->assertInstanceOf(IconRenderer::class, $renderer);
-    }
-
-    public function testIconRendererIsPrivate(): void
-    {
-        $this->assertFalse(self::getContainer()->has(IconRenderer::class));
-    }
-}
diff --git a/src/LiveComponent/tests/Fixtures/Component/SimpleTwigComponent.php b/src/LiveComponent/tests/Fixtures/Component/SimpleTwigComponent.php
deleted file mode 100644
index 72766b2f..00000000
--- a/src/LiveComponent/tests/Fixtures/Component/SimpleTwigComponent.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-namespace Symfony\UX\LiveComponent\Tests\Fixtures\Component;
-
-use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
-
-/**
- * @author Simon André <smn.andre@gmail.com>
- */
-#[AsTwigComponent('simple_twig')]
-final class SimpleTwigComponent
-{
-    public string $foo = 'foo';
-
-    public string $bar = 'bar';
-
-    public function getFooBar(): string
-    {
-        return $this->foo.$this->bar;
-    }
-}
diff --git a/src/LiveComponent/tests/Fixtures/Dto/HoldsArrayOfDtos.php b/src/LiveComponent/tests/Fixtures/Dto/HoldsArrayOfDtos.php
deleted file mode 100644
index 13eaec51..00000000
--- a/src/LiveComponent/tests/Fixtures/Dto/HoldsArrayOfDtos.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Symfony\UX\LiveComponent\Tests\Fixtures\Dto;
-
-final class HoldsArrayOfDtos
-{
-    /**
-     * @var Address[] $addresses
-     */
-    public array $addresses;
-}
diff --git a/src/LiveComponent/tests/Fixtures/templates/components/simple_twig.html.twig b/src/LiveComponent/tests/Fixtures/templates/components/simple_twig.html.twig
deleted file mode 100644
index b2ce5f84..00000000
--- a/src/LiveComponent/tests/Fixtures/templates/components/simple_twig.html.twig
+++ /dev/null
@@ -1,1 +0,0 @@
-<div{{ attributes }}>{{ this.getFooBar() }}</div>
diff --git a/src/LiveComponent/tests/Fixtures/templates/render_lazy_twig_component.html.twig b/src/LiveComponent/tests/Fixtures/templates/render_lazy_twig_component.html.twig
deleted file mode 100644
index bf74fa5e..00000000
--- a/src/LiveComponent/tests/Fixtures/templates/render_lazy_twig_component.html.twig
+++ /dev/null
@@ -1,1 +0,0 @@
-<twig:simple_twig foo="Foo" bar="Bar" loading="lazy" />
diff --git a/src/LiveComponent/tests/Functional/EventListener/DeferLiveComponentSubscriberTest.php b/src/LiveComponent/tests/Functional/EventListener/DeferLiveComponentSubscriberTest.php
index 6a8c083a..c0bffd82 100644
--- a/src/LiveComponent/tests/Functional/EventListener/DeferLiveComponentSubscriberTest.php
+++ b/src/LiveComponent/tests/Functional/EventListener/DeferLiveComponentSubscriberTest.php
@@ -170,17 +170,4 @@ final class DeferLiveComponentSubscriberTest extends KernelTestCase
         $browser->assertElementCount('#count', 1);
         $browser->assertElementAttributeContains('#count', 'value', '7');
     }
-
-    public function testSubscriberDoesNotHandleTwigComponent(): void
-    {
-        $browser = $this->browser()
-            ->visit('/render-template/render_lazy_twig_component')
-            ->assertSuccessful();
-
-        $browser->assertElementCount('[loading="lazy"]', 1);
-        $browser->assertElementCount('[data-controller]', 0);
-
-        $componentDiv = $browser->crawler()->filter('div');
-        $this->assertSame('<div loading="lazy">FooBar</div>', trim($componentDiv->outerHtml()));
-    }
 }
diff --git a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php
index 2441146f..fd01de4c 100644
--- a/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php
+++ b/src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php
@@ -23,7 +23,6 @@ use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\Address;
 use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\BlogPostWithSerializationContext;
 use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\CustomerDetails;
 use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\Embeddable2;
-use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\HoldsArrayOfDtos;
 use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\Money;
 use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\ParentDTO;
 use Symfony\UX\LiveComponent\Tests\Fixtures\Dto\SimpleDto;
@@ -969,127 +968,6 @@ final class LiveComponentHydratorTest extends KernelTestCase
                 });
         }];
 
-        yield 'Array with DTOs: fully writable allows anything to change' => [function () {
-            $address1 = create(Address::class, ['address' => '17 Arcadia Road', 'city' => 'London'])->object();
-            $address2 = create(Address::class, ['address' => '4 Privet Drive', 'city' => 'Little Whinging'])->object();
-            $address3 = create(Address::class, ['address' => '124 Conch St.', 'city' => 'Bikini Bottom'])->object();
-            $address4 = create(Address::class, ['address' => '32 Windsor Gardens', 'city' => 'London'])->object();
-
-            return HydrationTest::create(new class() {
-                /**
-                 * @var Symfony\UX\LiveComponent\Tests\Fixtures\Dto\Address[]
-                 */
-                #[LiveProp(writable: true, useSerializerForHydration: true)]
-                public array $addresses = [];
-            })
-                ->mountWith(['addresses' => [$address1, $address2]])
-                ->assertDehydratesTo(['addresses' => [
-                    [
-                        'address' => '17 Arcadia Road',
-                        'city' => 'London',
-                    ],
-                    [
-                        'address' => '4 Privet Drive',
-                        'city' => 'Little Whinging',
-                    ],
-                ]])
-                ->userUpdatesProps(['addresses' => [$address3, $address4]])
-                ->assertObjectAfterHydration(function (object $object) {
-                    self::assertEquals([
-                        create(Address::class, ['address' => '124 Conch St.', 'city' => 'Bikini Bottom'])->object(),
-                        create(Address::class, ['address' => '32 Windsor Gardens', 'city' => 'London'])->object(),
-                    ], $object->addresses);
-                });
-        }];
-
-        yield 'Array with DTOs: fully writable allows partial changes' => [function () {
-            $address1 = create(Address::class, ['address' => '1600 Pennsylvania Avenue', 'city' => 'Washington DC'])->object();
-            $address2 = create(Address::class, ['address' => '221 B Baker St', 'city' => 'Birmingham'])->object();
-
-            return HydrationTest::create(new class() {
-                /**
-                 * @var Symfony\UX\LiveComponent\Tests\Fixtures\Dto\Address[]
-                 */
-                #[LiveProp(writable: true, useSerializerForHydration: true)]
-                public array $addresses = [];
-            })
-                ->mountWith(['addresses' => [$address1, $address2]])
-                ->assertDehydratesTo(['addresses' => [
-                    [
-                        'address' => '1600 Pennsylvania Avenue',
-                        'city' => 'Washington DC',
-                    ],
-                    [
-                        'address' => '221 B Baker St',
-                        'city' => 'Birmingham',
-                    ],
-                ]])
-                ->userUpdatesProps(['addresses.1.city' => 'London'])
-                ->assertObjectAfterHydration(function (object $object) {
-                    self::assertEquals([
-                        create(Address::class, ['address' => '1600 Pennsylvania Avenue', 'city' => 'Washington DC'])->object(),
-                        create(Address::class, ['address' => '221 B Baker St', 'city' => 'London'])->object(),
-                    ], $object->addresses);
-                });
-        }];
-
-        yield 'Array with DTOs: fully writable allows deep partial changes' => [function () {
-            return HydrationTest::create(new class() {
-                /**
-                 * @var Symfony\UX\LiveComponent\Tests\Fixtures\Dto\HoldsArrayOfDtos[]
-                 */
-                #[LiveProp(writable: true, useSerializerForHydration: true)]
-                public array $dtos = [];
-            })
-                ->mountWith(['dtos' => [
-                    create(HoldsArrayOfDtos::class, ['addresses' => [
-                        create(Address::class, ['address' => '742 Evergreen Terrace', 'city' => 'Boston'])->object(),
-                        create(Address::class, ['address' => 'Apartment 5A, 129 West 81st Street', 'city' => 'New York'])->object(),
-                        create(Address::class, ['address' => '52 Festive Road', 'city' => 'London'])->object(),
-                    ]])->object(),
-                    create(HoldsArrayOfDtos::class, ['addresses' => [
-                        create(Address::class, ['address' => '698 Sycamore Road', 'city' => 'San Pueblo'])->object(),
-                        create(Address::class, ['address' => 'Madison Square Garden', 'city' => 'Chicago'])->object(),
-                    ]])->object(),
-                ]])
-                ->assertDehydratesTo(['dtos' => [
-                    [
-                        'addresses' => [
-                            ['address' => '742 Evergreen Terrace', 'city' => 'Boston'],
-                            ['address' => 'Apartment 5A, 129 West 81st Street', 'city' => 'New York'],
-                            ['address' => '52 Festive Road', 'city' => 'London'],
-                        ],
-                    ],
-                    [
-                        'addresses' => [
-                            ['address' => '698 Sycamore Road', 'city' => 'San Pueblo'],
-                            ['address' => 'Madison Square Garden', 'city' => 'Chicago'],
-                        ],
-                    ],
-                ]])
-                ->userUpdatesProps([
-                    'dtos.0.addresses.0.city' => 'Springfield',
-                    'dtos.1.addresses.1.address' => '1060 West Addison Street',
-                    'dtos.1.addresses.1' => create(Address::class, ['address' => '10 Downing Street', 'city' => 'London'])->object(),
-                ])
-                ->assertObjectAfterHydration(function (object $object) {
-                    self::assertEquals(
-                        [
-                            create(HoldsArrayOfDtos::class, ['addresses' => [
-                                create(Address::class, ['address' => '742 Evergreen Terrace', 'city' => 'Springfield'])->object(),
-                                create(Address::class, ['address' => 'Apartment 5A, 129 West 81st Street', 'city' => 'New York'])->object(),
-                                create(Address::class, ['address' => '52 Festive Road', 'city' => 'London'])->object(),
-                            ]])->object(),
-                            create(HoldsArrayOfDtos::class, ['addresses' => [
-                                create(Address::class, ['address' => '698 Sycamore Road', 'city' => 'San Pueblo'])->object(),
-                                create(Address::class, ['address' => '10 Downing Street', 'city' => 'London'])->object(),
-                            ]])->object(),
-                        ],
-                        $object->dtos
-                    );
-                });
-        }];
-
         yield 'Object: (de)hydrates nested objects with phpdoc typehints' => [function () {
             return HydrationTest::create(new class() {
                 #[LiveProp(writable: true)]
diff --git a/src/LiveComponent/tests/Unit/EventListener/DeferLiveComponentSubscriberTest.php b/src/LiveComponent/tests/Unit/EventListener/DeferLiveComponentSubscriberTest.php
index 5737c03a..eb2dd082 100644
--- a/src/LiveComponent/tests/Unit/EventListener/DeferLiveComponentSubscriberTest.php
+++ b/src/LiveComponent/tests/Unit/EventListener/DeferLiveComponentSubscriberTest.php
@@ -36,19 +36,6 @@ class DeferLiveComponentSubscriberTest extends TestCase
         $this->assertArrayNotHasKey('loading', $event->getData());
     }
 
-    public function testLoadingAttributeIsNotExtractedWhenComponentIsNotLive()
-    {
-        $data = ['loading' => 'lazy'];
-        $event = new PostMountEvent(new \stdClass(), $data, new ComponentMetadata([]));
-        $event->setData($data);
-
-        $subscriber = new DeferLiveComponentSubscriber();
-        $subscriber->onPostMount($event);
-
-        $this->assertArrayNotHasKey('loading', $event->getExtraMetadata());
-        $this->assertArrayHasKey('loading', $event->getData());
-    }
-
     /**
      * @group legacy
      */
@@ -123,7 +110,7 @@ class DeferLiveComponentSubscriberTest extends TestCase
 
     private function createPostMountEvent(array $data): PostMountEvent
     {
-        $componentMetadata = new ComponentMetadata(['live' => true]);
+        $componentMetadata = new ComponentMetadata([]);
         $event = new PostMountEvent(new \stdClass(), $data, $componentMetadata);
         $event->setData($data);
 
diff --git a/src/Translator/tests/Kernel/FrameworkAppKernel.php b/src/Translator/tests/Kernel/FrameworkAppKernel.php
index 2686ab7e..98c0ca6a 100644
--- a/src/Translator/tests/Kernel/FrameworkAppKernel.php
+++ b/src/Translator/tests/Kernel/FrameworkAppKernel.php
@@ -38,10 +38,6 @@ class FrameworkAppKernel extends Kernel
                 'secret' => '$ecret',
                 'test' => true,
                 'translator' => [
-                    'enabled' => match ($this->environment) {
-                        'test_without_translator' => false,
-                        default => true,
-                    },
                     'fallbacks' => ['en'],
                 ],
                 'http_method_override' => false,
diff --git a/src/Translator/tests/TranslationsDumperTest.php b/src/Translator/tests/TranslationsDumperTest.php
index c68a9fef..c21c3a8c 100644
--- a/src/Translator/tests/TranslationsDumperTest.php
+++ b/src/Translator/tests/TranslationsDumperTest.php
@@ -22,7 +22,6 @@ use Symfony\UX\Translator\TranslationsDumper;
 class TranslationsDumperTest extends TestCase
 {
     protected static $translationsDumpDir;
-    private TranslationsDumper $translationsDumper;
 
     public static function setUpBeforeClass(): void
     {
@@ -34,115 +33,17 @@ class TranslationsDumperTest extends TestCase
         @rmdir(self::$translationsDumpDir);
     }
 
-    protected function setUp(): void
+    public function testDump(): void
     {
-        $this->translationsDumper = new TranslationsDumper(
+        $translationsDumper = new TranslationsDumper(
             self::$translationsDumpDir,
             new MessageParametersExtractor(),
             new IntlMessageParametersExtractor(),
             new TypeScriptMessageParametersPrinter(),
             new Filesystem(),
         );
-    }
-
-    public function testDump(): void
-    {
-        $this->translationsDumper->dump(...self::getMessageCatalogues());
-
-        $this->assertFileExists(self::$translationsDumpDir.'/index.js');
-        $this->assertFileExists(self::$translationsDumpDir.'/index.d.ts');
-
-        $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.js', <<<'JAVASCRIPT'
-export const NOTIFICATION_COMMENT_CREATED = {"id":"notification.comment_created","translations":{"messages+intl-icu":{"en":"Your post received a comment!","fr":"Votre article a re\u00e7u un commentaire !"}}};
-export const NOTIFICATION_COMMENT_CREATED_DESCRIPTION = {"id":"notification.comment_created.description","translations":{"messages+intl-icu":{"en":"Your post \"{title}\" has received a new comment. You can read the comment by following <a href=\"{link}\">this link<\/a>","fr":"Votre article \"{title}\" a re\u00e7u un nouveau commentaire. Vous pouvez lire le commentaire en suivant <a href=\"{link}\">ce lien<\/a>"}}};
-export const POST_NUM_COMMENTS = {"id":"post.num_comments","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}}","fr":"{count, plural, one {# commentaire} other {# commentaires}}"},"foobar":{"en":"There is 1 comment|There are %count% comments","fr":"Il y a 1 comment|Il y a %count% comments"}}};
-export const POST_NUM_COMMENTS_1 = {"id":"post.num_comments.","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}} (should not conflict with the previous one.)","fr":"{count, plural, one {# commentaire} other {# commentaires}} (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
-export const SYMFONY_GREAT = {"id":"symfony.great","translations":{"messages":{"en":"Symfony is awesome!","fr":"Symfony est g\u00e9nial !"}}};
-export const SYMFONY_WHAT = {"id":"symfony.what","translations":{"messages":{"en":"Symfony is %what%!","fr":"Symfony est %what%!"}}};
-export const SYMFONY_WHAT_1 = {"id":"symfony.what!","translations":{"messages":{"en":"Symfony is %what%! (should not conflict with the previous one.)","fr":"Symfony est %what%! (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
-export const SYMFONY_WHAT_2 = {"id":"symfony.what.","translations":{"messages":{"en":"Symfony is %what%. (should also not conflict with the previous one.)","fr":"Symfony est %what%. (ne doit pas non plus rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
-export const APPLES_COUNT0 = {"id":"apples.count.0","translations":{"messages":{"en":"There is 1 apple|There are %count% apples","fr":"Il y a 1 pomme|Il y a %count% pommes"}}};
-export const APPLES_COUNT1 = {"id":"apples.count.1","translations":{"messages":{"en":"{1} There is one apple|]1,Inf] There are %count% apples","fr":"{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}};
-export const APPLES_COUNT2 = {"id":"apples.count.2","translations":{"messages":{"en":"{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples","fr":"{0} Il n'y a pas de pommes|{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}};
-export const APPLES_COUNT3 = {"id":"apples.count.3","translations":{"messages":{"en":"one: There is one apple|more: There are %count% apples","fr":"one: Il y a une pomme|more: Il y a %count% pommes"}}};
-export const APPLES_COUNT4 = {"id":"apples.count.4","translations":{"messages":{"en":"one: There is one apple|more: There are more than one apple","fr":"one: Il y a une pomme|more: Il y a plus d'une pomme"}}};
-export const WHAT_COUNT1 = {"id":"what.count.1","translations":{"messages":{"en":"{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}};
-export const WHAT_COUNT2 = {"id":"what.count.2","translations":{"messages":{"en":"{0} There are no %what%|{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{0} Il n'y a pas de %what%|{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}};
-export const WHAT_COUNT3 = {"id":"what.count.3","translations":{"messages":{"en":"one: There is one %what%|more: There are %count% %what%","fr":"one: Il y a une %what%|more: Il y a %count% %what%"}}};
-export const WHAT_COUNT4 = {"id":"what.count.4","translations":{"messages":{"en":"one: There is one %what%|more: There are more than one %what%","fr":"one: Il y a une %what%|more: Il y a more than one %what%"}}};
-export const ANIMAL_DOG_CAT = {"id":"animal.dog-cat","translations":{"messages":{"en":"Dog and cat","fr":"Chien et chat"}}};
-export const ANIMAL_DOG_CAT_1 = {"id":"animal.dog_cat","translations":{"messages":{"en":"Dog and cat (should not conflict with the previous one)","fr":"Chien et chat (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
-export const _0STARTS_WITH_NUMERIC = {"id":"0starts.with.numeric","translations":{"messages":{"en":"Key starts with numeric char","fr":"La touche commence par un caract\u00e8re num\u00e9rique"}}};
-
-JAVASCRIPT);
-
-        $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.d.ts', <<<'TYPESCRIPT'
-import { Message, NoParametersType } from '@symfony/ux-translator';
-
-export declare const NOTIFICATION_COMMENT_CREATED: Message<{ 'messages+intl-icu': { parameters: NoParametersType } }, 'en'|'fr'>;
-export declare const NOTIFICATION_COMMENT_CREATED_DESCRIPTION: Message<{ 'messages+intl-icu': { parameters: { 'title': string, 'link': string } } }, 'en'|'fr'>;
-export declare const POST_NUM_COMMENTS: Message<{ 'messages+intl-icu': { parameters: { 'count': number } }, 'foobar': { parameters: { '%count%': number } } }, 'en'|'fr'>;
-export declare const POST_NUM_COMMENTS_1: Message<{ 'messages+intl-icu': { parameters: { 'count': number } } }, 'en'|'fr'>;
-export declare const SYMFONY_GREAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
-export declare const SYMFONY_WHAT: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
-export declare const SYMFONY_WHAT_1: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
-export declare const SYMFONY_WHAT_2: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
-export declare const APPLES_COUNT0: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
-export declare const APPLES_COUNT1: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
-export declare const APPLES_COUNT2: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
-export declare const APPLES_COUNT3: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
-export declare const APPLES_COUNT4: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
-export declare const WHAT_COUNT1: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>;
-export declare const WHAT_COUNT2: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>;
-export declare const WHAT_COUNT3: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>;
-export declare const WHAT_COUNT4: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
-export declare const ANIMAL_DOG_CAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
-export declare const ANIMAL_DOG_CAT_1: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
-export declare const _0STARTS_WITH_NUMERIC: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
-
-TYPESCRIPT);
-    }
-
-    public function testDumpWithExcludedDomains(): void
-    {
-        $this->translationsDumper->addExcludedDomain('foobar');
-        $this->translationsDumper->dump(...$this->getMessageCatalogues());
-
-        $this->assertFileExists(self::$translationsDumpDir.'/index.js');
-        $this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js'));
-    }
-
-    public function testDumpIncludedDomains(): void
-    {
-        $this->translationsDumper->addIncludedDomain('messages');
-        $this->translationsDumper->dump(...$this->getMessageCatalogues());
 
-        $this->assertFileExists(self::$translationsDumpDir.'/index.js');
-        $this->assertStringNotContainsString('foobar', file_get_contents(self::$translationsDumpDir.'/index.js'));
-    }
-
-    public function testSetBothIncludedAndExcludedDomains(): void
-    {
-        $this->expectException(\LogicException::class);
-        $this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.');
-        $this->translationsDumper->addIncludedDomain('foobar');
-        $this->translationsDumper->addExcludedDomain('messages');
-    }
-
-    public function testSetBothExcludedAndIncludedDomains(): void
-    {
-        $this->expectException(\LogicException::class);
-        $this->expectExceptionMessage('You cannot set both "excluded_domains" and "included_domains" at the same time.');
-        $this->translationsDumper->addExcludedDomain('foobar');
-        $this->translationsDumper->addIncludedDomain('messages');
-    }
-
-    /**
-     * @return list<MessageCatalogue>
-     */
-    private static function getMessageCatalogues(): array
-    {
-        return [
+        $translationsDumper->dump(
             new MessageCatalogue('en', [
                 'messages+intl-icu' => [
                     'notification.comment_created' => 'Your post received a comment!',
@@ -200,7 +101,60 @@ TYPESCRIPT);
                 'foobar' => [
                     'post.num_comments' => 'Il y a 1 comment|Il y a %count% comments',
                 ],
-            ]),
-        ];
+            ])
+        );
+
+        $this->assertFileExists(self::$translationsDumpDir.'/index.js');
+        $this->assertFileExists(self::$translationsDumpDir.'/index.d.ts');
+
+        $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.js', <<<'JAVASCRIPT'
+export const NOTIFICATION_COMMENT_CREATED = {"id":"notification.comment_created","translations":{"messages+intl-icu":{"en":"Your post received a comment!","fr":"Votre article a re\u00e7u un commentaire !"}}};
+export const NOTIFICATION_COMMENT_CREATED_DESCRIPTION = {"id":"notification.comment_created.description","translations":{"messages+intl-icu":{"en":"Your post \"{title}\" has received a new comment. You can read the comment by following <a href=\"{link}\">this link<\/a>","fr":"Votre article \"{title}\" a re\u00e7u un nouveau commentaire. Vous pouvez lire le commentaire en suivant <a href=\"{link}\">ce lien<\/a>"}}};
+export const POST_NUM_COMMENTS = {"id":"post.num_comments","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}}","fr":"{count, plural, one {# commentaire} other {# commentaires}}"},"foobar":{"en":"There is 1 comment|There are %count% comments","fr":"Il y a 1 comment|Il y a %count% comments"}}};
+export const POST_NUM_COMMENTS_1 = {"id":"post.num_comments.","translations":{"messages+intl-icu":{"en":"{count, plural, one {# comment} other {# comments}} (should not conflict with the previous one.)","fr":"{count, plural, one {# commentaire} other {# commentaires}} (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
+export const SYMFONY_GREAT = {"id":"symfony.great","translations":{"messages":{"en":"Symfony is awesome!","fr":"Symfony est g\u00e9nial !"}}};
+export const SYMFONY_WHAT = {"id":"symfony.what","translations":{"messages":{"en":"Symfony is %what%!","fr":"Symfony est %what%!"}}};
+export const SYMFONY_WHAT_1 = {"id":"symfony.what!","translations":{"messages":{"en":"Symfony is %what%! (should not conflict with the previous one.)","fr":"Symfony est %what%! (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
+export const SYMFONY_WHAT_2 = {"id":"symfony.what.","translations":{"messages":{"en":"Symfony is %what%. (should also not conflict with the previous one.)","fr":"Symfony est %what%. (ne doit pas non plus rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
+export const APPLES_COUNT0 = {"id":"apples.count.0","translations":{"messages":{"en":"There is 1 apple|There are %count% apples","fr":"Il y a 1 pomme|Il y a %count% pommes"}}};
+export const APPLES_COUNT1 = {"id":"apples.count.1","translations":{"messages":{"en":"{1} There is one apple|]1,Inf] There are %count% apples","fr":"{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}};
+export const APPLES_COUNT2 = {"id":"apples.count.2","translations":{"messages":{"en":"{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples","fr":"{0} Il n'y a pas de pommes|{1} Il y a une pomme|]1,Inf] Il y a %count% pommes"}}};
+export const APPLES_COUNT3 = {"id":"apples.count.3","translations":{"messages":{"en":"one: There is one apple|more: There are %count% apples","fr":"one: Il y a une pomme|more: Il y a %count% pommes"}}};
+export const APPLES_COUNT4 = {"id":"apples.count.4","translations":{"messages":{"en":"one: There is one apple|more: There are more than one apple","fr":"one: Il y a une pomme|more: Il y a plus d'une pomme"}}};
+export const WHAT_COUNT1 = {"id":"what.count.1","translations":{"messages":{"en":"{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}};
+export const WHAT_COUNT2 = {"id":"what.count.2","translations":{"messages":{"en":"{0} There are no %what%|{1} There is one %what%|]1,Inf] There are %count% %what%","fr":"{0} Il n'y a pas de %what%|{1} Il y a une %what%|]1,Inf] Il y a %count% %what%"}}};
+export const WHAT_COUNT3 = {"id":"what.count.3","translations":{"messages":{"en":"one: There is one %what%|more: There are %count% %what%","fr":"one: Il y a une %what%|more: Il y a %count% %what%"}}};
+export const WHAT_COUNT4 = {"id":"what.count.4","translations":{"messages":{"en":"one: There is one %what%|more: There are more than one %what%","fr":"one: Il y a une %what%|more: Il y a more than one %what%"}}};
+export const ANIMAL_DOG_CAT = {"id":"animal.dog-cat","translations":{"messages":{"en":"Dog and cat","fr":"Chien et chat"}}};
+export const ANIMAL_DOG_CAT_1 = {"id":"animal.dog_cat","translations":{"messages":{"en":"Dog and cat (should not conflict with the previous one)","fr":"Chien et chat (ne doit pas rentrer en conflit avec la traduction pr\u00e9c\u00e9dente)"}}};
+export const _0STARTS_WITH_NUMERIC = {"id":"0starts.with.numeric","translations":{"messages":{"en":"Key starts with numeric char","fr":"La touche commence par un caract\u00e8re num\u00e9rique"}}};
+
+JAVASCRIPT);
+
+        $this->assertStringEqualsFile(self::$translationsDumpDir.'/index.d.ts', <<<'TYPESCRIPT'
+import { Message, NoParametersType } from '@symfony/ux-translator';
+
+export declare const NOTIFICATION_COMMENT_CREATED: Message<{ 'messages+intl-icu': { parameters: NoParametersType } }, 'en'|'fr'>;
+export declare const NOTIFICATION_COMMENT_CREATED_DESCRIPTION: Message<{ 'messages+intl-icu': { parameters: { 'title': string, 'link': string } } }, 'en'|'fr'>;
+export declare const POST_NUM_COMMENTS: Message<{ 'messages+intl-icu': { parameters: { 'count': number } }, 'foobar': { parameters: { '%count%': number } } }, 'en'|'fr'>;
+export declare const POST_NUM_COMMENTS_1: Message<{ 'messages+intl-icu': { parameters: { 'count': number } } }, 'en'|'fr'>;
+export declare const SYMFONY_GREAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
+export declare const SYMFONY_WHAT: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
+export declare const SYMFONY_WHAT_1: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
+export declare const SYMFONY_WHAT_2: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
+export declare const APPLES_COUNT0: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
+export declare const APPLES_COUNT1: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
+export declare const APPLES_COUNT2: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
+export declare const APPLES_COUNT3: Message<{ 'messages': { parameters: { '%count%': number } } }, 'en'|'fr'>;
+export declare const APPLES_COUNT4: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
+export declare const WHAT_COUNT1: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>;
+export declare const WHAT_COUNT2: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>;
+export declare const WHAT_COUNT3: Message<{ 'messages': { parameters: { '%what%': string, '%count%': number } } }, 'en'|'fr'>;
+export declare const WHAT_COUNT4: Message<{ 'messages': { parameters: { '%what%': string } } }, 'en'|'fr'>;
+export declare const ANIMAL_DOG_CAT: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
+export declare const ANIMAL_DOG_CAT_1: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
+export declare const _0STARTS_WITH_NUMERIC: Message<{ 'messages': { parameters: NoParametersType } }, 'en'|'fr'>;
+
+TYPESCRIPT);
     }
 }
diff --git a/src/Translator/tests/UxTranslatorBundleTest.php b/src/Translator/tests/UxTranslatorBundleTest.php
index fe17709d..8f244289 100644
--- a/src/Translator/tests/UxTranslatorBundleTest.php
+++ b/src/Translator/tests/UxTranslatorBundleTest.php
@@ -22,7 +22,6 @@ class UxTranslatorBundleTest extends TestCase
     {
         yield 'empty' => [new EmptyAppKernel('test', true)];
         yield 'framework' => [new FrameworkAppKernel('test', true)];
-        yield 'framework without translator' => [new FrameworkAppKernel('test_without_translator', true)];
     }
 
     /**
diff --git a/src/TwigComponent/tests/Fixtures/templates/anonymous_component_with_empty_props.html.twig b/src/TwigComponent/tests/Fixtures/templates/anonymous_component_with_empty_props.html.twig
deleted file mode 100644
index 2b05a2dc..00000000
--- a/src/TwigComponent/tests/Fixtures/templates/anonymous_component_with_empty_props.html.twig
+++ /dev/null
@@ -1,1 +0,0 @@
-<twig:EmptyProps/>
\ No newline at end of file
diff --git a/src/TwigComponent/tests/Fixtures/templates/anonymous_component_with_props_overwrite_parents_props.html.twig b/src/TwigComponent/tests/Fixtures/templates/anonymous_component_with_props_overwrite_parents_props.html.twig
deleted file mode 100644
index 91a293f6..00000000
--- a/src/TwigComponent/tests/Fixtures/templates/anonymous_component_with_props_overwrite_parents_props.html.twig
+++ /dev/null
@@ -1,3 +0,0 @@
-<twig:Alert size='md'>
-    <twig:Icon/>
-</twig:Alert>
\ No newline at end of file
diff --git a/src/TwigComponent/tests/Fixtures/templates/components/Alert.html.twig b/src/TwigComponent/tests/Fixtures/templates/components/Alert.html.twig
index 46b09843..e88a5795 100644
--- a/src/TwigComponent/tests/Fixtures/templates/components/Alert.html.twig
+++ b/src/TwigComponent/tests/Fixtures/templates/components/Alert.html.twig
@@ -31,6 +31,5 @@
 }) %}
 
 <div class="{{ alert.apply({color, size}, attributes.render('class'), 'flex p-4') }}">
-    {% block content %}
-    {% endblock %}
+    ...
 </div>
\ No newline at end of file
diff --git a/src/TwigComponent/tests/Fixtures/templates/components/EmptyProps.html.twig b/src/TwigComponent/tests/Fixtures/templates/components/EmptyProps.html.twig
deleted file mode 100644
index a8d7ae11..00000000
--- a/src/TwigComponent/tests/Fixtures/templates/components/EmptyProps.html.twig
+++ /dev/null
@@ -1,3 +0,0 @@
-{% props %}
-
-<p>I have an empty props tag</p>
\ No newline at end of file
diff --git a/src/TwigComponent/tests/Fixtures/templates/components/Icon.html.twig b/src/TwigComponent/tests/Fixtures/templates/components/Icon.html.twig
deleted file mode 100644
index e0037a02..00000000
--- a/src/TwigComponent/tests/Fixtures/templates/components/Icon.html.twig
+++ /dev/null
@@ -1,6 +0,0 @@
-{% props size = null %}
-
-<p>I am an icon</p>
-{% if size is not null %}
-    <p>I am {{ size }}</p>
-{% endif %}
\ No newline at end of file
diff --git a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php
index 04390622..ef55dbc3 100644
--- a/src/TwigComponent/tests/Integration/ComponentExtensionTest.php
+++ b/src/TwigComponent/tests/Integration/ComponentExtensionTest.php
@@ -366,21 +366,6 @@ final class ComponentExtensionTest extends KernelTestCase
         self::getContainer()->get(Environment::class)->render('component_with_conflict_between_props_from_template_and_class.html.twig');
     }
 
-    public function testComponentWithEmptyProps(): void
-    {
-        $output = self::getContainer()->get(Environment::class)->render('anonymous_component_with_empty_props.html.twig');
-
-        $this->assertStringContainsString('I have an empty props tag', $output);
-    }
-
-    public function testAnonymousComponentWithPropsOverwriteParentsProps(): void
-    {
-        $output = self::getContainer()->get(Environment::class)->render('anonymous_component_with_props_overwrite_parents_props.html.twig');
-
-        $this->assertStringContainsString('I am an icon', $output);
-        $this->assertStringNotContainsString('I am md', $output);
-    }
-
     private function renderComponent(string $name, array $data = []): string
     {
         return self::getContainer()->get(Environment::class)->render('render_component.html.twig', [