diff --git a/.github/workflows/analyse.yml b/.github/workflows/analyse.yml index 21f448d..885b94d 100644 --- a/.github/workflows/analyse.yml +++ b/.github/workflows/analyse.yml @@ -3,8 +3,21 @@ name: analyse on: ['push', 'pull_request'] jobs: - analyse: - runs-on: ubuntu-latest + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest] + php: [8.3] + laravel: [11.*] + stability: [prefer-stable] + include: + - laravel: 11.* + testbench: 9.* + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} + steps: - name: Checkout code uses: actions/checkout@v4 @@ -12,13 +25,13 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.3 + php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo coverage: none - name: Install dependencies run: | - composer require "laravel/framework:10.*" "orchestra/testbench:8.*" --no-interaction --no-update - composer update --prefer-stable --prefer-dist --no-interaction + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Analyse run: composer analyse \ No newline at end of file diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..46cd0f5 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,38 @@ +name: coverage + +on: ['push', 'pull_request'] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest] + php: [8.3] + laravel: [11.*] + stability: [prefer-stable] + include: + - laravel: 11.* + testbench: 9.* + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, xdebug + coverage: xdebug + + - name: Install dependencies + run: | + composer config allow-plugins.pestphp/pest-plugin true + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.stability }} --prefer-dist --no-interaction + - name: Execute tests + run: XDEBUG_MODE=coverage php vendor/bin/pest --coverage --min=85 \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e302d85 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,40 @@ +name: tests + +on: [ 'push', 'pull_request' ] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ ubuntu-latest ] + php: [ 8.1, 8.2, 8.3 ] + laravel: [ 11.* ] + stability: [ prefer-lowest, prefer-stable ] + include: + - laravel: 11.* + testbench: 9.* + exclude: + - laravel: 11.* + php: 8.1 + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo + coverage: none + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.stability }} --prefer-dist --no-interaction + - name: Execute tests + run: composer test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 885baa6..47108ec 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ composer.lock node_modules vendor .php_cs.cache +.phpunit.result.cache \ No newline at end of file diff --git a/README.md b/README.md index e55cfce..d2a8874 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ + + Banner + + # Statamic glide directive > Blade directive to use glide with images diff --git a/art/banner.png b/art/banner.png new file mode 100644 index 0000000..6716abe Binary files /dev/null and b/art/banner.png differ diff --git a/composer.json b/composer.json index c0da64b..028aa27 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Addon that adds a glide blade directive", "type": "package", "require": { - "php": "^8.2|^8.3", + "php": "^8.1|^8.2|^8.3", "laravel/framework": "^11.0", "statamic/cms": "^5.0" }, @@ -11,17 +11,25 @@ "laravel/pint": "^1.7", "larastan/larastan": "^2.5", "phpstan/phpstan-mockery": "^1.1", - "orchestra/testbench": "^8.0|^9.0" + "phpunit/phpunit": "^10.1", + "orchestra/testbench": "^8.0|^9.0", + "pestphp/pest": "^2.0" }, "autoload": { "psr-4": { "JustBetter\\GlideDirective\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "JustBetter\\GlideDirective\\Tests\\": "tests" + } + }, "config": { "sort-packages": true, "allow-plugins": { - "pixelfear/composer-dist-plugin": true + "pixelfear/composer-dist-plugin": true, + "pestphp/pest-plugin": true } }, "extra": { @@ -48,9 +56,15 @@ } ], "scripts": { + "test": "phpunit", "analyse": "phpstan", - "fix-style": "pint", - "style": "pint --test" + "style": "pint --test", + "quality": [ + "@test", + "@analyse", + "@style" + ], + "fix-style": "pint" }, "minimum-stability": "dev" } diff --git a/phpstan.neon b/phpstan.neon index 71d49fb..ffdbf4b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,5 +5,7 @@ includes: parameters: paths: - src + - tests level: 8 - checkMissingIterableValueType: false \ No newline at end of file + ignoreErrors: + - identifier: missingType.iterableValue diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..91b8cae --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,14 @@ + + + + + ./tests/* + + + + + + ./src + + + \ No newline at end of file diff --git a/src/Jobs/GenerateGlideImageJob.php b/src/Jobs/GenerateGlideImageJob.php index c1ba80b..b0d682a 100644 --- a/src/Jobs/GenerateGlideImageJob.php +++ b/src/Jobs/GenerateGlideImageJob.php @@ -2,28 +2,27 @@ namespace JustBetter\GlideDirective\Jobs; +use Illuminate\Bus\Batchable; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Statamic\Assets\Asset; -use Illuminate\Bus\Batchable; use Statamic\Statamic; class GenerateGlideImageJob implements ShouldQueue { + use Batchable; use Dispatchable; use InteractsWithQueue; use Queueable; - use Batchable; public function __construct( public Asset $asset, public string $preset = '', public string $fit = '', public ?string $format = null, - ) { - } + ) {} public function handle(): void { @@ -34,7 +33,7 @@ public function handle(): void 'preset' => $this->preset, 'src' => $this->asset->url(), 'format' => $this->format, - 'fit' => $this->fit + 'fit' => $this->fit, ] )->fetch(); } diff --git a/src/Responsive.php b/src/Responsive.php index 40ae858..3d771cc 100644 --- a/src/Responsive.php +++ b/src/Responsive.php @@ -2,17 +2,17 @@ namespace JustBetter\GlideDirective; -use JustBetter\GlideDirective\Jobs\GenerateGlideImageJob; -use Statamic\Contracts\Imaging\ImageManipulator; use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\View; +use JustBetter\GlideDirective\Jobs\GenerateGlideImageJob; +use Statamic\Assets\Asset; +use Statamic\Contracts\Imaging\ImageManipulator; use Statamic\Facades\Glide; use Statamic\Facades\Image; use Statamic\Facades\URL; -use Statamic\Assets\Asset; use Statamic\Fields\Value; -use Statamic\Support\Str; use Statamic\Statamic; +use Statamic\Support\Str; class Responsive { @@ -81,7 +81,7 @@ public static function getPresets(Asset $asset): array } if (self::canUseMimeTypeSource()) { - if($glideUrl = self::getGlideUrl($asset, $fit ?? $data['fit'], $preset)) { + if ($glideUrl = self::getGlideUrl($asset, $fit ?? $data['fit'], $preset)) { $presets[$asset->mimeType()] .= $glideUrl.' '.$size; if ($preset !== 'placeholder') { @@ -99,7 +99,7 @@ public static function getPresets(Asset $asset): array $index++; } - if (!$webpSourceFound && !$mimeTypeSourceFound) { + if (! $webpSourceFound && ! $mimeTypeSourceFound) { $presets = ['placeholder' => $asset->url()]; } @@ -107,7 +107,7 @@ public static function getPresets(Asset $asset): array $presets['placeholder'] = Statamic::tag('glide:data_url')->params([ 'preset' => collect($configPresets)->keys()->first(), 'src' => $asset->url(), - 'fit' => 'crop_focal' + 'fit' => 'crop_focal', ])->fetch(); } @@ -121,7 +121,7 @@ protected static function getGlideUrl(Asset $asset, string $preset, string $fit, 'preset' => $preset, 'src' => $asset->url(), 'format' => $format, - 'fit' => $fit + 'fit' => $fit, ])->fetch(); } @@ -133,10 +133,11 @@ protected static function getGlideUrl(Asset $asset, string $preset, string $fit, $params = $manipulator->getParams(); - $manipulationCacheKey = 'asset::' . $asset->id() . '::' . md5(json_encode($params) ? json_encode($params) : ''); + $manipulationCacheKey = 'asset::'.$asset->id().'::'.md5(json_encode($params) ? json_encode($params) : ''); if ($cachedUrl = Glide::cacheStore()->get($manipulationCacheKey)) { - $url = Str::ensureLeft(config('statamic.assets.image_manipulation.route'), '/') . '/' . $cachedUrl; + $url = Str::ensureLeft(config('statamic.assets.image_manipulation.route'), '/').'/'.$cachedUrl; + return URL::encode($url); } diff --git a/tests/Assets/.gitignore b/tests/Assets/.gitignore new file mode 100644 index 0000000..0ac405b --- /dev/null +++ b/tests/Assets/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!test.png \ No newline at end of file diff --git a/tests/Assets/test.png b/tests/Assets/test.png new file mode 100644 index 0000000..6716abe Binary files /dev/null and b/tests/Assets/test.png differ diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..879ec07 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,72 @@ +set('statamic.assets.image_manipulation.driver', 'gd'); + $app['config']->set('statamic.assets.image_manipulation.cache', true); + $app['config']->set('statamic.assets.image_manipulation.cache_path', __DIR__.'/Assets/img'); + + $app['config']->set('filesystems.disks.assets', [ + 'driver' => 'local', + 'root' => $this->assetPath(), + 'url' => '/test', + ]); + } + + protected string $addonServiceProvider = ServiceProvider::class; + + protected mixed $blade; + + protected function setUp(): void + { + parent::setUp(); + + $this->blade = app('blade.compiler'); + } + + public function assetPath(string $file = ''): string + { + $path = __DIR__.'/Assets'; + + if (strlen($file) > 0) { + $path .= '/'.$file; + } + + return $path; + } + + protected function uploadTestAsset(string $filename): Asset + { + UploadedFile::fake(); + + /* @phpstan-ignore-next-line */ + $assetContainer = (new AssetContainer) + ->handle('test_container') + ->disk('assets') + ->save(); + + copy($this->assetPath('test.png'), $this->assetPath($filename)); + + $file = new UploadedFile($this->assetPath($filename), 'test.png'); + $path = $file->getClientOriginalName(); + + return $assetContainer->makeAsset($path)->upload($file); + } +} diff --git a/tests/View/Blade/ResponsiveDirectiveTest.php b/tests/View/Blade/ResponsiveDirectiveTest.php new file mode 100644 index 0000000..75517ee --- /dev/null +++ b/tests/View/Blade/ResponsiveDirectiveTest.php @@ -0,0 +1,90 @@ +"; + + $this->assertSame($expected, $this->blade->compileString($blade)); + } + + #[Test] + public function test_responsive_directive_tag_handle(): void + { + $asset = $this->uploadTestAsset('upload.png'); + $view = Responsive::handle($asset); + $asset->delete(); + + /* @phpstan-ignore-next-line */ + $this->assertStringContainsString('render()); + } + + #[Test] + public function test_responsive_directive_tag_cant_handle_string(): void + { + $asset = $this->uploadTestAsset('upload.png'); + $view = Responsive::handle($asset->url()); + $asset->delete(); + + $this->assertSame($view, ''); + } + + #[Test] + public function can_dispatch_glide_job(): void + { + Queue::fake(); + Queue::assertNothingPushed(); + + $asset = $this->uploadTestAsset('upload.png'); + GenerateGlideImageJob::dispatch($asset, 'xs', '', null); + + Queue::assertPushed(GenerateGlideImageJob::class, 1); + $asset->delete(); + } + + #[Test] + public function can_generate_glide_preset(): void + { + $asset = $this->uploadTestAsset('upload.png'); + + $glideImage = Statamic::tag('glide')->params( + [ + 'preset' => 'xs', + 'src' => $asset->url(), + 'format' => null, + 'fit' => null, + ] + )->fetch(); + + $asset->delete(); + + $this->assertStringContainsString('/containers/test_container/test', $glideImage); + } + + #[Test] + public function can_get_presets_for_asset(): void + { + $asset = $this->uploadTestAsset('upload.png'); + $presets = Responsive::getPresets($asset); + + $this->assertIsArray($presets); + $this->assertArrayHasKey('placeholder', $presets); + } +} diff --git a/tests/__fixtures__/content/assets/test_container.yaml b/tests/__fixtures__/content/assets/test_container.yaml new file mode 100644 index 0000000..1bb97e5 --- /dev/null +++ b/tests/__fixtures__/content/assets/test_container.yaml @@ -0,0 +1 @@ +disk: assets diff --git a/tests/__fixtures__/dev-null/.gitkeep b/tests/__fixtures__/dev-null/.gitkeep new file mode 100644 index 0000000..e69de29