diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..42465ac --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,74 @@ +name: Coverage + +on: + # Run testing on all push and pull requests that have committed changes in PHP files + push: + paths: + - '**/*.php' + pull_request: + paths: + - '**/*.php' + # Make it possible to run the workflow manually + workflow_dispatch: + +permissions: + contents: read + +jobs: + coverage: + + runs-on: ubuntu-latest + + name: Code coverage report + + steps: + + #- name: Configure operating system + # run: sudo apt-get update && sudo apt-get install -y locales locales-all + + - name: Checkout code + uses: actions/checkout@v6.0.2 + with: + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v5.0.5 + with: + path: vendor + key: coverage-${{ hashFiles('**/composer.lock') }} + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + coverage: xdebug + extensions: mbstring, gd, intl, pcntl + + - name: Install dependencies + run: composer update --prefer-dist --no-progress --prefer-stable + + - name: Setup testbench environment + run: | + cp workbench/.env.example workbench/.env + sed -i 's/APP_KEY=/APP_KEY=base64:ZQvPGC7uVADkjOgtGIIuCI8u3\/Pzu+VaRObIbHsgjCc=/' workbench/.env + sed -i 's/APP_ENV=local/APP_ENV=testing/' workbench/.env + grep "APP_KEY=base64:" workbench/.env + npm install + php vendor/bin/testbench vendor:publish --tag='filament-shield-config' + php vendor/bin/testbench filament:assets + php vendor/bin/testbench package:sync-skeleton + + - name: Run test suite with coverage + run: vendor/bin/pest --coverage-clover ./coverage.xml + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v6.0.0 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + files: ./coverage.xml + verbose: true diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index b46b505..bc54579 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -60,23 +60,25 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - coverage: xdebug - # extensions: mbstring, gd, intl + coverage: none + extensions: mbstring, gd, intl, pcntl - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update - composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-interaction + composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update + composer require "orchestra/testbench:${{ matrix.testbench }}" --dev --no-interaction --no-update + composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-interaction --no-scripts - - name: Run test suite - run: composer test -- --coverage-clover ./coverage.xml + - name: Setup testbench environment + run: | + cp workbench/.env.example workbench/.env + sed -i 's/APP_KEY=/APP_KEY=base64:ZQvPGC7uVADkjOgtGIIuCI8u3\/Pzu+VaRObIbHsgjCc=/' workbench/.env + sed -i 's/APP_ENV=local/APP_ENV=testing/' workbench/.env + grep "APP_KEY=base64:" workbench/.env + npm install + php vendor/bin/testbench vendor:publish --tag='filament-shield-config' + php vendor/bin/testbench filament:assets + php vendor/bin/testbench package:sync-skeleton - - name: Upload coverage reports to Codecov - # Make sure the Codecov action is only executed once - if: matrix.php == '8.3' && matrix.laravel == '12.*' && matrix.dependency-version == 'prefer-stable' - uses: codecov/codecov-action@v6.0.0 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - files: ./coverage.xml - verbose: true + - name: Run test suite + run: vendor/bin/pest --ci --parallel diff --git a/.lando.dist.yml b/.lando.dist.yml index 04e9e45..ef8a196 100644 --- a/.lando.dist.yml +++ b/.lando.dist.yml @@ -14,7 +14,7 @@ services: APP_BASE_PATH: "/app/workbench" TESTBENCH_WORKING_PATH: "/app" overrides: - image: slimdeluxe/php:8.3-v1.4 + image: slimdeluxe/php:8.3-v1.5 platform: linux/amd64 run: - composer install --no-interaction --prefer-dist diff --git a/composer.json b/composer.json index 0fe9e09..118b63c 100644 --- a/composer.json +++ b/composer.json @@ -53,8 +53,9 @@ "require-dev": { "laravel/pint": "^1.21", "orchestra/testbench": "^9.9|^10.0", - "pestphp/pest": "^3.7", - "pestphp/pest-plugin-livewire": "^3.0" + "pestphp/pest": "^4.0", + "pestphp/pest-plugin-laravel": "^4.0", + "pestphp/pest-plugin-livewire": "^4.0" }, "scripts": { "post-autoload-dump": [ @@ -64,7 +65,7 @@ "post-install-cmd": "@setup", "post-update-cmd": "@setup", "format": "vendor/bin/pint", - "test": "vendor/bin/testbench package:test", + "test": "vendor/bin/pest --parallel", "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", "prepare": "@php vendor/bin/testbench package:discover --ansi", "build": "@php vendor/bin/testbench workbench:build --ansi", diff --git a/env/php-8.4/.lando.dist.yml b/env/php-8.4/.lando.dist.yml index c7a192a..087f5f3 100644 --- a/env/php-8.4/.lando.dist.yml +++ b/env/php-8.4/.lando.dist.yml @@ -5,7 +5,7 @@ services: via: cli app_mount: delegated overrides: - image: slimdeluxe/php:8.4-v1.4 + image: slimdeluxe/php:8.4-v1.5 volumes: # Mount the project root directory to /app - "../..:/app" diff --git a/env/php-8.5/.lando.dist.yml b/env/php-8.5/.lando.dist.yml index e528042..16fd82c 100644 --- a/env/php-8.5/.lando.dist.yml +++ b/env/php-8.5/.lando.dist.yml @@ -5,7 +5,7 @@ services: via: cli app_mount: delegated overrides: - image: slimdeluxe/php:8.5-v1.4 + image: slimdeluxe/php:8.5-v1.5 volumes: # Mount the project root directory to /app - "../..:/app" diff --git a/package-lock.json b/package-lock.json index 41e8dad..ee77dcc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -303,19 +303,19 @@ } }, "node_modules/@types/node": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -511,13 +511,13 @@ } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", - "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", "dev": true, "license": "MIT", "dependencies": { - "jiti": "^2.6.1" + "jiti": "2.6.1" }, "engines": { "node": ">=v18" @@ -1145,9 +1145,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", "dev": true, "license": "MIT", "engines": { @@ -1155,9 +1155,9 @@ } }, "node_modules/typescript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", - "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "peer": true, @@ -1170,9 +1170,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, diff --git a/tests/Feature/SmokeTest.php b/tests/Feature/SmokeTest.php new file mode 100644 index 0000000..ed23abc --- /dev/null +++ b/tests/Feature/SmokeTest.php @@ -0,0 +1,93 @@ +setUpSuperAdmin(); +}); + +describe('Smoke Tests', function () { + test('all resource URLs are accessible', function () { + $resources = [ + CountryResource::class, + CurrencyResource::class, + PostResource::class, + RegionResource::class, + ]; + + foreach ($resources as $resource) { + /** @noinspection PhpUndefinedMethodInspection */ + $this->get($resource::getUrl()) + ->assertSuccessful() + ->assertSee('Filament'); + } + }); + + test('country resource URLs are accessible', function () { + $this->get(CountryResource::getUrl()) + ->assertSuccessful() + ->assertSee('Countries') + ->assertSee('Filament'); + }); + + test('currency resource URLs are accessible', function () { + $this->get(CurrencyResource::getUrl()) + ->assertSuccessful() + ->assertSee('Currencies') + ->assertSee('Filament'); + }); + + test('post resource URLs are accessible', function () { + $this->get(PostResource::getUrl()) + ->assertSuccessful() + ->assertSee('Posts') + ->assertSee('Filament'); + }); + + test('region resource URLs are accessible', function () { + $this->get(RegionResource::getUrl()) + ->assertSuccessful() + ->assertSee('Regions') + ->assertSee('Filament'); + }); + + test('all resource URLs return valid HTML', function () { + $resources = [ + CountryResource::class, + CurrencyResource::class, + PostResource::class, + RegionResource::class, + ]; + + foreach ($resources as $resource) { + /** @noinspection PhpUndefinedMethodInspection */ + $response = $this->get($resource::getUrl()); + + $response->assertSuccessful(); + $response->assertHeader('content-type', 'text/html; charset=utf-8'); + $response->assertSee('', false); + } + }); + + test('all resource URLs have no JavaScript errors', function () { + $resources = [ + CountryResource::class, + CurrencyResource::class, + PostResource::class, + RegionResource::class, + ]; + + foreach ($resources as $resource) { + /** @noinspection PhpUndefinedMethodInspection */ + $response = $this->get($resource::getUrl()); + + $response->assertSuccessful(); + $response->assertDontSee('Uncaught'); + $response->assertDontSee('ReferenceError'); + $response->assertDontSee('TypeError'); + } + }); +}); diff --git a/tests/TestCase.php b/tests/TestCase.php index 4270cf7..f2f51c4 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -42,7 +42,10 @@ protected function migrate(): self */ protected function setUpSuperAdmin(): self { - $this->superAdmin = User::factory()->create(); + $this->superAdmin = User::factory()->create([ + 'name' => 'Test Super Admin', + 'email' => 'test@example.com', + ]); // Assign super admin role and give all permissions $superAdminRole = Role::where('name', 'super_admin')->first(); diff --git a/workbench/config/database.php b/workbench/config/database.php index 125949e..12b2b42 100644 --- a/workbench/config/database.php +++ b/workbench/config/database.php @@ -1,6 +1,7 @@ true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ - PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + version_compare(PHP_VERSION, '8.4', '>=') ? Mysql::ATTR_SSL_CA : PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ],