From fec07e55f950c10b9377d1fd90b763df75bea51f Mon Sep 17 00:00:00 2001 From: Alexander Hofbauer Date: Mon, 13 May 2024 14:23:43 +0200 Subject: [PATCH] [LiveComponent] Setup for browser tests --- .github/workflows/test-live-component.yml | 73 ++++++++++++++ .github/workflows/test.yaml | 1 + src/LiveComponent/.gitignore | 6 +- src/LiveComponent/composer.json | 7 ++ src/LiveComponent/phpunit.xml.dist | 5 + src/LiveComponent/tests/app/assets/app.js | 3 + .../tests/app/assets/bootstrap.js | 7 ++ .../tests/app/assets/controllers.json | 14 +++ .../tests/app/assets/controllers/.gitignore | 0 src/LiveComponent/tests/app/package.json | 27 ++++++ src/LiveComponent/tests/app/public/index.php | 28 ++++++ src/LiveComponent/tests/app/src/Kernel.php | 94 +++++++++++++++++++ .../tests/app/templates/base.html.twig | 12 +++ src/LiveComponent/tests/app/webpack.config.js | 24 +++++ 14 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test-live-component.yml create mode 100644 src/LiveComponent/tests/app/assets/app.js create mode 100644 src/LiveComponent/tests/app/assets/bootstrap.js create mode 100644 src/LiveComponent/tests/app/assets/controllers.json create mode 100644 src/LiveComponent/tests/app/assets/controllers/.gitignore create mode 100644 src/LiveComponent/tests/app/package.json create mode 100644 src/LiveComponent/tests/app/public/index.php create mode 100644 src/LiveComponent/tests/app/src/Kernel.php create mode 100644 src/LiveComponent/tests/app/templates/base.html.twig create mode 100644 src/LiveComponent/tests/app/webpack.config.js diff --git a/.github/workflows/test-live-component.yml b/.github/workflows/test-live-component.yml new file mode 100644 index 00000000000..b25167cc775 --- /dev/null +++ b/.github/workflows/test-live-component.yml @@ -0,0 +1,73 @@ +name: Symfony UX Live Components + +on: + push: + paths: + - 'src/LiveComponent/**' + pull_request: + paths: + - 'src/LiveComponent/**' + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-version: ['8.1', '8.3'] + include: + - php-version: '8.1' + dependency-version: 'lowest' + - php-version: '8.3' + dependency-version: 'highest' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + + - name: Install LiveComponent packages + uses: ramsey/composer-install@v3 + with: + working-directory: src/LiveComponent + dependency-versions: ${{ matrix.dependency-version }} + + - name: Build root packages + run: php .github/build-packages.php + working-directory: ${{ github.workspace }} + + - name: Install LiveComponent packages + uses: ramsey/composer-install@v3 + with: + working-directory: src/LiveComponent + dependency-versions: ${{ matrix.dependency-version }} + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/package.json') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install JavaScript dependencies + working-directory: src/LiveComponent/tests/app + run: yarn install + + - name: Build JavaScript + working-directory: src/LiveComponent/tests/app + run: yarn build + + - name: Run tests + working-directory: src/LiveComponent + run: vendor/bin/simple-phpunit + env: + SYMFONY_DEPRECATIONS_HELPER: 'max[self]=1' diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 96a0c126b02..5fda73efd8c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -91,6 +91,7 @@ jobs: exclude: - component: Swup # has no tests - component: Turbo # has its own workflow (test-turbo.yml) + - component: LiveComponent # has its own workflow (test-live-component.yml) - component: Typed # has no tests steps: diff --git a/src/LiveComponent/.gitignore b/src/LiveComponent/.gitignore index 854217846fe..5f22928d5bf 100644 --- a/src/LiveComponent/.gitignore +++ b/src/LiveComponent/.gitignore @@ -1,5 +1,9 @@ +/.phpunit.result.cache /composer.lock /phpunit.xml +/drivers /vendor/ /var/ -/.phpunit.result.cache +/tests/app/var +/tests/app/public/build/ +/tests/app/yarn.lock diff --git a/src/LiveComponent/composer.json b/src/LiveComponent/composer.json index f00a40c9db9..bd78f7f027f 100644 --- a/src/LiveComponent/composer.json +++ b/src/LiveComponent/composer.json @@ -22,6 +22,7 @@ }, "autoload-dev": { "psr-4": { + "App\\": "tests/app/src/", "Symfony\\UX\\LiveComponent\\Tests\\": "tests/" } }, @@ -32,23 +33,29 @@ "twig/twig": "^3.8.0" }, "require-dev": { + "dbrekelmans/bdi": "dev-main", "doctrine/annotations": "^1.0", "doctrine/collections": "^1.6.8|^2.0", "doctrine/doctrine-bundle": "^2.4.3", "doctrine/orm": "^2.9.4", "doctrine/persistence": "^2.5.2|^3.0", "phpdocumentor/reflection-docblock": "5.x-dev", + "symfony/debug-bundle": "^5.4|^6.0|^7.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/form": "^5.4|^6.0|^7.0", "symfony/framework-bundle": "^5.4|^6.0|^7.0", "symfony/options-resolver": "^5.4|^6.0|^7.0", + "symfony/panther": "^1.0|^2.0", "symfony/phpunit-bridge": "^6.1|^7.0", "symfony/property-info": "^5.4|^6.0|^7.0", "symfony/security-bundle": "^5.4|^6.0|^7.0", "symfony/serializer": "^5.4|^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9.1", "symfony/twig-bundle": "^5.4|^6.0|^7.0", "symfony/validator": "^5.4|^6.0|^7.0", + "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0", + "symfony/webpack-encore-bundle": "^2.1.1", "zenstruck/browser": "^1.2.0", "zenstruck/foundry": "1.37.*" }, diff --git a/src/LiveComponent/phpunit.xml.dist b/src/LiveComponent/phpunit.xml.dist index 87b89d583e8..e8341f726ca 100644 --- a/src/LiveComponent/phpunit.xml.dist +++ b/src/LiveComponent/phpunit.xml.dist @@ -19,6 +19,7 @@ + @@ -30,4 +31,8 @@ + + + + diff --git a/src/LiveComponent/tests/app/assets/app.js b/src/LiveComponent/tests/app/assets/app.js new file mode 100644 index 00000000000..9a2675b56ae --- /dev/null +++ b/src/LiveComponent/tests/app/assets/app.js @@ -0,0 +1,3 @@ +'use strict'; + +import './bootstrap'; diff --git a/src/LiveComponent/tests/app/assets/bootstrap.js b/src/LiveComponent/tests/app/assets/bootstrap.js new file mode 100644 index 00000000000..8d4da7d7f07 --- /dev/null +++ b/src/LiveComponent/tests/app/assets/bootstrap.js @@ -0,0 +1,7 @@ +import { startStimulusApp } from '@symfony/stimulus-bridge'; + +export const app = startStimulusApp(require.context( + '@symfony/stimulus-bridge/lazy-controller-loader!./controllers', + true, + /\.[jt]sx?$/ +)); diff --git a/src/LiveComponent/tests/app/assets/controllers.json b/src/LiveComponent/tests/app/assets/controllers.json new file mode 100644 index 00000000000..2d65bb28240 --- /dev/null +++ b/src/LiveComponent/tests/app/assets/controllers.json @@ -0,0 +1,14 @@ +{ + "controllers": { + "@symfony/ux-live-component": { + "live": { + "enabled": true, + "fetch": "eager", + "autoimport": { + "../../../assets/dist/live.min.css": true + } + } + } + }, + "entrypoints": [] +} diff --git a/src/LiveComponent/tests/app/assets/controllers/.gitignore b/src/LiveComponent/tests/app/assets/controllers/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/LiveComponent/tests/app/package.json b/src/LiveComponent/tests/app/package.json new file mode 100644 index 00000000000..22b0432fcb2 --- /dev/null +++ b/src/LiveComponent/tests/app/package.json @@ -0,0 +1,27 @@ +{ + "devDependencies": { + "@babel/core": "^7.20.12", + "@babel/preset-env": "^7.20.2", + "@hotwired/stimulus": "^3.0.0", + "@symfony/stimulus-bridge": "^3.2.2", + "@symfony/stimulus-bundle": "file:../../vendor/symfony/stimulus-bundle/assets", + "@symfony/ux-live-component": "file:../../assets", + "@symfony/webpack-encore": "^4.2.0", + "core-js": "^3.0.0", + "regenerator-runtime": "^0.13.2", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1", + "webpack-notifier": "^1.6.0" + }, + "resolutions": { + "coa": "2.0.2" + }, + "license": "MIT", + "private": true, + "scripts": { + "dev-server": "encore dev-server", + "dev": "encore dev", + "watch": "encore dev --watch", + "build": "encore production --progress" + } +} diff --git a/src/LiveComponent/tests/app/public/index.php b/src/LiveComponent/tests/app/public/index.php new file mode 100644 index 00000000000..3b0f4f6a53c --- /dev/null +++ b/src/LiveComponent/tests/app/public/index.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use App\Kernel; +use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\HttpFoundation\Request; + +require __DIR__.'/../../../vendor/autoload.php'; + +$app = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? true); + +if (\PHP_SAPI === 'cli') { + $application = new Application($app); + exit($application->run()); +} + +$request = Request::createFromGlobals(); +$response = $app->handle($request); +$response->send(); +$app->terminate($request, $response); diff --git a/src/LiveComponent/tests/app/src/Kernel.php b/src/LiveComponent/tests/app/src/Kernel.php new file mode 100644 index 00000000000..cbe10f842c7 --- /dev/null +++ b/src/LiveComponent/tests/app/src/Kernel.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App; + +use Symfony\Bundle\DebugBundle\DebugBundle; +use Symfony\Bundle\FrameworkBundle\Controller\TemplateController; +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; +use Symfony\Bundle\TwigBundle\TwigBundle; +use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle; +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use Symfony\Component\HttpKernel\Kernel as BaseKernel; +use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; +use Symfony\UX\LiveComponent\LiveComponentBundle; +use Symfony\UX\StimulusBundle\StimulusBundle; +use Symfony\UX\TwigComponent\TwigComponentBundle; +use Symfony\WebpackEncoreBundle\WebpackEncoreBundle; + +/** + * @author Alexander Hofbauer + */ +class Kernel extends BaseKernel +{ + use MicroKernelTrait; + + public function getProjectDir(): string + { + return __DIR__.'/../'; + } + + public function registerBundles(): iterable + { + yield new FrameworkBundle(); + yield new TwigBundle(); + yield new WebpackEncoreBundle(); + yield new WebProfilerBundle(); + yield new DebugBundle(); + yield new StimulusBundle(); + yield new TwigComponentBundle(); + yield new LiveComponentBundle(); + } + + protected function configureContainer(ContainerConfigurator $container): void + { + $container->extension('framework', [ + 'secret' => 'ChangeMe', + 'test' => 'test' === ($_SERVER['APP_ENV'] ?? 'dev'), + 'router' => [ + 'utf8' => true, + ], + 'profiler' => [ + 'only_exceptions' => false, + ], + ]); + + $container->extension('web_profiler', [ + 'toolbar' => true, + 'intercept_redirects' => false, + ]); + + $container->extension('twig_component', [ + 'anonymous_template_directory' => 'components/', + 'defaults' => [ + 'App\\Twig\\Component\\' => 'components/', + ], + ]); + + $container->extension('webpack_encore', ['output_path' => 'build']); + + $container->services() + ->defaults() + ->autowire() + ->autoconfigure() + ->load(__NAMESPACE__.'\\Twig\\Component\\', __DIR__.'/Twig/Component'); + } + + protected function configureRoutes(RoutingConfigurator $routes): void + { + $routes->import('@LiveComponentBundle/config/routes.php')->prefix('/_components'); + $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml')->prefix('/_wdt'); + $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml')->prefix('/_profiler'); + + $routes->add('whitespace_classes', '/whitespace-classes')->controller(TemplateController::class)->defaults(['template' => 'whitespace_classes.html.twig']); + } +} diff --git a/src/LiveComponent/tests/app/templates/base.html.twig b/src/LiveComponent/tests/app/templates/base.html.twig new file mode 100644 index 00000000000..cc739cec935 --- /dev/null +++ b/src/LiveComponent/tests/app/templates/base.html.twig @@ -0,0 +1,12 @@ + + + + + Symfony UX Live Components + {% block stylesheets %}{% endblock %} + {{ encore_entry_script_tags('app') }} + + + {% block body %}{% endblock %} + + diff --git a/src/LiveComponent/tests/app/webpack.config.js b/src/LiveComponent/tests/app/webpack.config.js new file mode 100644 index 00000000000..e70046c70a5 --- /dev/null +++ b/src/LiveComponent/tests/app/webpack.config.js @@ -0,0 +1,24 @@ +var Encore = require('@symfony/webpack-encore'); + +if (!Encore.isRuntimeEnvironmentConfigured()) { + Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev'); +} + +Encore + .setOutputPath('public/build/') + .setPublicPath('/build') + .addEntry('app', './assets/app.js') + .enableStimulusBridge('./assets/controllers.json') + .splitEntryChunks() + .enableSingleRuntimeChunk() + .cleanupOutputBeforeBuild() + .enableBuildNotifications() + .enableSourceMaps(!Encore.isProduction()) + .enableVersioning(Encore.isProduction()) + .configureBabelPresetEnv((config) => { + config.useBuiltIns = 'usage'; + config.corejs = 3; + }) +; + +module.exports = Encore.getWebpackConfig();