diff --git a/app/Console/Commands/FirmwareCheckCommand.php b/app/Console/Commands/FirmwareCheckCommand.php index 91922ba..f407314 100644 --- a/app/Console/Commands/FirmwareCheckCommand.php +++ b/app/Console/Commands/FirmwareCheckCommand.php @@ -23,7 +23,7 @@ class FirmwareCheckCommand extends Command ); $latestFirmware = Firmware::getLatest(); - if ($latestFirmware instanceof Firmware) { + if ($latestFirmware) { table( rows: [ ['Latest Version', $latestFirmware->version_tag], diff --git a/app/Console/Commands/FirmwareUpdateCommand.php b/app/Console/Commands/FirmwareUpdateCommand.php index bd43786..97d9d58 100644 --- a/app/Console/Commands/FirmwareUpdateCommand.php +++ b/app/Console/Commands/FirmwareUpdateCommand.php @@ -42,14 +42,15 @@ class FirmwareUpdateCommand extends Command label: 'Which devices should be updated?', options: [ 'all' => 'ALL Devices', - ...Device::all()->mapWithKeys(fn ($device): array => + ...Device::all()->mapWithKeys(function ($device) { // without _ returns index - ["_$device->id" => "$device->name (Current version: $device->last_firmware_version)"])->toArray(), + return ["_$device->id" => "$device->name (Current version: $device->last_firmware_version)"]; + })->toArray(), ], scroll: 10 ); - if ($devices === []) { + if (empty($devices)) { $this->error('No devices selected. Aborting.'); return; @@ -58,7 +59,9 @@ class FirmwareUpdateCommand extends Command if (in_array('all', $devices)) { $devices = Device::pluck('id')->toArray(); } else { - $devices = array_map(fn ($selected): int => (int) str_replace('_', '', $selected), $devices); + $devices = array_map(function ($selected) { + return (int) str_replace('_', '', $selected); + }, $devices); } foreach ($devices as $deviceId) { diff --git a/app/Console/Commands/MashupCreateCommand.php b/app/Console/Commands/MashupCreateCommand.php index 7201274..7020235 100644 --- a/app/Console/Commands/MashupCreateCommand.php +++ b/app/Console/Commands/MashupCreateCommand.php @@ -28,17 +28,17 @@ class MashupCreateCommand extends Command /** * Execute the console command. */ - public function handle(): int + public function handle() { // Select device $device = $this->selectDevice(); - if (! $device instanceof Device) { + if (! $device) { return 1; } // Select playlist $playlist = $this->selectPlaylist($device); - if (! $playlist instanceof Playlist) { + if (! $playlist) { return 1; } @@ -87,7 +87,7 @@ class MashupCreateCommand extends Command $deviceId = $this->choice( 'Select a device', - $devices->mapWithKeys(fn ($device): array => [$device->id => $device->name])->toArray() + $devices->mapWithKeys(fn ($device) => [$device->id => $device->name])->toArray() ); return $devices->firstWhere('id', $deviceId); @@ -105,7 +105,7 @@ class MashupCreateCommand extends Command $playlistId = $this->choice( 'Select a playlist', - $playlists->mapWithKeys(fn (Playlist $playlist): array => [$playlist->id => $playlist->name])->toArray() + $playlists->mapWithKeys(fn (Playlist $playlist) => [$playlist->id => $playlist->name])->toArray() ); return $playlists->firstWhere('id', $playlistId); @@ -123,13 +123,13 @@ class MashupCreateCommand extends Command { $name = $this->ask('Enter a name for this mashup', 'Mashup'); - if (mb_strlen((string) $name) < 2) { + if (mb_strlen($name) < 2) { $this->error('The name must be at least 2 characters.'); return null; } - if (mb_strlen((string) $name) > 50) { + if (mb_strlen($name) > 50) { $this->error('The name must not exceed 50 characters.'); return null; @@ -150,7 +150,7 @@ class MashupCreateCommand extends Command } $selectedPlugins = collect(); - $availablePlugins = $plugins->mapWithKeys(fn ($plugin): array => [$plugin->id => $plugin->name])->toArray(); + $availablePlugins = $plugins->mapWithKeys(fn ($plugin) => [$plugin->id => $plugin->name])->toArray(); for ($i = 0; $i < $requiredCount; ++$i) { $position = match ($i) { diff --git a/app/Console/Commands/OidcTestCommand.php b/app/Console/Commands/OidcTestCommand.php index 81dff0b..73321ce 100644 --- a/app/Console/Commands/OidcTestCommand.php +++ b/app/Console/Commands/OidcTestCommand.php @@ -26,7 +26,7 @@ class OidcTestCommand extends Command /** * Execute the console command. */ - public function handle(): int + public function handle() { $this->info('Testing OIDC Configuration...'); $this->newLine(); diff --git a/app/Console/Commands/ScreenGeneratorCommand.php b/app/Console/Commands/ScreenGeneratorCommand.php index c0a2cc3..ac74fba 100644 --- a/app/Console/Commands/ScreenGeneratorCommand.php +++ b/app/Console/Commands/ScreenGeneratorCommand.php @@ -25,7 +25,7 @@ class ScreenGeneratorCommand extends Command /** * Execute the console command. */ - public function handle(): int + public function handle() { $deviceId = $this->argument('deviceId'); $view = $this->argument('view'); diff --git a/app/Jobs/CleanupDeviceLogsJob.php b/app/Jobs/CleanupDeviceLogsJob.php index d2f1dd9..b49f507 100644 --- a/app/Jobs/CleanupDeviceLogsJob.php +++ b/app/Jobs/CleanupDeviceLogsJob.php @@ -18,7 +18,7 @@ class CleanupDeviceLogsJob implements ShouldQueue */ public function handle(): void { - Device::each(function ($device): void { + Device::each(function ($device) { $keepIds = $device->logs()->latest('device_timestamp')->take(50)->pluck('id'); // Delete all other logs for this device diff --git a/app/Jobs/FetchProxyCloudResponses.php b/app/Jobs/FetchProxyCloudResponses.php index ac23130..b560085 100644 --- a/app/Jobs/FetchProxyCloudResponses.php +++ b/app/Jobs/FetchProxyCloudResponses.php @@ -23,7 +23,7 @@ class FetchProxyCloudResponses implements ShouldQueue */ public function handle(): void { - Device::where('proxy_cloud', true)->each(function ($device): void { + Device::where('proxy_cloud', true)->each(function ($device) { if (! $device->getNextPlaylistItem()) { try { $response = Http::withHeaders([ diff --git a/app/Jobs/FirmwareDownloadJob.php b/app/Jobs/FirmwareDownloadJob.php index dfc851d..13352c3 100644 --- a/app/Jobs/FirmwareDownloadJob.php +++ b/app/Jobs/FirmwareDownloadJob.php @@ -18,7 +18,12 @@ class FirmwareDownloadJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(private Firmware $firmware) {} + private Firmware $firmware; + + public function __construct(Firmware $firmware) + { + $this->firmware = $firmware; + } public function handle(): void { diff --git a/app/Jobs/FirmwarePollJob.php b/app/Jobs/FirmwarePollJob.php index c1a2267..7110b9c 100644 --- a/app/Jobs/FirmwarePollJob.php +++ b/app/Jobs/FirmwarePollJob.php @@ -17,7 +17,12 @@ class FirmwarePollJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(private bool $download = false) {} + private bool $download; + + public function __construct(bool $download = false) + { + $this->download = $download; + } public function handle(): void { diff --git a/app/Jobs/NotifyDeviceBatteryLowJob.php b/app/Jobs/NotifyDeviceBatteryLowJob.php index 9b1001b..2508365 100644 --- a/app/Jobs/NotifyDeviceBatteryLowJob.php +++ b/app/Jobs/NotifyDeviceBatteryLowJob.php @@ -15,6 +15,8 @@ class NotifyDeviceBatteryLowJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + public function __construct() {} + public function handle(): void { $devices = Device::all(); @@ -30,11 +32,9 @@ class NotifyDeviceBatteryLowJob implements ShouldQueue continue; } + // Skip if battery is not low or notification was already sent - if ($batteryPercent > $batteryThreshold) { - continue; - } - if ($device->battery_notification_sent) { + if ($batteryPercent > $batteryThreshold || $device->battery_notification_sent) { continue; } diff --git a/app/Liquid/Filters/Data.php b/app/Liquid/Filters/Data.php index 3fb695a..2bbb5a9 100644 --- a/app/Liquid/Filters/Data.php +++ b/app/Liquid/Filters/Data.php @@ -72,7 +72,7 @@ class Data extends FiltersProvider */ public function sample(array $array): mixed { - if ($array === []) { + if (empty($array)) { return null; } diff --git a/app/Liquid/Filters/Numbers.php b/app/Liquid/Filters/Numbers.php index 0e31de1..53d1973 100644 --- a/app/Liquid/Filters/Numbers.php +++ b/app/Liquid/Filters/Numbers.php @@ -40,11 +40,15 @@ class Numbers extends FiltersProvider $currency = 'GBP'; } - $locale = $delimiter === '.' && $separator === ',' ? 'de' : 'en'; + if ($delimiter === '.' && $separator === ',') { + $locale = 'de'; + } else { + $locale = 'en'; + } // 2 decimal places for floats, 0 for integers $decimal = is_float($value + 0) ? 2 : 0; - return Number::currency($value, in: $currency, locale: $locale, precision: $decimal); + return Number::currency($value, in: $currency, precision: $decimal, locale: $locale); } } diff --git a/app/Liquid/Filters/Uniqueness.php b/app/Liquid/Filters/Uniqueness.php index 35378b3..89148c4 100644 --- a/app/Liquid/Filters/Uniqueness.php +++ b/app/Liquid/Filters/Uniqueness.php @@ -35,7 +35,7 @@ class Uniqueness extends FiltersProvider $randomString = ''; for ($i = 0; $i < $length; ++$i) { - $randomString .= $characters[random_int(0, mb_strlen($characters) - 1)]; + $randomString .= $characters[rand(0, mb_strlen($characters) - 1)]; } return $randomString; diff --git a/app/Livewire/Actions/DeviceAutoJoin.php b/app/Livewire/Actions/DeviceAutoJoin.php index 183add4..c16322c 100644 --- a/app/Livewire/Actions/DeviceAutoJoin.php +++ b/app/Livewire/Actions/DeviceAutoJoin.php @@ -10,14 +10,14 @@ class DeviceAutoJoin extends Component public bool $isFirstUser = false; - public function mount(): void + public function mount() { $this->deviceAutojoin = auth()->user()->assign_new_devices; $this->isFirstUser = auth()->user()->id === 1; } - public function updating($name, $value): void + public function updating($name, $value) { $this->validate([ 'deviceAutojoin' => 'boolean', @@ -30,7 +30,7 @@ class DeviceAutoJoin extends Component } } - public function render(): \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory + public function render() { return view('livewire.actions.device-auto-join'); } diff --git a/app/Livewire/Actions/Logout.php b/app/Livewire/Actions/Logout.php index c26fa72..45993bb 100644 --- a/app/Livewire/Actions/Logout.php +++ b/app/Livewire/Actions/Logout.php @@ -10,7 +10,7 @@ class Logout /** * Log the current user out of the application. */ - public function __invoke(): \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse + public function __invoke() { Auth::guard('web')->logout(); diff --git a/app/Livewire/DeviceDashboard.php b/app/Livewire/DeviceDashboard.php index a2a3692..78309cb 100644 --- a/app/Livewire/DeviceDashboard.php +++ b/app/Livewire/DeviceDashboard.php @@ -6,7 +6,7 @@ use Livewire\Component; class DeviceDashboard extends Component { - public function render(): \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory + public function render() { return view('livewire.device-dashboard', ['devices' => auth()->user()->devices()->paginate(10)]); } diff --git a/app/Models/Device.php b/app/Models/Device.php index 6a99fcd..5001a22 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -10,9 +10,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Facades\Storage; -/** - * @property-read DeviceModel|null $deviceModel - */ class Device extends Model { use HasFactory; @@ -35,7 +32,7 @@ class Device extends Model 'pause_until' => 'datetime', ]; - public function getBatteryPercentAttribute(): int|float + public function getBatteryPercentAttribute() { $volts = $this->last_battery_voltage; @@ -83,7 +80,7 @@ class Device extends Model return round($voltage, 2); } - public function getWifiStrengthAttribute(): int + public function getWifiStrengthAttribute() { $rssi = $this->last_rssi_level; if ($rssi >= 0) { @@ -106,7 +103,11 @@ class Device extends Model return true; } - return $this->proxy_cloud_response && $this->proxy_cloud_response['update_firmware']; + if ($this->proxy_cloud_response && $this->proxy_cloud_response['update_firmware']) { + return true; + } + + return false; } public function getFirmwareUrlAttribute(): ?string @@ -187,30 +188,6 @@ class Device extends Model return $this->belongsTo(DeviceModel::class); } - /** - * Get the color depth string (e.g., "4bit") for the associated device model. - */ - public function colorDepth(): ?string - { - return $this->deviceModel?->color_depth; - } - - /** - * Get the scale level (e.g., large/xlarge/xxlarge) for the associated device model. - */ - public function scaleLevel(): ?string - { - return $this->deviceModel?->scale_level; - } - - /** - * Get the device variant name, defaulting to 'og' if not available. - */ - public function deviceVariant(): string - { - return $this->deviceModel->name ?? 'og'; - } - public function logs(): HasMany { return $this->hasMany(DeviceLog::class); @@ -227,7 +204,7 @@ class Device extends Model return false; } - $now = $now instanceof DateTimeInterface ? Carbon::instance($now) : now(); + $now = $now ? Carbon::instance($now) : now(); // Handle overnight ranges (e.g. 22:00 to 06:00) return $this->sleep_mode_from < $this->sleep_mode_to @@ -241,7 +218,7 @@ class Device extends Model return null; } - $now = $now instanceof DateTimeInterface ? Carbon::instance($now) : now(); + $now = $now ? Carbon::instance($now) : now(); $from = $this->sleep_mode_from; $to = $this->sleep_mode_to; diff --git a/app/Models/Playlist.php b/app/Models/Playlist.php index 7b55a73..d20798c 100644 --- a/app/Models/Playlist.php +++ b/app/Models/Playlist.php @@ -38,8 +38,10 @@ class Playlist extends Model } // Check weekday - if ($this->weekdays !== null && ! in_array(now()->dayOfWeek, $this->weekdays)) { - return false; + if ($this->weekdays !== null) { + if (! in_array(now()->dayOfWeek, $this->weekdays)) { + return false; + } } if ($this->active_from !== null && $this->active_until !== null) { @@ -51,8 +53,10 @@ class Playlist extends Model if ($now >= $this->active_from || $now <= $this->active_until) { return true; } - } elseif ($now >= $this->active_from && $now <= $this->active_until) { - return true; + } else { + if ($now >= $this->active_from && $now <= $this->active_until) { + return true; + } } return false; diff --git a/app/Models/PlaylistItem.php b/app/Models/PlaylistItem.php index ad11f1d..28f6454 100644 --- a/app/Models/PlaylistItem.php +++ b/app/Models/PlaylistItem.php @@ -139,9 +139,9 @@ class PlaylistItem extends Model { if (! $this->isMashup()) { return view('trmnl-layouts.single', [ - 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceVariant() ?? 'og', - 'scaleLevel' => $device?->scaleLevel(), + 'colorDepth' => $device?->deviceModel?->color_depth, + 'deviceVariant' => $device?->deviceModel->name ?? 'og', + 'scaleLevel' => $device?->deviceModel?->scale_level, 'slot' => $this->plugin instanceof Plugin ? $this->plugin->render('full', false) : throw new Exception('Invalid plugin instance'), @@ -153,7 +153,9 @@ class PlaylistItem extends Model $plugins = Plugin::whereIn('id', $pluginIds)->get(); // Sort the collection to match plugin_ids order - $plugins = $plugins->sortBy(fn ($plugin): int|string|false => array_search($plugin->id, $pluginIds))->values(); + $plugins = $plugins->sortBy(function ($plugin) use ($pluginIds) { + return array_search($plugin->id, $pluginIds); + })->values(); foreach ($plugins as $index => $plugin) { $size = $this->getLayoutSize($index); @@ -161,9 +163,9 @@ class PlaylistItem extends Model } return view('trmnl-layouts.mashup', [ - 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceVariant() ?? 'og', - 'scaleLevel' => $device?->scaleLevel(), + 'colorDepth' => $device?->deviceModel?->color_depth, + 'deviceVariant' => $device?->deviceModel->name ?? 'og', + 'scaleLevel' => $device?->deviceModel?->scale_level, 'mashupLayout' => $this->getMashupLayoutType(), 'slot' => implode('', $pluginMarkups), ])->render(); diff --git a/app/Models/Plugin.php b/app/Models/Plugin.php index 2fd3718..f5f6928 100644 --- a/app/Models/Plugin.php +++ b/app/Models/Plugin.php @@ -42,7 +42,7 @@ class Plugin extends Model { parent::boot(); - static::creating(function ($model): void { + static::creating(function ($model) { if (empty($model->uuid)) { $model->uuid = Str::uuid(); } @@ -83,7 +83,7 @@ class Plugin extends Model $currentValue = $this->configuration[$fieldKey] ?? null; // If the field has a default value and no current value is set, it's not missing - if (($currentValue === null || $currentValue === '' || ($currentValue === [])) && ! isset($field['default'])) { + if (($currentValue === null || $currentValue === '' || (is_array($currentValue) && empty($currentValue))) && ! isset($field['default'])) { return true; // Found a required field that is not set and has no default } } @@ -126,7 +126,7 @@ class Plugin extends Model // Split URLs by newline and filter out empty lines $urls = array_filter( array_map('trim', explode("\n", $this->polling_url)), - fn ($url): bool => ! empty($url) + fn ($url) => ! empty($url) ); // If only one URL, use the original logic without nesting @@ -237,7 +237,7 @@ class Plugin extends Model // Converts to: {% assign temp_filtered = collection | filter: "key", "value" %}{% for item in temp_filtered %} $template = preg_replace_callback( '/{%\s*for\s+(\w+)\s+in\s+([^|%}]+)\s*\|\s*([^%}]+)%}/', - function ($matches): string { + function ($matches) { $variableName = mb_trim($matches[1]); $collection = mb_trim($matches[2]); $filter = mb_trim($matches[3]); @@ -245,7 +245,7 @@ class Plugin extends Model return "{% assign {$tempVarName} = {$collection} | {$filter} %}{% for {$variableName} in {$tempVarName} %}"; }, - (string) $template + $template ); return $template; @@ -345,18 +345,18 @@ class Plugin extends Model if ($standalone) { if ($size === 'full') { return view('trmnl-layouts.single', [ - 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceVariant() ?? 'og', - 'scaleLevel' => $device?->scaleLevel(), + 'colorDepth' => $device?->deviceModel?->color_depth, + 'deviceVariant' => $device?->deviceModel->name ?? 'og', + 'scaleLevel' => $device?->deviceModel?->scale_level, 'slot' => $renderedContent, ])->render(); } return view('trmnl-layouts.mashup', [ 'mashupLayout' => $this->getPreviewMashupLayoutForSize($size), - 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceVariant() ?? 'og', - 'scaleLevel' => $device?->scaleLevel(), + 'colorDepth' => $device?->deviceModel?->color_depth, + 'deviceVariant' => $device?->deviceModel->name ?? 'og', + 'scaleLevel' => $device?->deviceModel?->scale_level, 'slot' => $renderedContent, ])->render(); @@ -368,9 +368,9 @@ class Plugin extends Model if ($this->render_markup_view) { if ($standalone) { return view('trmnl-layouts.single', [ - 'colorDepth' => $device?->colorDepth(), - 'deviceVariant' => $device?->deviceVariant() ?? 'og', - 'scaleLevel' => $device?->scaleLevel(), + 'colorDepth' => $device?->deviceModel?->color_depth, + 'deviceVariant' => $device?->deviceModel->name ?? 'og', + 'scaleLevel' => $device?->deviceModel?->scale_level, 'slot' => view($this->render_markup_view, [ 'size' => $size, 'data' => $this->data_payload, diff --git a/app/Notifications/BatteryLow.php b/app/Notifications/BatteryLow.php index 09a5755..c76c87f 100644 --- a/app/Notifications/BatteryLow.php +++ b/app/Notifications/BatteryLow.php @@ -13,10 +13,15 @@ class BatteryLow extends Notification { use Queueable; + private Device $device; + /** * Create a new notification instance. */ - public function __construct(private Device $device) {} + public function __construct(Device $device) + { + $this->device = $device; + } /** * Get the notification's delivery channels. diff --git a/app/Notifications/Channels/WebhookChannel.php b/app/Notifications/Channels/WebhookChannel.php index 796cb24..d116200 100644 --- a/app/Notifications/Channels/WebhookChannel.php +++ b/app/Notifications/Channels/WebhookChannel.php @@ -11,7 +11,13 @@ use Illuminate\Support\Arr; class WebhookChannel extends Notification { - public function __construct(protected Client $client) {} + /** @var Client */ + protected $client; + + public function __construct(Client $client) + { + $this->client = $client; + } /** * Send the given notification. diff --git a/app/Notifications/Messages/WebhookMessage.php b/app/Notifications/Messages/WebhookMessage.php index 6dc58eb..920c16d 100644 --- a/app/Notifications/Messages/WebhookMessage.php +++ b/app/Notifications/Messages/WebhookMessage.php @@ -13,6 +13,13 @@ final class WebhookMessage extends Notification */ private $query; + /** + * The POST data of the Webhook request. + * + * @var mixed + */ + private $data; + /** * The headers to send with the request. * @@ -29,8 +36,9 @@ final class WebhookMessage extends Notification /** * @param mixed $data + * @return static */ - public static function create($data = ''): self + public static function create($data = '') { return new self($data); } @@ -38,12 +46,10 @@ final class WebhookMessage extends Notification /** * @param mixed $data */ - public function __construct( - /** - * The POST data of the Webhook request. - */ - private $data = '' - ) {} + public function __construct($data = '') + { + $this->data = $data; + } /** * Set the Webhook parameters to be URL encoded. @@ -51,7 +57,7 @@ final class WebhookMessage extends Notification * @param mixed $query * @return $this */ - public function query($query): self + public function query($query) { $this->query = $query; @@ -64,7 +70,7 @@ final class WebhookMessage extends Notification * @param mixed $data * @return $this */ - public function data($data): self + public function data($data) { $this->data = $data; @@ -78,7 +84,7 @@ final class WebhookMessage extends Notification * @param string $value * @return $this */ - public function header($name, $value): self + public function header($name, $value) { $this->headers[$name] = $value; @@ -91,7 +97,7 @@ final class WebhookMessage extends Notification * @param string $userAgent * @return $this */ - public function userAgent($userAgent): self + public function userAgent($userAgent) { $this->headers['User-Agent'] = $userAgent; @@ -103,14 +109,17 @@ final class WebhookMessage extends Notification * * @return $this */ - public function verify($value = true): self + public function verify($value = true) { $this->verify = $value; return $this; } - public function toArray(): array + /** + * @return array + */ + public function toArray() { return [ 'query' => $this->query, diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index b8ad9bb..b7deb3b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -33,19 +33,17 @@ class AppServiceProvider extends ServiceProvider $http = clone $this; $http->server->set('HTTPS', 'off'); - if (URL::hasValidSignature($https, $absolute, $ignoreQuery)) { - return true; - } - return URL::hasValidSignature($http, $absolute, $ignoreQuery); + return URL::hasValidSignature($https, $absolute, $ignoreQuery) + || URL::hasValidSignature($http, $absolute, $ignoreQuery); }); // Register OIDC provider with Socialite - Socialite::extend('oidc', function (\Illuminate\Contracts\Foundation\Application $app): OidcProvider { - $config = $app->make('config')->get('services.oidc', []); + Socialite::extend('oidc', function ($app) { + $config = $app['config']['services.oidc'] ?? []; return new OidcProvider( - $app->make(Request::class), + $app['request'], $config['client_id'] ?? null, $config['client_secret'] ?? null, $config['redirect'] ?? null, diff --git a/app/Services/ImageGenerationService.php b/app/Services/ImageGenerationService.php index 36597d7..762d449 100644 --- a/app/Services/ImageGenerationService.php +++ b/app/Services/ImageGenerationService.php @@ -233,14 +233,14 @@ class ImageGenerationService if ($plugin?->id) { // Check if any devices have custom dimensions or use non-standard DeviceModels $hasCustomDimensions = Device::query() - ->where(function ($query): void { + ->where(function ($query) { $query->where('width', '!=', 800) ->orWhere('height', '!=', 480) ->orWhere('rotate', '!=', 0); }) - ->orWhereHas('deviceModel', function ($query): void { + ->orWhereHas('deviceModel', function ($query) { // Only allow caching if all device models have standard dimensions (800x480, rotation=0) - $query->where(function ($subQuery): void { + $query->where(function ($subQuery) { $subQuery->where('width', '!=', 800) ->orWhere('height', '!=', 480) ->orWhere('rotation', '!=', 0); diff --git a/app/Services/OidcProvider.php b/app/Services/OidcProvider.php index 8ea2e44..74143f1 100644 --- a/app/Services/OidcProvider.php +++ b/app/Services/OidcProvider.php @@ -33,7 +33,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface /** * Create a new provider instance. */ - public function __construct(\Illuminate\Http\Request $request, $clientId, $clientSecret, $redirectUrl, $scopes = [], $guzzle = []) + public function __construct($request, $clientId, $clientSecret, $redirectUrl, $scopes = [], $guzzle = []) { parent::__construct($request, $clientId, $clientSecret, $redirectUrl, $guzzle); @@ -43,7 +43,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface } // Handle both full well-known URL and base URL - if (str_ends_with((string) $endpoint, '/.well-known/openid-configuration')) { + if (str_ends_with($endpoint, '/.well-known/openid-configuration')) { $this->baseUrl = str_replace('/.well-known/openid-configuration', '', $endpoint); } else { $this->baseUrl = mb_rtrim($endpoint, '/'); @@ -73,7 +73,7 @@ class OidcProvider extends AbstractProvider implements ProviderInterface } } catch (Exception $e) { - throw new Exception('Failed to load OIDC configuration: '.$e->getMessage(), $e->getCode(), $e); + throw new Exception('Failed to load OIDC configuration: '.$e->getMessage()); } } diff --git a/app/Services/PluginExportService.php b/app/Services/PluginExportService.php index 4cd246d..9f08d76 100644 --- a/app/Services/PluginExportService.php +++ b/app/Services/PluginExportService.php @@ -47,33 +47,44 @@ class PluginExportService $tempDirName = 'temp/'.uniqid('plugin_export_', true); Storage::makeDirectory($tempDirName); $tempDir = Storage::path($tempDirName); - // Generate settings.yml content - $settings = $this->generateSettingsYaml($plugin); - $settingsYaml = Yaml::dump($settings, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); - File::put($tempDir.'/settings.yml', $settingsYaml); - // Generate full template content - $fullTemplate = $this->generateFullTemplate($plugin); - $extension = $plugin->markup_language === 'liquid' ? 'liquid' : 'blade.php'; - File::put($tempDir.'/full.'.$extension, $fullTemplate); - // Generate shared.liquid if needed (for liquid templates) - if ($plugin->markup_language === 'liquid') { - $sharedTemplate = $this->generateSharedTemplate(); - if ($sharedTemplate) { - File::put($tempDir.'/shared.liquid', $sharedTemplate); - } - } - // Create ZIP file - $zipPath = $tempDir.'/plugin_'.$plugin->trmnlp_id.'.zip'; - $zip = new ZipArchive(); - if ($zip->open($zipPath, ZipArchive::CREATE) !== true) { - throw new Exception('Could not create ZIP file.'); - } - // Add files directly to ZIP root - $this->addDirectoryToZip($zip, $tempDir, ''); - $zip->close(); - // Return the ZIP file as a download response - return response()->download($zipPath, 'plugin_'.$plugin->trmnlp_id.'.zip'); + try { + // Generate settings.yml content + $settings = $this->generateSettingsYaml($plugin); + $settingsYaml = Yaml::dump($settings, 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); + File::put($tempDir.'/settings.yml', $settingsYaml); + + // Generate full template content + $fullTemplate = $this->generateFullTemplate($plugin); + $extension = $plugin->markup_language === 'liquid' ? 'liquid' : 'blade.php'; + File::put($tempDir.'/full.'.$extension, $fullTemplate); + + // Generate shared.liquid if needed (for liquid templates) + if ($plugin->markup_language === 'liquid') { + $sharedTemplate = $this->generateSharedTemplate($plugin); + if ($sharedTemplate) { + File::put($tempDir.'/shared.liquid', $sharedTemplate); + } + } + + // Create ZIP file + $zipPath = $tempDir.'/plugin_'.$plugin->trmnlp_id.'.zip'; + $zip = new ZipArchive(); + + if ($zip->open($zipPath, ZipArchive::CREATE) !== true) { + throw new Exception('Could not create ZIP file.'); + } + + // Add files directly to ZIP root + $this->addDirectoryToZip($zip, $tempDir, ''); + $zip->close(); + + // Return the ZIP file as a download response + return response()->download($zipPath, 'plugin_'.$plugin->trmnlp_id.'.zip'); + + } catch (Exception $e) { + throw $e; + } } /** @@ -139,7 +150,7 @@ class PluginExportService /** * Generate the shared template content (for liquid templates) */ - private function generateSharedTemplate(): null + private function generateSharedTemplate(Plugin $plugin) { // For now, we don't have a way to store shared templates separately // TODO - add support for shared templates @@ -159,10 +170,14 @@ class PluginExportService foreach ($files as $file) { if (! $file->isDir()) { $filePath = $file->getRealPath(); - $fileName = basename((string) $filePath); + $fileName = basename($filePath); // For root directory, just use the filename - $relativePath = $zipPath === '' ? $fileName : $zipPath.'/'.mb_substr((string) $filePath, mb_strlen($dirPath) + 1); + if ($zipPath === '') { + $relativePath = $fileName; + } else { + $relativePath = $zipPath.'/'.mb_substr($filePath, mb_strlen($dirPath) + 1); + } $zip->addFile($filePath, $relativePath); } diff --git a/app/Services/PluginImportService.php b/app/Services/PluginImportService.php index 5cc928b..e824f35 100644 --- a/app/Services/PluginImportService.php +++ b/app/Services/PluginImportService.php @@ -72,7 +72,7 @@ class PluginImportService // Check if the file ends with .liquid to set markup language $markupLanguage = 'blade'; - if (pathinfo((string) $filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') { + if (pathinfo($filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') { $markupLanguage = 'liquid'; } @@ -197,7 +197,7 @@ class PluginImportService // Check if the file ends with .liquid to set markup language $markupLanguage = 'blade'; - if (pathinfo((string) $filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') { + if (pathinfo($filePaths['fullLiquidPath'], PATHINFO_EXTENSION) === 'liquid') { $markupLanguage = 'liquid'; } @@ -352,7 +352,7 @@ class PluginImportService // check if they're in the root of the ZIP or in a subfolder if ($settingsYamlPath && $fullLiquidPath) { // If the files are in the root of the ZIP, create a src folder and move them there - $srcDir = dirname((string) $settingsYamlPath); + $srcDir = dirname($settingsYamlPath); // If the parent directory is not named 'src', create a src directory if (basename($srcDir) !== 'src') { diff --git a/composer.json b/composer.json index 8f3079d..e3cbb13 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "ext-imagick": "*", "ext-zip": "*", "bnussbau/laravel-trmnl-blade": "2.0.*", - "bnussbau/trmnl-pipeline-php": "^0.3.0", + "bnussbau/trmnl-pipeline-php": "^0.2.0", "keepsuit/laravel-liquid": "^0.5.2", "laravel/framework": "^12.1", "laravel/sanctum": "^4.0", @@ -37,8 +37,7 @@ "nunomaduro/collision": "^8.6", "pestphp/pest": "^4.0", "pestphp/pest-plugin-drift": "^4.0", - "pestphp/pest-plugin-laravel": "^4.0", - "rector/rector": "^2.1" + "pestphp/pest-plugin-laravel": "^4.0" }, "autoload": { "psr-4": { @@ -76,8 +75,7 @@ "test-coverage": "vendor/bin/pest --coverage", "format": "vendor/bin/pint", "analyse": "vendor/bin/phpstan analyse", - "analyze": "vendor/bin/phpstan analyse", - "rector": "vendor/bin/rector process" + "analyze": "vendor/bin/phpstan analyse" }, "extra": { "laravel": { diff --git a/composer.lock b/composer.lock index 09facfa..5a3c004 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9122624c0df3b24bc94c7c866aa4e17c", + "content-hash": "f8f7d3fd0eba117ddeb5463047ac5493", "packages": [ { "name": "aws/aws-crt-php", @@ -243,16 +243,16 @@ }, { "name": "bnussbau/trmnl-pipeline-php", - "version": "0.3.0", + "version": "0.2.0", "source": { "type": "git", "url": "https://github.com/bnussbau/trmnl-pipeline-php.git", - "reference": "89ceac9e0f35bdee591dfddd7b048aff1218bb6e" + "reference": "0a85e4c935a7009c469c014c6b7f2d9783d82523" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bnussbau/trmnl-pipeline-php/zipball/89ceac9e0f35bdee591dfddd7b048aff1218bb6e", - "reference": "89ceac9e0f35bdee591dfddd7b048aff1218bb6e", + "url": "https://api.github.com/repos/bnussbau/trmnl-pipeline-php/zipball/0a85e4c935a7009c469c014c6b7f2d9783d82523", + "reference": "0a85e4c935a7009c469c014c6b7f2d9783d82523", "shasum": "" }, "require": { @@ -294,7 +294,7 @@ ], "support": { "issues": "https://github.com/bnussbau/trmnl-pipeline-php/issues", - "source": "https://github.com/bnussbau/trmnl-pipeline-php/tree/0.3.0" + "source": "https://github.com/bnussbau/trmnl-pipeline-php/tree/0.2.0" }, "funding": [ { @@ -310,7 +310,7 @@ "type": "github" } ], - "time": "2025-09-24T16:29:38+00:00" + "time": "2025-09-18T16:40:28+00:00" }, { "name": "brick/math", @@ -10546,66 +10546,6 @@ ], "time": "2025-09-03T06:25:17+00:00" }, - { - "name": "rector/rector", - "version": "2.1.7", - "source": { - "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "c34cc07c4698f007a20dc5c99ff820089ae413ce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/c34cc07c4698f007a20dc5c99ff820089ae413ce", - "reference": "c34cc07c4698f007a20dc5c99ff820089ae413ce", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0", - "phpstan/phpstan": "^2.1.18" - }, - "conflict": { - "rector/rector-doctrine": "*", - "rector/rector-downgrade-php": "*", - "rector/rector-phpunit": "*", - "rector/rector-symfony": "*" - }, - "suggest": { - "ext-dom": "To manipulate phpunit.xml via the custom-rule command" - }, - "bin": [ - "bin/rector" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Instant Upgrade and Automated Refactoring of any PHP code", - "homepage": "https://getrector.com/", - "keywords": [ - "automation", - "dev", - "migration", - "refactoring" - ], - "support": { - "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/2.1.7" - }, - "funding": [ - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2025-09-10T11:13:58+00:00" - }, { "name": "sebastian/cli-parser", "version": "4.2.0", diff --git a/rector.php b/rector.php deleted file mode 100644 index dde2f14..0000000 --- a/rector.php +++ /dev/null @@ -1,26 +0,0 @@ -paths([ - __DIR__.'/app', - __DIR__.'/tests', - ]); - - $rectorConfig->sets([ - LevelSetList::UP_TO_PHP_82, - SetList::CODE_QUALITY, - SetList::DEAD_CODE, - SetList::EARLY_RETURN, - SetList::TYPE_DECLARATION, - ]); - - $rectorConfig->skip([ - // Skip any specific rules if needed - ]); -}; diff --git a/resources/views/livewire/devices/configure.blade.php b/resources/views/livewire/devices/configure.blade.php index 30b4481..44e424c 100644 --- a/resources/views/livewire/devices/configure.blade.php +++ b/resources/views/livewire/devices/configure.blade.php @@ -383,6 +383,7 @@ new class extends Component { Edit TRMNL + makeDirectory('/images/generated'); }); -test('device can fetch display data with valid credentials', function (): void { +test('device can fetch display data with valid credentials', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -52,7 +50,7 @@ test('device can fetch display data with valid credentials', function (): void { ->last_firmware_version->toBe('1.0.0'); }); -test('display endpoint includes image_url_timeout when configured', function (): void { +test('display endpoint includes image_url_timeout when configured', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -74,7 +72,7 @@ test('display endpoint includes image_url_timeout when configured', function (): ]); }); -test('display endpoint omits image_url_timeout when not configured', function (): void { +test('display endpoint omits image_url_timeout when not configured', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -94,7 +92,7 @@ test('display endpoint omits image_url_timeout when not configured', function () ->assertJsonMissing(['image_url_timeout']); }); -test('new device is auto-assigned to user with auto-assign enabled', function (): void { +test('new device is auto-assigned to user with auto-assign enabled', function () { $user = User::factory()->create(['assign_new_devices' => true]); $response = $this->withHeaders([ @@ -114,7 +112,7 @@ test('new device is auto-assigned to user with auto-assign enabled', function () ->api_key->toBe('new-device-key'); }); -test('new device is auto-assigned and mirrors specified device', function (): void { +test('new device is auto-assigned and mirrors specified device', function () { // Create a source device that will be mirrored $sourceDevice = Device::factory()->create([ 'mac_address' => 'AA:BB:CC:DD:EE:FF', @@ -153,7 +151,7 @@ test('new device is auto-assigned and mirrors specified device', function (): vo ]); }); -test('device setup endpoint returns correct data', function (): void { +test('device setup endpoint returns correct data', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -172,7 +170,7 @@ test('device setup endpoint returns correct data', function (): void { ]); }); -test('device can submit logs', function (): void { +test('device can submit logs', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -200,7 +198,7 @@ test('device can submit logs', function (): void { expect($device->logs()->count())->toBe(1); }); -test('device can submit logs in revised format', function (): void { +test('device can submit logs in revised format', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -240,7 +238,7 @@ test('device can submit logs in revised format', function (): void { // $response->assertOk(); // }); -test('user cannot update display for devices they do not own', function (): void { +test('user cannot update display for devices they do not own', function () { $user = User::factory()->create(); $otherUser = User::factory()->create(); $device = Device::factory()->create(['user_id' => $otherUser->id]); @@ -255,7 +253,7 @@ test('user cannot update display for devices they do not own', function (): void $response->assertForbidden(); }); -test('invalid device credentials return error', function (): void { +test('invalid device credentials return error', function () { $response = $this->withHeaders([ 'id' => 'invalid-mac', 'access-token' => 'invalid-token', @@ -265,7 +263,7 @@ test('invalid device credentials return error', function (): void { ->assertJson(['message' => 'MAC Address not registered or invalid access token']); }); -test('log endpoint requires valid device credentials', function (): void { +test('log endpoint requires valid device credentials', function () { $response = $this->withHeaders([ 'id' => 'invalid-mac', 'access-token' => 'invalid-token', @@ -275,7 +273,7 @@ test('log endpoint requires valid device credentials', function (): void { ->assertJson(['message' => 'Device not found or invalid access token']); }); -test('update_firmware flag is only returned once', function (): void { +test('update_firmware flag is only returned once', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -320,7 +318,7 @@ test('update_firmware flag is only returned once', function (): void { expect($device->proxy_cloud_response['update_firmware'])->toBeFalse(); }); -test('authenticated user can fetch device status', function (): void { +test('authenticated user can fetch device status', function () { $user = User::factory()->create(); $device = Device::factory()->create([ 'user_id' => $user->id, @@ -354,7 +352,7 @@ test('authenticated user can fetch device status', function (): void { ]); }); -test('user cannot fetch status for devices they do not own', function (): void { +test('user cannot fetch status for devices they do not own', function () { $user = User::factory()->create(); $otherUser = User::factory()->create(); $device = Device::factory()->create(['user_id' => $otherUser->id]); @@ -366,7 +364,7 @@ test('user cannot fetch status for devices they do not own', function (): void { $response->assertForbidden(); }); -test('display status endpoint requires device_id parameter', function (): void { +test('display status endpoint requires device_id parameter', function () { $user = User::factory()->create(); Sanctum::actingAs($user); @@ -376,7 +374,7 @@ test('display status endpoint requires device_id parameter', function (): void { ->assertJsonValidationErrors(['device_id']); }); -test('display status endpoint requires valid device_id', function (): void { +test('display status endpoint requires valid device_id', function () { $user = User::factory()->create(); Sanctum::actingAs($user); @@ -386,7 +384,7 @@ test('display status endpoint requires valid device_id', function (): void { ->assertJsonValidationErrors(['device_id']); }); -test('device can mirror another device', function (): void { +test('device can mirror another device', function () { // Create source device with a playlist and image $sourceDevice = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', @@ -428,7 +426,7 @@ test('device can mirror another device', function (): void { ->last_firmware_version->toBe('1.0.0'); }); -test('device can fetch current screen data', function (): void { +test('device can fetch current screen data', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -451,7 +449,7 @@ test('device can fetch current screen data', function (): void { ]); }); -test('current_screen endpoint requires valid device credentials', function (): void { +test('current_screen endpoint requires valid device credentials', function () { $response = $this->withHeaders([ 'access-token' => 'invalid-token', ])->get('/api/current_screen'); @@ -460,7 +458,7 @@ test('current_screen endpoint requires valid device credentials', function (): v ->assertJson(['message' => 'Device not found or invalid access token']); }); -test('authenticated user can fetch their devices', function (): void { +test('authenticated user can fetch their devices', function () { $user = User::factory()->create(); $devices = Device::factory()->count(2)->create([ 'user_id' => $user->id, @@ -502,7 +500,7 @@ test('authenticated user can fetch their devices', function (): void { ]); }); -test('plugin caches image until data is stale', function (): void { +test('plugin caches image until data is stale', function () { // Create source device with a playlist $device = Device::factory()->create([ 'mac_address' => '55:11:22:33:44:55', @@ -575,9 +573,9 @@ test('plugin caches image until data is stale', function (): void { expect($thirdResponse['filename']) ->not->toBe($firstResponse['filename']); -}); +})->skipOnCi(); -test('plugins in playlist are rendered in order', function (): void { +test('plugins in playlist are rendered in order', function () { // Create source device with a playlist $device = Device::factory()->create([ 'mac_address' => '55:11:22:33:44:55', @@ -679,9 +677,9 @@ test('plugins in playlist are rendered in order', function (): void { $thirdResponse->assertOk(); expect($thirdResponse['filename']) ->not->toBe($secondResponse['filename']); -}); +})->skipOnCi(); -test('display endpoint updates last_refreshed_at timestamp', function (): void { +test('display endpoint updates last_refreshed_at timestamp', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -702,7 +700,7 @@ test('display endpoint updates last_refreshed_at timestamp', function (): void { ->and($device->last_refreshed_at->diffInSeconds(now()))->toBeLessThan(2); }); -test('display endpoint updates last_refreshed_at timestamp for mirrored devices', function (): void { +test('display endpoint updates last_refreshed_at timestamp for mirrored devices', function () { // Create source device $sourceDevice = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', @@ -731,7 +729,7 @@ test('display endpoint updates last_refreshed_at timestamp for mirrored devices' ->and($mirrorDevice->last_refreshed_at->diffInSeconds(now()))->toBeLessThan(2); }); -test('display endpoint handles mashup playlist items correctly', function (): void { +test('display endpoint handles mashup playlist items correctly', function () { // Create a device $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', @@ -789,9 +787,9 @@ test('display endpoint handles mashup playlist items correctly', function (): vo // Verify the playlist item was marked as displayed $playlistItem->refresh(); expect($playlistItem->last_displayed_at)->not->toBeNull(); -}); +})->skipOnCi(); -test('device in sleep mode returns sleep image and correct refresh rate', function (): void { +test('device in sleep mode returns sleep image and correct refresh rate', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -821,7 +819,7 @@ test('device in sleep mode returns sleep image and correct refresh rate', functi Carbon\Carbon::setTestNow(); // Clear test time }); -test('device not in sleep mode returns normal image', function (): void { +test('device not in sleep mode returns normal image', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -850,7 +848,7 @@ test('device not in sleep mode returns normal image', function (): void { Carbon\Carbon::setTestNow(); // Clear test time }); -test('device returns sleep.png and correct refresh time when paused', function (): void { +test('device returns sleep.png and correct refresh time when paused', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -872,7 +870,7 @@ test('device returns sleep.png and correct refresh time when paused', function ( expect($json['refresh_rate'])->toBeLessThanOrEqual(3600); // ~60 min }); -test('screens endpoint accepts nullable file_name', function (): void { +test('screens endpoint accepts nullable file_name', function () { Queue::fake(); $device = Device::factory()->create([ @@ -894,7 +892,7 @@ test('screens endpoint accepts nullable file_name', function (): void { Queue::assertPushed(GenerateScreenJob::class); }); -test('screens endpoint returns 404 for invalid device credentials', function (): void { +test('screens endpoint returns 404 for invalid device credentials', function () { $response = $this->withHeaders([ 'id' => 'invalid-mac', 'access-token' => 'invalid-key', @@ -911,7 +909,7 @@ test('screens endpoint returns 404 for invalid device credentials', function (): ]); }); -test('setup endpoint assigns device model when model-id header is provided', function (): void { +test('setup endpoint assigns device model when model-id header is provided', function () { $user = User::factory()->create(['assign_new_devices' => true]); $deviceModel = DeviceModel::factory()->create([ 'name' => 'test-model', @@ -934,7 +932,7 @@ test('setup endpoint assigns device model when model-id header is provided', fun ->and($device->device_model_id)->toBe($deviceModel->id); }); -test('setup endpoint handles non-existent device model gracefully', function (): void { +test('setup endpoint handles non-existent device model gracefully', function () { $user = User::factory()->create(['assign_new_devices' => true]); $response = $this->withHeaders([ diff --git a/tests/Feature/Api/DeviceImageFormatTest.php b/tests/Feature/Api/DeviceImageFormatTest.php index a7db928..fcb7555 100644 --- a/tests/Feature/Api/DeviceImageFormatTest.php +++ b/tests/Feature/Api/DeviceImageFormatTest.php @@ -10,12 +10,12 @@ use Illuminate\Support\Facades\Storage; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -beforeEach(function (): void { +beforeEach(function () { Storage::fake('public'); Storage::disk('public')->makeDirectory('/images/generated'); }); -test('device with firmware version 1.5.1 gets bmp format', function (): void { +test('device with firmware version 1.5.1 gets bmp format', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -52,7 +52,7 @@ test('device with firmware version 1.5.1 gets bmp format', function (): void { ]); }); -test('device with firmware version 1.5.2 gets png format', function (): void { +test('device with firmware version 1.5.2 gets png format', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -88,7 +88,7 @@ test('device with firmware version 1.5.2 gets png format', function (): void { ]); }); -test('device falls back to bmp when png does not exist', function (): void { +test('device falls back to bmp when png does not exist', function () { $device = Device::factory()->create([ 'mac_address' => '00:11:22:33:44:55', 'api_key' => 'test-api-key', @@ -124,7 +124,7 @@ test('device falls back to bmp when png does not exist', function (): void { ]); }); -test('device without device_model_id and image_format bmp3_1bit_srgb returns bmp when plugin is rendered', function (): void { +test('device without device_model_id and image_format bmp3_1bit_srgb returns bmp when plugin is rendered', function () { // Create a user with auto-assign enabled $user = User::factory()->create([ 'assign_new_devices' => true, diff --git a/tests/Feature/Api/PluginSettingsArchiveTest.php b/tests/Feature/Api/PluginSettingsArchiveTest.php index f0ad3d0..517f2f8 100644 --- a/tests/Feature/Api/PluginSettingsArchiveTest.php +++ b/tests/Feature/Api/PluginSettingsArchiveTest.php @@ -8,7 +8,7 @@ use Illuminate\Http\UploadedFile; use Illuminate\Support\Str; use Laravel\Sanctum\Sanctum; -it('accepts a plugin settings archive and updates the plugin', function (): void { +it('accepts a plugin settings archive and updates the plugin', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, diff --git a/tests/Feature/Auth/AuthenticationTest.php b/tests/Feature/Auth/AuthenticationTest.php index 07c1683..96edffc 100644 --- a/tests/Feature/Auth/AuthenticationTest.php +++ b/tests/Feature/Auth/AuthenticationTest.php @@ -5,13 +5,13 @@ use Livewire\Volt\Volt as LivewireVolt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('login screen can be rendered', function (): void { +test('login screen can be rendered', function () { $response = $this->get('/login'); $response->assertStatus(200); }); -test('users can authenticate using the login screen', function (): void { +test('users can authenticate using the login screen', function () { $user = User::factory()->create(); $response = LivewireVolt::test('auth.login') @@ -26,7 +26,7 @@ test('users can authenticate using the login screen', function (): void { $this->assertAuthenticated(); }); -test('users can not authenticate with invalid password', function (): void { +test('users can not authenticate with invalid password', function () { $user = User::factory()->create(); $this->post('/login', [ @@ -37,7 +37,7 @@ test('users can not authenticate with invalid password', function (): void { $this->assertGuest(); }); -test('users can logout', function (): void { +test('users can logout', function () { $user = User::factory()->create(); $response = $this->actingAs($user)->post('/logout'); diff --git a/tests/Feature/Auth/EmailVerificationTest.php b/tests/Feature/Auth/EmailVerificationTest.php index 5cc2db8..52a663d 100644 --- a/tests/Feature/Auth/EmailVerificationTest.php +++ b/tests/Feature/Auth/EmailVerificationTest.php @@ -7,7 +7,7 @@ use Illuminate\Support\Facades\URL; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('email verification screen can be rendered', function (): void { +test('email verification screen can be rendered', function () { $user = User::factory()->unverified()->create(); $response = $this->actingAs($user)->get('/verify-email'); @@ -15,7 +15,7 @@ test('email verification screen can be rendered', function (): void { $response->assertStatus(200); }); -test('email can be verified', function (): void { +test('email can be verified', function () { $user = User::factory()->unverified()->create(); Event::fake(); @@ -23,7 +23,7 @@ test('email can be verified', function (): void { $verificationUrl = URL::temporarySignedRoute( 'verification.verify', now()->addMinutes(60), - ['id' => $user->id, 'hash' => sha1((string) $user->email)] + ['id' => $user->id, 'hash' => sha1($user->email)] ); $response = $this->actingAs($user)->get($verificationUrl); @@ -34,7 +34,7 @@ test('email can be verified', function (): void { $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); }); -test('email is not verified with invalid hash', function (): void { +test('email is not verified with invalid hash', function () { $user = User::factory()->unverified()->create(); $verificationUrl = URL::temporarySignedRoute( diff --git a/tests/Feature/Auth/PasswordConfirmationTest.php b/tests/Feature/Auth/PasswordConfirmationTest.php index 265963a..efb11ce 100644 --- a/tests/Feature/Auth/PasswordConfirmationTest.php +++ b/tests/Feature/Auth/PasswordConfirmationTest.php @@ -5,7 +5,7 @@ use Livewire\Volt\Volt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('confirm password screen can be rendered', function (): void { +test('confirm password screen can be rendered', function () { $user = User::factory()->create(); $response = $this->actingAs($user)->get('/confirm-password'); @@ -13,7 +13,7 @@ test('confirm password screen can be rendered', function (): void { $response->assertStatus(200); }); -test('password can be confirmed', function (): void { +test('password can be confirmed', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -27,7 +27,7 @@ test('password can be confirmed', function (): void { ->assertRedirect(route('dashboard', absolute: false)); }); -test('password is not confirmed with invalid password', function (): void { +test('password is not confirmed with invalid password', function () { $user = User::factory()->create(); $this->actingAs($user); diff --git a/tests/Feature/Auth/PasswordResetTest.php b/tests/Feature/Auth/PasswordResetTest.php index 2f38263..86fda9d 100644 --- a/tests/Feature/Auth/PasswordResetTest.php +++ b/tests/Feature/Auth/PasswordResetTest.php @@ -7,13 +7,13 @@ use Livewire\Volt\Volt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('reset password link screen can be rendered', function (): void { +test('reset password link screen can be rendered', function () { $response = $this->get('/forgot-password'); $response->assertStatus(200); }); -test('reset password link can be requested', function (): void { +test('reset password link can be requested', function () { Notification::fake(); $user = User::factory()->create(); @@ -25,7 +25,7 @@ test('reset password link can be requested', function (): void { Notification::assertSentTo($user, ResetPassword::class); }); -test('reset password screen can be rendered', function (): void { +test('reset password screen can be rendered', function () { Notification::fake(); $user = User::factory()->create(); @@ -34,7 +34,7 @@ test('reset password screen can be rendered', function (): void { ->set('email', $user->email) ->call('sendPasswordResetLink'); - Notification::assertSentTo($user, ResetPassword::class, function ($notification): true { + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { $response = $this->get('/reset-password/'.$notification->token); $response->assertStatus(200); @@ -43,7 +43,7 @@ test('reset password screen can be rendered', function (): void { }); }); -test('password can be reset with valid token', function (): void { +test('password can be reset with valid token', function () { Notification::fake(); $user = User::factory()->create(); @@ -52,7 +52,7 @@ test('password can be reset with valid token', function (): void { ->set('email', $user->email) ->call('sendPasswordResetLink'); - Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user): true { + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { $response = Volt::test('auth.reset-password', ['token' => $notification->token]) ->set('email', $user->email) ->set('password', 'password') diff --git a/tests/Feature/Auth/RegistrationTest.php b/tests/Feature/Auth/RegistrationTest.php index 45bc39b..a1c4c07 100644 --- a/tests/Feature/Auth/RegistrationTest.php +++ b/tests/Feature/Auth/RegistrationTest.php @@ -4,13 +4,13 @@ use Livewire\Volt\Volt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('registration screen can be rendered', function (): void { +test('registration screen can be rendered', function () { $response = $this->get('/register'); $response->assertStatus(200); }); -test('new users can register', function (): void { +test('new users can register', function () { $response = Volt::test('auth.register') ->set('name', 'Test User') ->set('email', 'test@example.com') diff --git a/tests/Feature/Console/ExampleRecipesSeederCommandTest.php b/tests/Feature/Console/ExampleRecipesSeederCommandTest.php index 74241e0..4b98180 100644 --- a/tests/Feature/Console/ExampleRecipesSeederCommandTest.php +++ b/tests/Feature/Console/ExampleRecipesSeederCommandTest.php @@ -7,7 +7,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('example recipes seeder command calls seeder with correct user id', function (): void { +test('example recipes seeder command calls seeder with correct user id', function () { $seeder = Mockery::mock(ExampleRecipesSeeder::class); $seeder->shouldReceive('run') ->once() @@ -19,14 +19,14 @@ test('example recipes seeder command calls seeder with correct user id', functio ->assertExitCode(0); }); -test('example recipes seeder command has correct signature', function (): void { +test('example recipes seeder command has correct signature', function () { $command = $this->app->make(App\Console\Commands\ExampleRecipesSeederCommand::class); expect($command->getName())->toBe('recipes:seed'); expect($command->getDescription())->toBe('Seed example recipes'); }); -test('example recipes seeder command prompts for missing input', function (): void { +test('example recipes seeder command prompts for missing input', function () { $seeder = Mockery::mock(ExampleRecipesSeeder::class); $seeder->shouldReceive('run') ->once() diff --git a/tests/Feature/Console/FetchProxyCloudResponsesCommandTest.php b/tests/Feature/Console/FetchProxyCloudResponsesCommandTest.php index e8d12f0..b34357d 100644 --- a/tests/Feature/Console/FetchProxyCloudResponsesCommandTest.php +++ b/tests/Feature/Console/FetchProxyCloudResponsesCommandTest.php @@ -3,7 +3,7 @@ use App\Jobs\FetchProxyCloudResponses; use Illuminate\Support\Facades\Bus; -test('it dispatches fetch proxy cloud responses job', function (): void { +test('it dispatches fetch proxy cloud responses job', function () { // Prevent the job from actually running Bus::fake(); diff --git a/tests/Feature/Console/FirmwareCheckCommandTest.php b/tests/Feature/Console/FirmwareCheckCommandTest.php index e0ed205..19098ea 100644 --- a/tests/Feature/Console/FirmwareCheckCommandTest.php +++ b/tests/Feature/Console/FirmwareCheckCommandTest.php @@ -6,24 +6,24 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('firmware check command has correct signature', function (): void { +test('firmware check command has correct signature', function () { $command = $this->app->make(App\Console\Commands\FirmwareCheckCommand::class); expect($command->getName())->toBe('trmnl:firmware:check'); expect($command->getDescription())->toBe('Checks for the latest firmware and downloads it if flag --download is passed.'); }); -test('firmware check command runs without errors', function (): void { +test('firmware check command runs without errors', function () { $this->artisan('trmnl:firmware:check') ->assertExitCode(0); }); -test('firmware check command runs with download flag', function (): void { +test('firmware check command runs with download flag', function () { $this->artisan('trmnl:firmware:check', ['--download' => true]) ->assertExitCode(0); }); -test('firmware check command can run successfully', function (): void { +test('firmware check command can run successfully', function () { $this->artisan('trmnl:firmware:check') ->assertExitCode(0); }); diff --git a/tests/Feature/Console/FirmwareUpdateCommandTest.php b/tests/Feature/Console/FirmwareUpdateCommandTest.php index 3e8c916..ee250b9 100644 --- a/tests/Feature/Console/FirmwareUpdateCommandTest.php +++ b/tests/Feature/Console/FirmwareUpdateCommandTest.php @@ -6,12 +6,12 @@ use App\Models\Device; use App\Models\Firmware; use App\Models\User; -test('firmware update command has correct signature', function (): void { +test('firmware update command has correct signature', function () { $this->artisan('trmnl:firmware:update --help') ->assertExitCode(0); }); -test('firmware update command can be called', function (): void { +test('firmware update command can be called', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $firmware = Firmware::factory()->create(['version_tag' => '1.0.0']); @@ -26,7 +26,7 @@ test('firmware update command can be called', function (): void { expect($device->update_firmware_id)->toBe($firmware->id); }); -test('firmware update command updates all devices when all is selected', function (): void { +test('firmware update command updates all devices when all is selected', function () { $user = User::factory()->create(); $device1 = Device::factory()->create(['user_id' => $user->id]); $device2 = Device::factory()->create(['user_id' => $user->id]); @@ -44,7 +44,7 @@ test('firmware update command updates all devices when all is selected', functio expect($device2->update_firmware_id)->toBe($firmware->id); }); -test('firmware update command aborts when no devices selected', function (): void { +test('firmware update command aborts when no devices selected', function () { $firmware = Firmware::factory()->create(['version_tag' => '1.0.0']); $this->artisan('trmnl:firmware:update') @@ -55,7 +55,7 @@ test('firmware update command aborts when no devices selected', function (): voi ->assertExitCode(0); }); -test('firmware update command calls firmware check when check is selected', function (): void { +test('firmware update command calls firmware check when check is selected', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $firmware = Firmware::factory()->create(['version_tag' => '1.0.0']); @@ -70,7 +70,7 @@ test('firmware update command calls firmware check when check is selected', func expect($device->update_firmware_id)->toBe($firmware->id); }); -test('firmware update command calls firmware check with download when download is selected', function (): void { +test('firmware update command calls firmware check with download when download is selected', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $firmware = Firmware::factory()->create(['version_tag' => '1.0.0']); diff --git a/tests/Feature/Console/MashupCreateCommandTest.php b/tests/Feature/Console/MashupCreateCommandTest.php index e2d35eb..e61c34c 100644 --- a/tests/Feature/Console/MashupCreateCommandTest.php +++ b/tests/Feature/Console/MashupCreateCommandTest.php @@ -8,12 +8,12 @@ use App\Models\PlaylistItem; use App\Models\Plugin; use App\Models\User; -test('mashup create command has correct signature', function (): void { +test('mashup create command has correct signature', function () { $this->artisan('mashup:create --help') ->assertExitCode(0); }); -test('mashup create command creates mashup successfully', function (): void { +test('mashup create command creates mashup successfully', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $playlist = Playlist::factory()->create(['device_id' => $device->id]); @@ -40,13 +40,13 @@ test('mashup create command creates mashup successfully', function (): void { expect($playlistItem->getMashupPluginIds())->toContain($plugin1->id, $plugin2->id); }); -test('mashup create command exits when no devices found', function (): void { +test('mashup create command exits when no devices found', function () { $this->artisan('mashup:create') ->expectsOutput('No devices found. Please create a device first.') ->assertExitCode(1); }); -test('mashup create command exits when no playlists found for device', function (): void { +test('mashup create command exits when no playlists found for device', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); @@ -56,7 +56,7 @@ test('mashup create command exits when no playlists found for device', function ->assertExitCode(1); }); -test('mashup create command exits when no plugins found', function (): void { +test('mashup create command exits when no plugins found', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $playlist = Playlist::factory()->create(['device_id' => $device->id]); @@ -70,7 +70,7 @@ test('mashup create command exits when no plugins found', function (): void { ->assertExitCode(1); }); -test('mashup create command validates mashup name length', function (): void { +test('mashup create command validates mashup name length', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $playlist = Playlist::factory()->create(['device_id' => $device->id]); @@ -86,7 +86,7 @@ test('mashup create command validates mashup name length', function (): void { ->assertExitCode(1); }); -test('mashup create command validates mashup name maximum length', function (): void { +test('mashup create command validates mashup name maximum length', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $playlist = Playlist::factory()->create(['device_id' => $device->id]); @@ -104,7 +104,7 @@ test('mashup create command validates mashup name maximum length', function (): ->assertExitCode(1); }); -test('mashup create command uses default name when provided', function (): void { +test('mashup create command uses default name when provided', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $playlist = Playlist::factory()->create(['device_id' => $device->id]); @@ -128,7 +128,7 @@ test('mashup create command uses default name when provided', function (): void expect($playlistItem)->not->toBeNull(); }); -test('mashup create command handles 1x1 layout with single plugin', function (): void { +test('mashup create command handles 1x1 layout with single plugin', function () { $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); $playlist = Playlist::factory()->create(['device_id' => $device->id]); diff --git a/tests/Feature/Console/OidcTestCommandTest.php b/tests/Feature/Console/OidcTestCommandTest.php index 56ccea8..e7456b0 100644 --- a/tests/Feature/Console/OidcTestCommandTest.php +++ b/tests/Feature/Console/OidcTestCommandTest.php @@ -4,21 +4,13 @@ declare(strict_types=1); use function Pest\Laravel\mock; -test('oidc test command has correct signature', function (): void { +test('oidc test command has correct signature', function () { $this->artisan('oidc:test --help') ->assertExitCode(0); }); -test('oidc test command runs successfully with disabled oidc', function (): void { - config([ - 'app.url' => 'http://localhost', - 'services.oidc.enabled' => false, - 'services.oidc.endpoint' => null, - 'services.oidc.client_id' => null, - 'services.oidc.client_secret' => null, - 'services.oidc.redirect' => null, - 'services.oidc.scopes' => [], - ]); +test('oidc test command runs successfully with disabled oidc', function () { + config(['services.oidc.enabled' => false]); $this->artisan('oidc:test') ->expectsOutput('Testing OIDC Configuration...') @@ -40,9 +32,8 @@ test('oidc test command runs successfully with disabled oidc', function (): void ->assertExitCode(0); }); -test('oidc test command runs successfully with enabled oidc but missing config', function (): void { +test('oidc test command runs successfully with enabled oidc but missing config', function () { config([ - 'app.url' => 'http://localhost', 'services.oidc.enabled' => true, 'services.oidc.endpoint' => null, 'services.oidc.client_id' => null, @@ -70,7 +61,7 @@ test('oidc test command runs successfully with enabled oidc but missing config', ->assertExitCode(0); }); -test('oidc test command runs successfully with partial config', function (): void { +test('oidc test command runs successfully with partial config', function () { config([ 'services.oidc.enabled' => true, 'services.oidc.endpoint' => 'https://example.com', @@ -95,9 +86,9 @@ test('oidc test command runs successfully with partial config', function (): voi ->assertExitCode(0); }); -test('oidc test command runs successfully with full config but disabled', function (): void { +test('oidc test command runs successfully with full config but disabled', function () { // Mock the HTTP client to return fake OIDC configuration - mock(GuzzleHttp\Client::class, function ($mock): void { + mock(GuzzleHttp\Client::class, function ($mock) { $mock->shouldReceive('get') ->with('https://example.com/.well-known/openid-configuration') ->andReturn(new GuzzleHttp\Psr7\Response(200, [], json_encode([ @@ -129,9 +120,9 @@ test('oidc test command runs successfully with full config but disabled', functi ->assertExitCode(0); }); -test('oidc test command runs successfully with full config and enabled', function (): void { +test('oidc test command runs successfully with full config and enabled', function () { // Mock the HTTP client to return fake OIDC configuration - mock(GuzzleHttp\Client::class, function ($mock): void { + mock(GuzzleHttp\Client::class, function ($mock) { $mock->shouldReceive('get') ->with('https://example.com/.well-known/openid-configuration') ->andReturn(new GuzzleHttp\Psr7\Response(200, [], json_encode([ @@ -164,9 +155,9 @@ test('oidc test command runs successfully with full config and enabled', functio ->assertExitCode(0); }); -test('oidc test command handles empty scopes', function (): void { +test('oidc test command handles empty scopes', function () { // Mock the HTTP client to return fake OIDC configuration - mock(GuzzleHttp\Client::class, function ($mock): void { + mock(GuzzleHttp\Client::class, function ($mock) { $mock->shouldReceive('get') ->with('https://example.com/.well-known/openid-configuration') ->andReturn(new GuzzleHttp\Psr7\Response(200, [], json_encode([ diff --git a/tests/Feature/Console/ScreenGeneratorCommandTest.php b/tests/Feature/Console/ScreenGeneratorCommandTest.php index 1f18107..54621d6 100644 --- a/tests/Feature/Console/ScreenGeneratorCommandTest.php +++ b/tests/Feature/Console/ScreenGeneratorCommandTest.php @@ -3,7 +3,7 @@ use App\Jobs\GenerateScreenJob; use Illuminate\Support\Facades\Bus; -test('it generates screen with default parameters', function (): void { +test('it generates screen with default parameters', function () { Bus::fake(); $this->artisan('trmnl:screen:generate') diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index 110adc8..4ed5100 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -4,12 +4,12 @@ use App\Models\User; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('guests are redirected to the login page', function (): void { +test('guests are redirected to the login page', function () { $response = $this->get('/dashboard'); $response->assertRedirect('/login'); }); -test('authenticated users can visit the dashboard', function (): void { +test('authenticated users can visit the dashboard', function () { $user = User::factory()->create(); $this->actingAs($user); diff --git a/tests/Feature/Devices/DeviceConfigureTest.php b/tests/Feature/Devices/DeviceConfigureTest.php index dff0954..85b1fd3 100644 --- a/tests/Feature/Devices/DeviceConfigureTest.php +++ b/tests/Feature/Devices/DeviceConfigureTest.php @@ -10,7 +10,7 @@ use function Pest\Laravel\actingAs; uses(RefreshDatabase::class); -test('configure view displays last_refreshed_at timestamp', function (): void { +test('configure view displays last_refreshed_at timestamp', function () { $user = User::factory()->create(); $device = Device::factory()->create([ 'user_id' => $user->id, diff --git a/tests/Feature/Devices/DeviceRotationTest.php b/tests/Feature/Devices/DeviceRotationTest.php index 35367ba..e6fb7e0 100644 --- a/tests/Feature/Devices/DeviceRotationTest.php +++ b/tests/Feature/Devices/DeviceRotationTest.php @@ -8,7 +8,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('dashboard shows device image with correct rotation', function (): void { +test('dashboard shows device image with correct rotation', function () { $user = User::factory()->create(); $device = Device::factory()->create([ 'user_id' => $user->id, @@ -28,7 +28,7 @@ test('dashboard shows device image with correct rotation', function (): void { $response->assertSee('origin-center'); }); -test('device configure page shows device image with correct rotation', function (): void { +test('device configure page shows device image with correct rotation', function () { $user = User::factory()->create(); $device = Device::factory()->create([ 'user_id' => $user->id, @@ -48,7 +48,7 @@ test('device configure page shows device image with correct rotation', function $response->assertSee('origin-center'); }); -test('device with no rotation shows no transform style', function (): void { +test('device with no rotation shows no transform style', function () { $user = User::factory()->create(); $device = Device::factory()->create([ 'user_id' => $user->id, @@ -67,7 +67,7 @@ test('device with no rotation shows no transform style', function (): void { $response->assertSee('-rotate-[0deg]'); }); -test('device with null rotation defaults to 0', function (): void { +test('device with null rotation defaults to 0', function () { $user = User::factory()->create(); $device = Device::factory()->create([ 'user_id' => $user->id, diff --git a/tests/Feature/Devices/DeviceTest.php b/tests/Feature/Devices/DeviceTest.php index 3cff76b..e03a82a 100644 --- a/tests/Feature/Devices/DeviceTest.php +++ b/tests/Feature/Devices/DeviceTest.php @@ -5,7 +5,7 @@ use Illuminate\Support\Carbon; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('device can be created with basic attributes', function (): void { +test('device can be created with basic attributes', function () { $device = Device::factory()->create([ 'name' => 'Test Device', ]); @@ -14,7 +14,7 @@ test('device can be created with basic attributes', function (): void { ->and($device->name)->toBe('Test Device'); }); -test('battery percentage is calculated correctly', function (): void { +test('battery percentage is calculated correctly', function () { $cases = [ ['voltage' => 3.0, 'expected' => 0], // Min voltage ['voltage' => 4.2, 'expected' => 100], // Max voltage @@ -34,7 +34,7 @@ test('battery percentage is calculated correctly', function (): void { } }); -test('wifi strength is determined correctly', function (): void { +test('wifi strength is determined correctly', function () { $cases = [ ['rssi' => 0, 'expected' => 0], // No signal ['rssi' => -90, 'expected' => 1], // Weak signal @@ -52,7 +52,7 @@ test('wifi strength is determined correctly', function (): void { } }); -test('proxy cloud attribute is properly cast to boolean', function (): void { +test('proxy cloud attribute is properly cast to boolean', function () { $device = Device::factory()->create([ 'proxy_cloud' => true, ]); @@ -63,7 +63,7 @@ test('proxy cloud attribute is properly cast to boolean', function (): void { expect($device->proxy_cloud)->toBeFalse(); }); -test('last log request is properly cast to json', function (): void { +test('last log request is properly cast to json', function () { $logData = ['status' => 'success', 'timestamp' => '2024-03-04 12:00:00']; $device = Device::factory()->create([ @@ -76,7 +76,7 @@ test('last log request is properly cast to json', function (): void { ->toHaveKey('timestamp'); }); -test('getSleepModeEndsInSeconds returns correct value for overnight sleep window', function (): void { +test('getSleepModeEndsInSeconds returns correct value for overnight sleep window', function () { // Set the current time to 12:13 Carbon::setTestNow(Carbon::create(2024, 1, 1, 12, 13, 0)); diff --git a/tests/Feature/Devices/ManageTest.php b/tests/Feature/Devices/ManageTest.php index fbfd2f2..a629cfe 100644 --- a/tests/Feature/Devices/ManageTest.php +++ b/tests/Feature/Devices/ManageTest.php @@ -6,7 +6,7 @@ use Livewire\Volt\Volt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('device management page can be rendered', function (): void { +test('device management page can be rendered', function () { $user = User::factory()->create(); $response = $this->actingAs($user) @@ -15,7 +15,7 @@ test('device management page can be rendered', function (): void { $response->assertOk(); }); -test('user can create a new device', function (): void { +test('user can create a new device', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -48,7 +48,7 @@ test('user can create a new device', function (): void { expect($device->user_id)->toBe($user->id); }); -test('device creation requires required fields', function (): void { +test('device creation requires required fields', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -67,7 +67,7 @@ test('device creation requires required fields', function (): void { ]); }); -test('user can toggle proxy cloud for their device', function (): void { +test('user can toggle proxy cloud for their device', function () { $user = User::factory()->create(); $this->actingAs($user); $device = Device::factory()->create([ @@ -88,7 +88,7 @@ test('user can toggle proxy cloud for their device', function (): void { expect($device->fresh()->proxy_cloud)->toBeFalse(); }); -test('user cannot toggle proxy cloud for other users devices', function (): void { +test('user cannot toggle proxy cloud for other users devices', function () { $user = User::factory()->create(); $this->actingAs($user); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 34782b1..8b5843f 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -1,6 +1,6 @@ get('/'); $response->assertStatus(200); diff --git a/tests/Feature/FetchDeviceModelsCommandTest.php b/tests/Feature/FetchDeviceModelsCommandTest.php index e09ff4c..2836330 100644 --- a/tests/Feature/FetchDeviceModelsCommandTest.php +++ b/tests/Feature/FetchDeviceModelsCommandTest.php @@ -8,7 +8,7 @@ use Illuminate\Support\Facades\Queue; uses(RefreshDatabase::class); -test('command dispatches fetch device models job', function (): void { +test('command dispatches fetch device models job', function () { Queue::fake(); $this->artisan('device-models:fetch') diff --git a/tests/Feature/FetchProxyCloudResponsesTest.php b/tests/Feature/FetchProxyCloudResponsesTest.php index 561dc1c..bd58002 100644 --- a/tests/Feature/FetchProxyCloudResponsesTest.php +++ b/tests/Feature/FetchProxyCloudResponsesTest.php @@ -7,7 +7,7 @@ use Illuminate\Support\Facades\Storage; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -beforeEach(function (): void { +beforeEach(function () { Storage::fake('public'); Storage::disk('public')->makeDirectory('/images/generated'); Http::preventStrayRequests(); @@ -18,7 +18,7 @@ beforeEach(function (): void { ]); }); -test('it fetches and processes proxy cloud responses for devices', function (): void { +test('it fetches and processes proxy cloud responses for devices', function () { config(['services.trmnl.proxy_base_url' => 'https://example.com']); // Create a test device with proxy cloud enabled @@ -59,14 +59,16 @@ test('it fetches and processes proxy cloud responses for devices', function (): $job->handle(); // Assert HTTP requests were made with correct headers - Http::assertSent(fn ($request): bool => $request->hasHeader('id', $device->mac_address) && - $request->hasHeader('access-token', $device->api_key) && - $request->hasHeader('width', 800) && - $request->hasHeader('height', 480) && - $request->hasHeader('rssi', $device->last_rssi_level) && - $request->hasHeader('battery_voltage', $device->last_battery_voltage) && - $request->hasHeader('refresh-rate', $device->default_refresh_interval) && - $request->hasHeader('fw-version', $device->last_firmware_version)); + Http::assertSent(function ($request) use ($device) { + return $request->hasHeader('id', $device->mac_address) && + $request->hasHeader('access-token', $device->api_key) && + $request->hasHeader('width', 800) && + $request->hasHeader('height', 480) && + $request->hasHeader('rssi', $device->last_rssi_level) && + $request->hasHeader('battery_voltage', $device->last_battery_voltage) && + $request->hasHeader('refresh-rate', $device->default_refresh_interval) && + $request->hasHeader('fw-version', $device->last_firmware_version); + }); // Assert the device was updated $device->refresh(); @@ -80,7 +82,7 @@ test('it fetches and processes proxy cloud responses for devices', function (): Storage::disk('public')->assertExists('images/generated/test-image.bmp'); }); -test('it handles log requests when present', function (): void { +test('it handles log requests when present', function () { $device = Device::factory()->create([ 'proxy_cloud' => true, 'mac_address' => '00:11:22:33:44:55', @@ -101,16 +103,18 @@ test('it handles log requests when present', function (): void { $job->handle(); // Assert log request was sent - Http::assertSent(fn ($request): bool => $request->url() === config('services.trmnl.proxy_base_url').'/api/log' && - $request->hasHeader('id', $device->mac_address) && - $request->body() === json_encode(['message' => 'test log'])); + Http::assertSent(function ($request) use ($device) { + return $request->url() === config('services.trmnl.proxy_base_url').'/api/log' && + $request->hasHeader('id', $device->mac_address) && + $request->body() === json_encode(['message' => 'test log']); + }); // Assert log request was cleared $device->refresh(); expect($device->last_log_request)->toBeNull(); }); -test('it handles API errors gracefully', function (): void { +test('it handles API errors gracefully', function () { $device = Device::factory()->create([ 'proxy_cloud' => true, 'mac_address' => '00:11:22:33:44:55', @@ -126,7 +130,7 @@ test('it handles API errors gracefully', function (): void { expect(fn () => $job->handle())->not->toThrow(Exception::class); }); -test('it only processes proxy cloud enabled devices', function (): void { +test('it only processes proxy cloud enabled devices', function () { Http::fake(); $enabledDevice = Device::factory()->create(['proxy_cloud' => true]); $disabledDevice = Device::factory()->create(['proxy_cloud' => false]); @@ -135,12 +139,16 @@ test('it only processes proxy cloud enabled devices', function (): void { $job->handle(); // Assert request was only made for enabled device - Http::assertSent(fn ($request) => $request->hasHeader('id', $enabledDevice->mac_address)); + Http::assertSent(function ($request) use ($enabledDevice) { + return $request->hasHeader('id', $enabledDevice->mac_address); + }); - Http::assertNotSent(fn ($request) => $request->hasHeader('id', $disabledDevice->mac_address)); + Http::assertNotSent(function ($request) use ($disabledDevice) { + return $request->hasHeader('id', $disabledDevice->mac_address); + }); }); -test('it fetches and processes proxy cloud responses for devices with BMP images', function (): void { +test('it fetches and processes proxy cloud responses for devices with BMP images', function () { config(['services.trmnl.proxy_base_url' => 'https://example.com']); // Create a test device with proxy cloud enabled @@ -168,14 +176,16 @@ test('it fetches and processes proxy cloud responses for devices with BMP images $job->handle(); // Assert HTTP requests were made with correct headers - Http::assertSent(fn ($request): bool => $request->hasHeader('id', $device->mac_address) && - $request->hasHeader('access-token', $device->api_key) && - $request->hasHeader('width', 800) && - $request->hasHeader('height', 480) && - $request->hasHeader('rssi', $device->last_rssi_level) && - $request->hasHeader('battery_voltage', $device->last_battery_voltage) && - $request->hasHeader('refresh-rate', $device->default_refresh_interval) && - $request->hasHeader('fw-version', $device->last_firmware_version)); + Http::assertSent(function ($request) use ($device) { + return $request->hasHeader('id', $device->mac_address) && + $request->hasHeader('access-token', $device->api_key) && + $request->hasHeader('width', 800) && + $request->hasHeader('height', 480) && + $request->hasHeader('rssi', $device->last_rssi_level) && + $request->hasHeader('battery_voltage', $device->last_battery_voltage) && + $request->hasHeader('refresh-rate', $device->default_refresh_interval) && + $request->hasHeader('fw-version', $device->last_firmware_version); + }); // Assert the device was updated $device->refresh(); @@ -191,7 +201,7 @@ test('it fetches and processes proxy cloud responses for devices with BMP images expect(Storage::disk('public')->exists('images/generated/test-image.png'))->toBeFalse(); }); -test('it fetches and processes proxy cloud responses for devices with PNG images', function (): void { +test('it fetches and processes proxy cloud responses for devices with PNG images', function () { config(['services.trmnl.proxy_base_url' => 'https://example.com']); // Create a test device with proxy cloud enabled @@ -219,14 +229,16 @@ test('it fetches and processes proxy cloud responses for devices with PNG images $job->handle(); // Assert HTTP requests were made with correct headers - Http::assertSent(fn ($request): bool => $request->hasHeader('id', $device->mac_address) && - $request->hasHeader('access-token', $device->api_key) && - $request->hasHeader('width', 800) && - $request->hasHeader('height', 480) && - $request->hasHeader('rssi', $device->last_rssi_level) && - $request->hasHeader('battery_voltage', $device->last_battery_voltage) && - $request->hasHeader('refresh-rate', $device->default_refresh_interval) && - $request->hasHeader('fw-version', $device->last_firmware_version)); + Http::assertSent(function ($request) use ($device) { + return $request->hasHeader('id', $device->mac_address) && + $request->hasHeader('access-token', $device->api_key) && + $request->hasHeader('width', 800) && + $request->hasHeader('height', 480) && + $request->hasHeader('rssi', $device->last_rssi_level) && + $request->hasHeader('battery_voltage', $device->last_battery_voltage) && + $request->hasHeader('refresh-rate', $device->default_refresh_interval) && + $request->hasHeader('fw-version', $device->last_firmware_version); + }); // Assert the device was updated $device->refresh(); @@ -242,7 +254,7 @@ test('it fetches and processes proxy cloud responses for devices with PNG images expect(Storage::disk('public')->exists('images/generated/test-image.bmp'))->toBeFalse(); }); -test('it handles missing content type in image URL gracefully', function (): void { +test('it handles missing content type in image URL gracefully', function () { config(['services.trmnl.proxy_base_url' => 'https://example.com']); // Create a test device with proxy cloud enabled diff --git a/tests/Feature/GenerateScreenJobTest.php b/tests/Feature/GenerateScreenJobTest.php index 115fb51..35b4377 100644 --- a/tests/Feature/GenerateScreenJobTest.php +++ b/tests/Feature/GenerateScreenJobTest.php @@ -2,18 +2,16 @@ use App\Jobs\GenerateScreenJob; use App\Models\Device; -use Bnussbau\TrmnlPipeline\TrmnlPipeline; use Illuminate\Support\Facades\Storage; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -beforeEach(function (): void { - TrmnlPipeline::fake(); +beforeEach(function () { Storage::fake('public'); Storage::disk('public')->makeDirectory('/images/generated'); }); -test('it generates screen images and updates device', function (): void { +test('it generates screen images and updates device', function () { $device = Device::factory()->create(); $job = new GenerateScreenJob($device->id, null, view('trmnl')->render()); $job->handle(); @@ -25,9 +23,9 @@ test('it generates screen images and updates device', function (): void { // Assert both PNG and BMP files were created $uuid = $device->current_screen_image; Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); -test('it cleans up unused images', function (): void { +test('it cleans up unused images', function () { // Create some test devices with images $activeDevice = Device::factory()->create([ 'current_screen_image' => 'uuid-to-be-replaced', @@ -47,9 +45,9 @@ test('it cleans up unused images', function (): void { Storage::disk('public')->assertMissing('/images/generated/uuid-to-be-replaced.bmp'); Storage::disk('public')->assertMissing('/images/generated/inactive-uuid.png'); Storage::disk('public')->assertMissing('/images/generated/inactive-uuid.bmp'); -}); +})->skipOnCi(); -test('it preserves gitignore file during cleanup', function (): void { +test('it preserves gitignore file during cleanup', function () { Storage::disk('public')->put('/images/generated/.gitignore', '*'); $device = Device::factory()->create(); @@ -57,4 +55,4 @@ test('it preserves gitignore file during cleanup', function (): void { $job->handle(); Storage::disk('public')->assertExists('/images/generated/.gitignore'); -}); +})->skipOnCi(); diff --git a/tests/Feature/ImageGenerationServiceTest.php b/tests/Feature/ImageGenerationServiceTest.php index 603205e..f2af102 100644 --- a/tests/Feature/ImageGenerationServiceTest.php +++ b/tests/Feature/ImageGenerationServiceTest.php @@ -6,7 +6,6 @@ use App\Enums\ImageFormat; use App\Models\Device; use App\Models\DeviceModel; use App\Services\ImageGenerationService; -use Bnussbau\TrmnlPipeline\TrmnlPipeline; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Storage; @@ -15,11 +14,6 @@ uses(RefreshDatabase::class); beforeEach(function (): void { Storage::fake('public'); Storage::disk('public')->makeDirectory('/images/generated'); - TrmnlPipeline::fake(); -}); - -afterEach(function (): void { - TrmnlPipeline::restore(); }); it('generates image for device without device model', function (): void { @@ -40,7 +34,7 @@ it('generates image for device without device model', function (): void { // Assert PNG file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); it('generates image for device with device model', function (): void { // Create a DeviceModel @@ -70,7 +64,68 @@ it('generates image for device with device model', function (): void { // Assert PNG file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); + +it('generates 4-color 2-bit PNG with device model', function (): void { + // Create a DeviceModel for 4-color, 2-bit PNG + $deviceModel = DeviceModel::factory()->create([ + 'width' => 800, + 'height' => 480, + 'colors' => 4, + 'bit_depth' => 2, + 'scale_factor' => 1.0, + 'rotation' => 0, + 'mime_type' => 'image/png', + 'offset_x' => 0, + 'offset_y' => 0, + ]); + + // Create a device with the DeviceModel + $device = Device::factory()->create([ + 'device_model_id' => $deviceModel->id, + ]); + + $markup = '
Test Content
'; + $uuid = ImageGenerationService::generateImage($markup, $device->id); + + // Assert the device was updated with a new image UUID + $device->refresh(); + expect($device->current_screen_image)->toBe($uuid); + + // Assert PNG file was created + Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); + + // Verify the image file has content and isn't blank + $imagePath = Storage::disk('public')->path("/images/generated/{$uuid}.png"); + $imageSize = filesize($imagePath); + expect($imageSize)->toBeGreaterThan(200); // Should be at least 200 bytes for a 2-bit PNG + + // Verify it's a valid PNG file + $imageInfo = getimagesize($imagePath); + expect($imageInfo[0])->toBe(800); // Width + expect($imageInfo[1])->toBe(480); // Height + expect($imageInfo[2])->toBe(IMAGETYPE_PNG); // PNG type + + // Debug: Check if the image has any non-transparent pixels + $image = imagecreatefrompng($imagePath); + $width = imagesx($image); + $height = imagesy($image); + $hasContent = false; + + // Check a few sample pixels to see if there's content + for ($x = 0; $x < min(10, $width); $x += 2) { + for ($y = 0; $y < min(10, $height); $y += 2) { + $color = imagecolorat($image, $x, $y); + if ($color !== 0) { // Not black/transparent + $hasContent = true; + break 2; + } + } + } + + imagedestroy($image); + expect($hasContent)->toBe(true, 'Image should contain visible content'); +})->skipOnCi(); it('generates BMP with device model', function (): void { // Create a DeviceModel for BMP format @@ -100,7 +155,7 @@ it('generates BMP with device model', function (): void { // Assert BMP file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.bmp"); -}); +})->skipOnCi(); it('applies scale factor from device model', function (): void { // Create a DeviceModel with scale factor @@ -130,7 +185,7 @@ it('applies scale factor from device model', function (): void { // Assert PNG file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); it('applies rotation from device model', function (): void { // Create a DeviceModel with rotation @@ -160,7 +215,7 @@ it('applies rotation from device model', function (): void { // Assert PNG file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); it('applies offset from device model', function (): void { // Create a DeviceModel with offset @@ -190,7 +245,7 @@ it('applies offset from device model', function (): void { // Assert PNG file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); it('falls back to device settings when no device model', function (): void { // Create a device with custom settings but no DeviceModel @@ -210,7 +265,7 @@ it('falls back to device settings when no device model', function (): void { // Assert PNG file was created Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); it('handles auto image format for legacy devices', function (): void { // Create a device with AUTO format (legacy behavior) @@ -231,7 +286,7 @@ it('handles auto image format for legacy devices', function (): void { // Assert PNG file was created (modern firmware defaults to PNG) Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); -}); +})->skipOnCi(); it('cleanupFolder removes unused images', function (): void { // Create active devices with images @@ -254,7 +309,7 @@ it('cleanupFolder removes unused images', function (): void { // Assert inactive files are removed Storage::disk('public')->assertMissing('/images/generated/inactive-uuid.png'); Storage::disk('public')->assertMissing('/images/generated/another-inactive.png'); -}); +})->skipOnCi(); it('cleanupFolder preserves .gitignore', function (): void { // Create gitignore file @@ -268,7 +323,7 @@ it('cleanupFolder preserves .gitignore', function (): void { // Assert gitignore is preserved Storage::disk('public')->assertExists('/images/generated/.gitignore'); -}); +})->skipOnCi(); it('resetIfNotCacheable resets when device models exist', function (): void { // Create a plugin @@ -285,7 +340,7 @@ it('resetIfNotCacheable resets when device models exist', function (): void { // Assert plugin image was reset $plugin->refresh(); expect($plugin->current_image)->toBeNull(); -}); +})->skipOnCi(); it('resetIfNotCacheable resets when custom dimensions exist', function (): void { // Create a plugin @@ -303,7 +358,7 @@ it('resetIfNotCacheable resets when custom dimensions exist', function (): void // Assert plugin image was reset $plugin->refresh(); expect($plugin->current_image)->toBeNull(); -}); +})->skipOnCi(); it('resetIfNotCacheable preserves image for standard devices', function (): void { // Create a plugin @@ -322,7 +377,7 @@ it('resetIfNotCacheable preserves image for standard devices', function (): void // Assert plugin image was preserved $plugin->refresh(); expect($plugin->current_image)->toBe('test-uuid'); -}); +})->skipOnCi(); it('determines correct image format from device model', function (): void { // Test BMP format detection @@ -367,7 +422,7 @@ it('determines correct image format from device model', function (): void { $device3->refresh(); expect($device3->current_screen_image)->toBe($uuid3); Storage::disk('public')->assertExists("/images/generated/{$uuid3}.png"); -}); +})->skipOnCi(); it('generates BMP for legacy device with bmp3_1bit_srgb format', function (): void { // Create a device with BMP format but no DeviceModel (legacy behavior) @@ -399,4 +454,4 @@ it('generates BMP for legacy device with bmp3_1bit_srgb format', function (): vo expect($imageInfo[0])->toBe(800); // Width expect($imageInfo[1])->toBe(480); // Height expect($imageInfo[2])->toBe(IMAGETYPE_BMP); // BMP type -}); +})->skipOnCi(); diff --git a/tests/Feature/ImageGenerationWithoutFakeTest.php b/tests/Feature/ImageGenerationWithoutFakeTest.php deleted file mode 100644 index ff70174..0000000 --- a/tests/Feature/ImageGenerationWithoutFakeTest.php +++ /dev/null @@ -1,55 +0,0 @@ -makeDirectory('/images/generated'); -}); - -it('generates 4-color 2-bit PNG with device model', function (): void { - // Create a DeviceModel for 4-color, 2-bit PNG - $deviceModel = DeviceModel::factory()->create([ - 'width' => 800, - 'height' => 480, - 'colors' => 4, - 'bit_depth' => 2, - 'scale_factor' => 1.0, - 'rotation' => 0, - 'mime_type' => 'image/png', - 'offset_x' => 0, - 'offset_y' => 0, - ]); - - // Create a device with the DeviceModel - $device = Device::factory()->create([ - 'device_model_id' => $deviceModel->id, - ]); - - $markup = '
Test Content
'; - $uuid = ImageGenerationService::generateImage($markup, $device->id); - - // Assert the device was updated with a new image UUID - $device->refresh(); - expect($device->current_screen_image)->toBe($uuid); - - // Assert PNG file was created - Storage::disk('public')->assertExists("/images/generated/{$uuid}.png"); - - // Verify the image file has content and isn't blank - $imagePath = Storage::disk('public')->path("/images/generated/{$uuid}.png"); - $imageSize = filesize($imagePath); - expect($imageSize)->toBeGreaterThan(200); // Should be at least 200 bytes for a 2-bit PNG - - // Verify it's a valid PNG file - $imageInfo = getimagesize($imagePath); - expect($imageInfo[0])->toBe(800); // Width - expect($imageInfo[1])->toBe(480); // Height - expect($imageInfo[2])->toBe(IMAGETYPE_PNG); // PNG type - -})->skipOnCI(); diff --git a/tests/Feature/Jobs/CleanupDeviceLogsJobTest.php b/tests/Feature/Jobs/CleanupDeviceLogsJobTest.php index ae2833b..15888c0 100644 --- a/tests/Feature/Jobs/CleanupDeviceLogsJobTest.php +++ b/tests/Feature/Jobs/CleanupDeviceLogsJobTest.php @@ -7,7 +7,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('it keeps only the 50 most recent logs per device', function (): void { +test('it keeps only the 50 most recent logs per device', function () { // Create two devices $device1 = Device::factory()->create(); $device2 = Device::factory()->create(); diff --git a/tests/Feature/Jobs/FetchDeviceModelsJobTest.php b/tests/Feature/Jobs/FetchDeviceModelsJobTest.php index 1c131c4..b85a24e 100644 --- a/tests/Feature/Jobs/FetchDeviceModelsJobTest.php +++ b/tests/Feature/Jobs/FetchDeviceModelsJobTest.php @@ -14,12 +14,12 @@ beforeEach(function (): void { DeviceModel::truncate(); }); -test('fetch device models job can be dispatched', function (): void { +test('fetch device models job can be dispatched', function () { $job = new FetchDeviceModelsJob(); expect($job)->toBeInstanceOf(FetchDeviceModelsJob::class); }); -test('fetch device models job handles successful api response', function (): void { +test('fetch device models job handles successful api response', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => [ @@ -65,7 +65,7 @@ test('fetch device models job handles successful api response', function (): voi expect($deviceModel->source)->toBe('api'); }); -test('fetch device models job handles multiple device models', function (): void { +test('fetch device models job handles multiple device models', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => [ @@ -114,7 +114,7 @@ test('fetch device models job handles multiple device models', function (): void expect(DeviceModel::where('name', 'model-2')->exists())->toBeTrue(); }); -test('fetch device models job handles empty data array', function (): void { +test('fetch device models job handles empty data array', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => [], @@ -131,7 +131,7 @@ test('fetch device models job handles empty data array', function (): void { expect(DeviceModel::count())->toBe(0); }); -test('fetch device models job handles missing data field', function (): void { +test('fetch device models job handles missing data field', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'message' => 'No data available', @@ -148,7 +148,7 @@ test('fetch device models job handles missing data field', function (): void { expect(DeviceModel::count())->toBe(0); }); -test('fetch device models job handles non-array data', function (): void { +test('fetch device models job handles non-array data', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => 'invalid-data', @@ -165,7 +165,7 @@ test('fetch device models job handles non-array data', function (): void { expect(DeviceModel::count())->toBe(0); }); -test('fetch device models job handles api failure', function (): void { +test('fetch device models job handles api failure', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'error' => 'Internal Server Error', @@ -185,9 +185,9 @@ test('fetch device models job handles api failure', function (): void { expect(DeviceModel::count())->toBe(0); }); -test('fetch device models job handles network exception', function (): void { +test('fetch device models job handles network exception', function () { Http::fake([ - 'usetrmnl.com/api/models' => function (): void { + 'usetrmnl.com/api/models' => function () { throw new Exception('Network connection failed'); }, ]); @@ -202,7 +202,7 @@ test('fetch device models job handles network exception', function (): void { expect(DeviceModel::count())->toBe(0); }); -test('fetch device models job handles device model with missing name', function (): void { +test('fetch device models job handles device model with missing name', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => [ @@ -228,7 +228,7 @@ test('fetch device models job handles device model with missing name', function expect(DeviceModel::count())->toBe(0); }); -test('fetch device models job handles device model with partial data', function (): void { +test('fetch device models job handles device model with partial data', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => [ @@ -263,7 +263,7 @@ test('fetch device models job handles device model with partial data', function expect($deviceModel->source)->toBe('api'); }); -test('fetch device models job updates existing device model', function (): void { +test('fetch device models job updates existing device model', function () { // Create an existing device model $existingModel = DeviceModel::factory()->create([ 'name' => 'existing-model', @@ -309,7 +309,7 @@ test('fetch device models job updates existing device model', function (): void expect($existingModel->source)->toBe('api'); }); -test('fetch device models job handles processing exception for individual model', function (): void { +test('fetch device models job handles processing exception for individual model', function () { Http::fake([ 'usetrmnl.com/api/models' => Http::response([ 'data' => [ diff --git a/tests/Feature/Jobs/FirmwareDownloadJobTest.php b/tests/Feature/Jobs/FirmwareDownloadJobTest.php index f9109bb..7ae9417 100644 --- a/tests/Feature/Jobs/FirmwareDownloadJobTest.php +++ b/tests/Feature/Jobs/FirmwareDownloadJobTest.php @@ -5,12 +5,12 @@ use App\Models\Firmware; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; -beforeEach(function (): void { +beforeEach(function () { Storage::fake('public'); Storage::disk('public')->makeDirectory('/firmwares'); }); -test('it creates firmwares directory if it does not exist', function (): void { +test('it creates firmwares directory if it does not exist', function () { $firmware = Firmware::factory()->create([ 'url' => 'https://example.com/firmware.bin', 'version_tag' => '1.0.0', @@ -26,7 +26,7 @@ test('it creates firmwares directory if it does not exist', function (): void { expect(Storage::disk('public')->exists('firmwares'))->toBeTrue(); }); -test('it downloads firmware and updates storage location', function (): void { +test('it downloads firmware and updates storage location', function () { Http::fake([ 'https://example.com/firmware.bin' => Http::response('fake firmware content', 200), ]); @@ -42,7 +42,7 @@ test('it downloads firmware and updates storage location', function (): void { expect($firmware->fresh()->storage_location)->toBe('firmwares/FW1.0.0.bin'); }); -test('it handles connection exception gracefully', function (): void { +test('it handles connection exception gracefully', function () { $firmware = Firmware::factory()->create([ 'url' => 'https://example.com/firmware.bin', 'version_tag' => '1.0.0', @@ -50,7 +50,7 @@ test('it handles connection exception gracefully', function (): void { ]); Http::fake([ - 'https://example.com/firmware.bin' => function (): void { + 'https://example.com/firmware.bin' => function () { throw new Illuminate\Http\Client\ConnectionException('Connection failed'); }, ]); @@ -65,7 +65,7 @@ test('it handles connection exception gracefully', function (): void { expect($firmware->fresh()->storage_location)->toBeNull(); }); -test('it handles general exception gracefully', function (): void { +test('it handles general exception gracefully', function () { $firmware = Firmware::factory()->create([ 'url' => 'https://example.com/firmware.bin', 'version_tag' => '1.0.0', @@ -73,7 +73,7 @@ test('it handles general exception gracefully', function (): void { ]); Http::fake([ - 'https://example.com/firmware.bin' => function (): void { + 'https://example.com/firmware.bin' => function () { throw new Exception('Unexpected error'); }, ]); @@ -88,7 +88,7 @@ test('it handles general exception gracefully', function (): void { expect($firmware->fresh()->storage_location)->toBeNull(); }); -test('it handles firmware with special characters in version tag', function (): void { +test('it handles firmware with special characters in version tag', function () { Http::fake([ 'https://example.com/firmware.bin' => Http::response('fake firmware content', 200), ]); @@ -103,7 +103,7 @@ test('it handles firmware with special characters in version tag', function (): expect($firmware->fresh()->storage_location)->toBe('firmwares/FW1.0.0-beta.bin'); }); -test('it handles firmware with long version tag', function (): void { +test('it handles firmware with long version tag', function () { Http::fake([ 'https://example.com/firmware.bin' => Http::response('fake firmware content', 200), ]); @@ -118,7 +118,7 @@ test('it handles firmware with long version tag', function (): void { expect($firmware->fresh()->storage_location)->toBe('firmwares/FW1.0.0.1234.5678.90.bin'); }); -test('it creates firmwares directory even when it already exists', function (): void { +test('it creates firmwares directory even when it already exists', function () { $firmware = Firmware::factory()->create([ 'url' => 'https://example.com/firmware.bin', 'version_tag' => '1.0.0', @@ -138,7 +138,7 @@ test('it creates firmwares directory even when it already exists', function (): expect($firmware->fresh()->storage_location)->toBe('firmwares/FW1.0.0.bin'); }); -test('it handles http error response', function (): void { +test('it handles http error response', function () { $firmware = Firmware::factory()->create([ 'url' => 'https://example.com/firmware.bin', 'version_tag' => '1.0.0', diff --git a/tests/Feature/Jobs/FirmwarePollJobTest.php b/tests/Feature/Jobs/FirmwarePollJobTest.php index 74c3cf7..751bc8c 100644 --- a/tests/Feature/Jobs/FirmwarePollJobTest.php +++ b/tests/Feature/Jobs/FirmwarePollJobTest.php @@ -5,11 +5,11 @@ use App\Models\Firmware; use Illuminate\Http\Client\ConnectionException; use Illuminate\Support\Facades\Http; -beforeEach(function (): void { +beforeEach(function () { Http::preventStrayRequests(); }); -test('it creates new firmware record when polling', function (): void { +test('it creates new firmware record when polling', function () { Http::fake([ 'https://usetrmnl.com/api/firmware/latest' => Http::response([ 'version' => '1.0.0', @@ -25,7 +25,7 @@ test('it creates new firmware record when polling', function (): void { ->latest->toBeTrue(); }); -test('it updates existing firmware record when polling', function (): void { +test('it updates existing firmware record when polling', function () { $existingFirmware = Firmware::factory()->create([ 'version_tag' => '1.0.0', 'url' => 'https://old-url.com/firmware.bin', @@ -46,7 +46,7 @@ test('it updates existing firmware record when polling', function (): void { ->latest->toBeTrue(); }); -test('it marks previous firmware as not latest when new version is found', function (): void { +test('it marks previous firmware as not latest when new version is found', function () { $oldFirmware = Firmware::factory()->create([ 'version_tag' => '1.0.0', 'latest' => true, @@ -65,9 +65,9 @@ test('it marks previous firmware as not latest when new version is found', funct ->and(Firmware::where('version_tag', '1.1.0')->first()->latest)->toBeTrue(); }); -test('it handles connection exception gracefully', function (): void { +test('it handles connection exception gracefully', function () { Http::fake([ - 'https://usetrmnl.com/api/firmware/latest' => function (): void { + 'https://usetrmnl.com/api/firmware/latest' => function () { throw new ConnectionException('Connection failed'); }, ]); @@ -78,7 +78,7 @@ test('it handles connection exception gracefully', function (): void { expect(Firmware::count())->toBe(0); }); -test('it handles invalid response gracefully', function (): void { +test('it handles invalid response gracefully', function () { Http::fake([ 'https://usetrmnl.com/api/firmware/latest' => Http::response(null, 200), ]); @@ -89,7 +89,7 @@ test('it handles invalid response gracefully', function (): void { expect(Firmware::count())->toBe(0); }); -test('it handles missing version in response gracefully', function (): void { +test('it handles missing version in response gracefully', function () { Http::fake([ 'https://usetrmnl.com/api/firmware/latest' => Http::response([ 'url' => 'https://example.com/firmware.bin', @@ -102,7 +102,7 @@ test('it handles missing version in response gracefully', function (): void { expect(Firmware::count())->toBe(0); }); -test('it handles missing url in response gracefully', function (): void { +test('it handles missing url in response gracefully', function () { Http::fake([ 'https://usetrmnl.com/api/firmware/latest' => Http::response([ 'version' => '1.0.0', diff --git a/tests/Feature/Jobs/NotifyDeviceBatteryLowJobTest.php b/tests/Feature/Jobs/NotifyDeviceBatteryLowJobTest.php index 6d69924..5ac9c17 100644 --- a/tests/Feature/Jobs/NotifyDeviceBatteryLowJobTest.php +++ b/tests/Feature/Jobs/NotifyDeviceBatteryLowJobTest.php @@ -8,7 +8,7 @@ use App\Models\User; use App\Notifications\BatteryLow; use Illuminate\Support\Facades\Notification; -test('it sends battery low notification when battery is below threshold', function (): void { +test('it sends battery low notification when battery is below threshold', function () { Notification::fake(); config(['app.notifications.battery_low.warn_at_percent' => 20]); @@ -29,7 +29,7 @@ test('it sends battery low notification when battery is below threshold', functi expect($device->battery_notification_sent)->toBeTrue(); }); -test('it does not send notification when battery is above threshold', function (): void { +test('it does not send notification when battery is above threshold', function () { Notification::fake(); config(['app.notifications.battery_low.warn_at_percent' => 20]); @@ -50,7 +50,7 @@ test('it does not send notification when battery is above threshold', function ( expect($device->battery_notification_sent)->toBeFalse(); }); -test('it does not send notification when already sent', function (): void { +test('it does not send notification when already sent', function () { Notification::fake(); config(['app.notifications.battery_low.warn_at_percent' => 20]); @@ -68,7 +68,7 @@ test('it does not send notification when already sent', function (): void { Notification::assertNotSentTo($user, BatteryLow::class); }); -test('it resets notification flag when battery is above threshold', function (): void { +test('it resets notification flag when battery is above threshold', function () { Notification::fake(); config(['app.notifications.battery_low.warn_at_percent' => 20]); @@ -89,7 +89,7 @@ test('it resets notification flag when battery is above threshold', function (): expect($device->battery_notification_sent)->toBeFalse(); }); -test('it skips devices without associated user', function (): void { +test('it skips devices without associated user', function () { Notification::fake(); config(['app.notifications.battery_low.warn_at_percent' => 20]); @@ -106,7 +106,7 @@ test('it skips devices without associated user', function (): void { Notification::assertNothingSent(); }); -test('it processes multiple devices correctly', function (): void { +test('it processes multiple devices correctly', function () { Notification::fake(); config(['app.notifications.battery_low.warn_at_percent' => 20]); diff --git a/tests/Feature/Livewire/Actions/DeviceAutoJoinTest.php b/tests/Feature/Livewire/Actions/DeviceAutoJoinTest.php index 5d8b057..d263334 100644 --- a/tests/Feature/Livewire/Actions/DeviceAutoJoinTest.php +++ b/tests/Feature/Livewire/Actions/DeviceAutoJoinTest.php @@ -9,7 +9,7 @@ use Livewire\Livewire; uses(RefreshDatabase::class); -test('device auto join component can be rendered', function (): void { +test('device auto join component can be rendered', function () { $user = User::factory()->create(['assign_new_devices' => false]); Livewire::actingAs($user) @@ -19,7 +19,7 @@ test('device auto join component can be rendered', function (): void { ->assertSet('isFirstUser', true); }); -test('device auto join component initializes with user settings', function (): void { +test('device auto join component initializes with user settings', function () { $user = User::factory()->create(['assign_new_devices' => true]); Livewire::actingAs($user) @@ -28,7 +28,7 @@ test('device auto join component initializes with user settings', function (): v ->assertSet('isFirstUser', true); }); -test('device auto join component identifies first user correctly', function (): void { +test('device auto join component identifies first user correctly', function () { $firstUser = User::factory()->create(['id' => 1, 'assign_new_devices' => false]); $otherUser = User::factory()->create(['id' => 2, 'assign_new_devices' => false]); @@ -41,7 +41,7 @@ test('device auto join component identifies first user correctly', function (): ->assertSet('isFirstUser', false); }); -test('device auto join component updates user setting when toggled', function (): void { +test('device auto join component updates user setting when toggled', function () { $user = User::factory()->create(['assign_new_devices' => false]); Livewire::actingAs($user) @@ -55,7 +55,7 @@ test('device auto join component updates user setting when toggled', function () // Validation test removed - Livewire automatically handles boolean conversion -test('device auto join component handles false value correctly', function (): void { +test('device auto join component handles false value correctly', function () { $user = User::factory()->create(['assign_new_devices' => true]); Livewire::actingAs($user) @@ -67,7 +67,7 @@ test('device auto join component handles false value correctly', function (): vo expect($user->assign_new_devices)->toBeFalse(); }); -test('device auto join component only updates when deviceAutojoin property changes', function (): void { +test('device auto join component only updates when deviceAutojoin property changes', function () { $user = User::factory()->create(['assign_new_devices' => false]); $component = Livewire::actingAs($user) @@ -80,7 +80,7 @@ test('device auto join component only updates when deviceAutojoin property chang expect($user->assign_new_devices)->toBeFalse(); }); -test('device auto join component renders correct view', function (): void { +test('device auto join component renders correct view', function () { $user = User::factory()->create(); Livewire::actingAs($user) @@ -88,7 +88,7 @@ test('device auto join component renders correct view', function (): void { ->assertViewIs('livewire.actions.device-auto-join'); }); -test('device auto join component works with authenticated user', function (): void { +test('device auto join component works with authenticated user', function () { $user = User::factory()->create(['assign_new_devices' => true]); $component = Livewire::actingAs($user) @@ -98,7 +98,7 @@ test('device auto join component works with authenticated user', function (): vo expect($component->instance()->isFirstUser)->toBe($user->id === 1); }); -test('device auto join component handles multiple updates correctly', function (): void { +test('device auto join component handles multiple updates correctly', function () { $user = User::factory()->create(['assign_new_devices' => false]); $component = Livewire::actingAs($user) diff --git a/tests/Feature/Livewire/Catalog/IndexTest.php b/tests/Feature/Livewire/Catalog/IndexTest.php index 8b26076..82bf816 100644 --- a/tests/Feature/Livewire/Catalog/IndexTest.php +++ b/tests/Feature/Livewire/Catalog/IndexTest.php @@ -6,11 +6,11 @@ use Illuminate\Support\Facades\Http; use Livewire\Volt\Volt; use Symfony\Component\Yaml\Yaml; -beforeEach(function (): void { +beforeEach(function () { Cache::flush(); }); -it('can render catalog component', function (): void { +it('can render catalog component', function () { // Mock empty catalog response Http::fake([ config('app.catalog_url') => Http::response('', 200), @@ -21,7 +21,7 @@ it('can render catalog component', function (): void { $component->assertSee('No plugins available'); }); -it('loads plugins from catalog URL', function (): void { +it('loads plugins from catalog URL', function () { // Clear cache first to ensure fresh data Cache::forget('catalog_plugins'); @@ -62,7 +62,7 @@ it('loads plugins from catalog URL', function (): void { $component->assertSee('MIT'); }); -it('shows error when plugin not found', function (): void { +it('shows error when plugin not found', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -75,7 +75,7 @@ it('shows error when plugin not found', function (): void { $component->assertHasErrors(); }); -it('shows error when zip_url is missing', function (): void { +it('shows error when zip_url is missing', function () { $user = User::factory()->create(); // Mock the HTTP response for the catalog URL without zip_url diff --git a/tests/Feature/PlaylistSchedulingTest.php b/tests/Feature/PlaylistSchedulingTest.php index aea4923..43ad663 100644 --- a/tests/Feature/PlaylistSchedulingTest.php +++ b/tests/Feature/PlaylistSchedulingTest.php @@ -10,7 +10,7 @@ use Illuminate\Support\Carbon; uses(RefreshDatabase::class); -test('playlist scheduling works correctly for time ranges spanning midnight', function (): void { +test('playlist scheduling works correctly for time ranges spanning midnight', function () { // Create a user and device $user = User::factory()->create(); $device = Device::factory()->create(['user_id' => $user->id]); @@ -85,7 +85,7 @@ test('playlist scheduling works correctly for time ranges spanning midnight', fu expect($nextItem->playlist->name)->toBe('Day until Deep Night Playlist'); }); -test('playlist isActiveNow handles midnight spanning correctly', function (): void { +test('playlist isActiveNow handles midnight spanning correctly', function () { $playlist = Playlist::factory()->create([ 'is_active' => true, 'active_from' => '09:01', @@ -110,7 +110,7 @@ test('playlist isActiveNow handles midnight spanning correctly', function (): vo expect($playlist->isActiveNow())->toBeFalse(); }); -test('playlist isActiveNow handles normal time ranges correctly', function (): void { +test('playlist isActiveNow handles normal time ranges correctly', function () { $playlist = Playlist::factory()->create([ 'is_active' => true, 'active_from' => '09:00', diff --git a/tests/Feature/PluginArchiveTest.php b/tests/Feature/PluginArchiveTest.php index 9a95379..9a7f66c 100644 --- a/tests/Feature/PluginArchiveTest.php +++ b/tests/Feature/PluginArchiveTest.php @@ -9,11 +9,11 @@ use App\Services\PluginImportService; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; -beforeEach(function (): void { +beforeEach(function () { Storage::fake('local'); }); -it('exports plugin to zip file in correct format', function (): void { +it('exports plugin to zip file in correct format', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -42,7 +42,7 @@ it('exports plugin to zip file in correct format', function (): void { expect($response->getFile()->getFilename())->toContain('test-plugin-123.zip'); }); -it('exports plugin with polling configuration', function (): void { +it('exports plugin with polling configuration', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -63,7 +63,7 @@ it('exports plugin with polling configuration', function (): void { expect($response)->toBeInstanceOf(Symfony\Component\HttpFoundation\BinaryFileResponse::class); }); -it('exports and imports plugin maintaining all data', function (): void { +it('exports and imports plugin maintaining all data', function () { $user = User::factory()->create(); $originalPlugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -122,7 +122,7 @@ it('exports and imports plugin maintaining all data', function (): void { expect($importedPlugin->data_payload)->toBe(['items' => [1, 2, 3]]); }); -it('handles blade templates correctly', function (): void { +it('handles blade templates correctly', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -138,7 +138,7 @@ it('handles blade templates correctly', function (): void { expect($response)->toBeInstanceOf(Symfony\Component\HttpFoundation\BinaryFileResponse::class); }); -it('removes wrapper div from exported markup', function (): void { +it('removes wrapper div from exported markup', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -154,7 +154,7 @@ it('removes wrapper div from exported markup', function (): void { expect($response)->toBeInstanceOf(Symfony\Component\HttpFoundation\BinaryFileResponse::class); }); -it('converts polling headers correctly', function (): void { +it('converts polling headers correctly', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -170,7 +170,7 @@ it('converts polling headers correctly', function (): void { expect($response)->toBeInstanceOf(Symfony\Component\HttpFoundation\BinaryFileResponse::class); }); -it('api route returns zip file for authenticated user', function (): void { +it('api route returns zip file for authenticated user', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -188,7 +188,7 @@ it('api route returns zip file for authenticated user', function (): void { $response->assertHeader('Content-Disposition', 'attachment; filename=plugin_api-test-404.zip'); }); -it('api route returns 404 for non-existent plugin', function (): void { +it('api route returns 404 for non-existent plugin', function () { $user = User::factory()->create(); $response = $this->actingAs($user) @@ -197,13 +197,13 @@ it('api route returns 404 for non-existent plugin', function (): void { $response->assertStatus(404); }); -it('api route returns 401 for unauthenticated user', function (): void { +it('api route returns 401 for unauthenticated user', function () { $response = $this->getJson('/api/plugin_settings/test-id/archive'); $response->assertStatus(401); }); -it('api route returns 404 for plugin belonging to different user', function (): void { +it('api route returns 404 for plugin belonging to different user', function () { $user1 = User::factory()->create(); $user2 = User::factory()->create(); $plugin = Plugin::factory()->create([ @@ -217,7 +217,7 @@ it('api route returns 404 for plugin belonging to different user', function (): $response->assertStatus(404); }); -it('exports zip with files in root directory', function (): void { +it('exports zip with files in root directory', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, @@ -243,7 +243,7 @@ it('exports zip with files in root directory', function (): void { $zip->close(); }); -it('maintains correct yaml field order', function (): void { +it('maintains correct yaml field order', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ 'user_id' => $user->id, diff --git a/tests/Feature/PluginDefaultValuesTest.php b/tests/Feature/PluginDefaultValuesTest.php index 353ad0c..30f62c0 100644 --- a/tests/Feature/PluginDefaultValuesTest.php +++ b/tests/Feature/PluginDefaultValuesTest.php @@ -6,7 +6,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('plugin import extracts default values from custom_fields and stores in configuration', function (): void { +test('plugin import extracts default values from custom_fields and stores in configuration', function () { // Create a user $user = User::factory()->create(); @@ -74,7 +74,7 @@ test('plugin import extracts default values from custom_fields and stores in con expect($plugin->configuration_template['custom_fields'])->toHaveCount(3); }); -test('plugin import handles custom_fields without default values', function (): void { +test('plugin import handles custom_fields without default values', function () { // Create a user $user = User::factory()->create(); diff --git a/tests/Feature/PluginImportTest.php b/tests/Feature/PluginImportTest.php index 5c4a31f..86b9220 100644 --- a/tests/Feature/PluginImportTest.php +++ b/tests/Feature/PluginImportTest.php @@ -9,11 +9,11 @@ use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; -beforeEach(function (): void { +beforeEach(function () { Storage::fake('local'); }); -it('imports plugin from valid zip file', function (): void { +it('imports plugin from valid zip file', function () { $user = User::factory()->create(); // Create a mock ZIP file with the required structure @@ -38,7 +38,7 @@ it('imports plugin from valid zip file', function (): void { ->and($plugin->configuration['api_key'])->toBe('default-api-key'); }); -it('imports plugin with shared.liquid file', function (): void { +it('imports plugin with shared.liquid file', function () { $user = User::factory()->create(); $zipContent = createMockZipFile([ @@ -56,7 +56,7 @@ it('imports plugin with shared.liquid file', function (): void { ->and($plugin->render_markup)->toContain('
'); }); -it('imports plugin with files in root directory', function (): void { +it('imports plugin with files in root directory', function () { $user = User::factory()->create(); $zipContent = createMockZipFile([ @@ -73,17 +73,17 @@ it('imports plugin with files in root directory', function (): void { ->and($plugin->name)->toBe('Test Plugin'); }); -it('throws exception for invalid zip file', function (): void { +it('throws exception for invalid zip file', function () { $user = User::factory()->create(); $zipFile = UploadedFile::fake()->createWithContent('invalid.zip', 'not a zip file'); $pluginImportService = new PluginImportService(); - expect(fn (): Plugin => $pluginImportService->importFromZip($zipFile, $user)) + expect(fn () => $pluginImportService->importFromZip($zipFile, $user)) ->toThrow(Exception::class, 'Could not open the ZIP file.'); }); -it('throws exception for missing required files', function (): void { +it('throws exception for missing required files', function () { $user = User::factory()->create(); $zipContent = createMockZipFile([ @@ -94,11 +94,11 @@ it('throws exception for missing required files', function (): void { $zipFile = UploadedFile::fake()->createWithContent('test-plugin.zip', $zipContent); $pluginImportService = new PluginImportService(); - expect(fn (): Plugin => $pluginImportService->importFromZip($zipFile, $user)) + expect(fn () => $pluginImportService->importFromZip($zipFile, $user)) ->toThrow(Exception::class, 'Invalid ZIP structure. Required files settings.yml and full.liquid are missing.'); }); -it('sets default values when settings are missing', function (): void { +it('sets default values when settings are missing', function () { $user = User::factory()->create(); $zipContent = createMockZipFile([ @@ -117,7 +117,7 @@ it('sets default values when settings are missing', function (): void { ->and($plugin->polling_verb)->toBe('get'); // default value }); -it('handles blade markup language correctly', function (): void { +it('handles blade markup language correctly', function () { $user = User::factory()->create(); $zipContent = createMockZipFile([ @@ -133,7 +133,7 @@ it('handles blade markup language correctly', function (): void { expect($plugin->markup_language)->toBe('blade'); }); -it('imports plugin from monorepo with zip_entry_path parameter', function (): void { +it('imports plugin from monorepo with zip_entry_path parameter', function () { $user = User::factory()->create(); // Create a mock ZIP file with plugin in a subdirectory @@ -152,7 +152,7 @@ it('imports plugin from monorepo with zip_entry_path parameter', function (): vo ->and($plugin->name)->toBe('Test Plugin'); }); -it('imports plugin from monorepo with src subdirectory', function (): void { +it('imports plugin from monorepo with src subdirectory', function () { $user = User::factory()->create(); // Create a mock ZIP file with plugin in a subdirectory with src folder @@ -171,7 +171,7 @@ it('imports plugin from monorepo with src subdirectory', function (): void { ->and($plugin->name)->toBe('Test Plugin'); }); -it('imports plugin from monorepo with shared.liquid in subdirectory', function (): void { +it('imports plugin from monorepo with shared.liquid in subdirectory', function () { $user = User::factory()->create(); $zipContent = createMockZipFile([ @@ -189,7 +189,7 @@ it('imports plugin from monorepo with shared.liquid in subdirectory', function ( ->and($plugin->render_markup)->toContain('
'); }); -it('imports plugin from URL with zip_entry_path parameter', function (): void { +it('imports plugin from URL with zip_entry_path parameter', function () { $user = User::factory()->create(); // Create a mock ZIP file with plugin in a subdirectory @@ -214,10 +214,12 @@ it('imports plugin from URL with zip_entry_path parameter', function (): void { ->and($plugin->user_id)->toBe($user->id) ->and($plugin->name)->toBe('Test Plugin'); - Http::assertSent(fn ($request): bool => $request->url() === 'https://github.com/example/repo/archive/refs/heads/main.zip'); + Http::assertSent(function ($request) { + return $request->url() === 'https://github.com/example/repo/archive/refs/heads/main.zip'; + }); }); -it('imports plugin from URL with zip_entry_path and src subdirectory', function (): void { +it('imports plugin from URL with zip_entry_path and src subdirectory', function () { $user = User::factory()->create(); // Create a mock ZIP file with plugin in a subdirectory with src folder @@ -243,7 +245,7 @@ it('imports plugin from URL with zip_entry_path and src subdirectory', function ->and($plugin->name)->toBe('Test Plugin'); }); -it('imports plugin from GitHub monorepo with repository-named directory', function (): void { +it('imports plugin from GitHub monorepo with repository-named directory', function () { $user = User::factory()->create(); // Create a mock ZIP file that simulates GitHub's ZIP structure with repository-named directory @@ -271,7 +273,7 @@ it('imports plugin from GitHub monorepo with repository-named directory', functi ->and($plugin->name)->toBe('Test Plugin'); // Should be from example-plugin, not other-plugin }); -it('finds required files in simple ZIP structure', function (): void { +it('finds required files in simple ZIP structure', function () { $user = User::factory()->create(); // Create a simple ZIP file with just one plugin @@ -290,7 +292,7 @@ it('finds required files in simple ZIP structure', function (): void { ->and($plugin->name)->toBe('Test Plugin'); }); -it('finds required files in GitHub monorepo structure with zip_entry_path', function (): void { +it('finds required files in GitHub monorepo structure with zip_entry_path', function () { $user = User::factory()->create(); // Create a mock ZIP file that simulates GitHub's ZIP structure @@ -311,7 +313,7 @@ it('finds required files in GitHub monorepo structure with zip_entry_path', func ->and($plugin->name)->toBe('Test Plugin'); // Should be from example-plugin, not other-plugin }); -it('imports specific plugin from monorepo zip with zip_entry_path parameter', function (): void { +it('imports specific plugin from monorepo zip with zip_entry_path parameter', function () { $user = User::factory()->create(); // Create a mock ZIP file with 2 plugins in a monorepo structure diff --git a/tests/Feature/PluginInlineTemplatesTest.php b/tests/Feature/PluginInlineTemplatesTest.php index 76b29d7..fb35344 100644 --- a/tests/Feature/PluginInlineTemplatesTest.php +++ b/tests/Feature/PluginInlineTemplatesTest.php @@ -5,7 +5,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('renders plugin with inline templates', function (): void { +test('renders plugin with inline templates', function () { $plugin = Plugin::factory()->create([ 'name' => 'Test Plugin', 'markup_language' => 'liquid', @@ -61,16 +61,16 @@ LIQUID // Should render both templates // Check for any of the facts (since random number generation is non-deterministic) $this->assertTrue( - str_contains((string) $result, 'Fact 1') || - str_contains((string) $result, 'Fact 2') || - str_contains((string) $result, 'Fact 3') + str_contains($result, 'Fact 1') || + str_contains($result, 'Fact 2') || + str_contains($result, 'Fact 3') ); $this->assertStringContainsString('Test Plugin', $result); $this->assertStringContainsString('Please try to enjoy each fact equally', $result); $this->assertStringContainsString('class="view view--full"', $result); }); -test('renders plugin with inline templates using with syntax', function (): void { +test('renders plugin with inline templates using with syntax', function () { $plugin = Plugin::factory()->create([ 'name' => 'Test Plugin', 'markup_language' => 'liquid', @@ -127,16 +127,16 @@ LIQUID // Should render both templates // Check for any of the facts (since random number generation is non-deterministic) $this->assertTrue( - str_contains((string) $result, 'Fact 1') || - str_contains((string) $result, 'Fact 2') || - str_contains((string) $result, 'Fact 3') + str_contains($result, 'Fact 1') || + str_contains($result, 'Fact 2') || + str_contains($result, 'Fact 3') ); $this->assertStringContainsString('Test Plugin', $result); $this->assertStringContainsString('Please try to enjoy each fact equally', $result); $this->assertStringContainsString('class="view view--full"', $result); }); -test('renders plugin with simple inline template', function (): void { +test('renders plugin with simple inline template', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' @@ -162,7 +162,7 @@ LIQUID $this->assertStringContainsString('class="simple"', $result); }); -test('renders plugin with liquid filter find_by', function (): void { +test('renders plugin with liquid filter find_by', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' @@ -194,7 +194,7 @@ LIQUID $this->assertStringContainsString('class="user"', $result); }); -test('renders plugin with liquid filter find_by and fallback', function (): void { +test('renders plugin with liquid filter find_by and fallback', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' @@ -216,7 +216,7 @@ LIQUID $this->assertStringContainsString('Not Found', $result); }); -test('renders plugin with liquid filter group_by', function (): void { +test('renders plugin with liquid filter group_by', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' diff --git a/tests/Feature/PluginLiquidFilterTest.php b/tests/Feature/PluginLiquidFilterTest.php index bc0fc18..fb429ae 100644 --- a/tests/Feature/PluginLiquidFilterTest.php +++ b/tests/Feature/PluginLiquidFilterTest.php @@ -14,7 +14,7 @@ use Keepsuit\Liquid\Environment; * to: * {% assign _temp_xxx = collection | filter: "key", "value" %}{% for item in _temp_xxx %} */ -test('where filter works when assigned to variable first', function (): void { +test('where filter works when assigned to variable first', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' @@ -42,7 +42,7 @@ LIQUID $this->assertStringNotContainsString('"type":"L"', $result); }); -test('where filter works directly in for loop with preprocessing', function (): void { +test('where filter works directly in for loop with preprocessing', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' @@ -68,7 +68,7 @@ LIQUID $this->assertStringNotContainsString('"type":"L"', $result); }); -test('where filter works directly in for loop with multiple matches', function (): void { +test('where filter works directly in for loop with multiple matches', function () { $plugin = Plugin::factory()->create([ 'markup_language' => 'liquid', 'render_markup' => <<<'LIQUID' @@ -95,7 +95,7 @@ LIQUID $this->assertStringNotContainsString('"type":"L"', $result); }); -it('encodes arrays for url_encode as JSON with spaces after commas and then percent-encodes', function (): void { +it('encodes arrays for url_encode as JSON with spaces after commas and then percent-encodes', function () { /** @var Environment $env */ $env = app('liquid.environment'); $env->filterRegistry->register(StandardFilters::class); @@ -109,7 +109,7 @@ it('encodes arrays for url_encode as JSON with spaces after commas and then perc expect($output)->toBe('%5B%22common%22%2C%22obscure%22%5D'); }); -it('keeps scalar url_encode behavior intact', function (): void { +it('keeps scalar url_encode behavior intact', function () { /** @var Environment $env */ $env = app('liquid.environment'); $env->filterRegistry->register(StandardFilters::class); diff --git a/tests/Feature/PluginRequiredConfigurationTest.php b/tests/Feature/PluginRequiredConfigurationTest.php index 83be449..552b996 100644 --- a/tests/Feature/PluginRequiredConfigurationTest.php +++ b/tests/Feature/PluginRequiredConfigurationTest.php @@ -6,7 +6,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('hasMissingRequiredConfigurationFields returns true when required field is null', function (): void { +test('hasMissingRequiredConfigurationFields returns true when required field is null', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -39,7 +39,7 @@ test('hasMissingRequiredConfigurationFields returns true when required field is expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); }); -test('hasMissingRequiredConfigurationFields returns false when all required fields are set', function (): void { +test('hasMissingRequiredConfigurationFields returns false when all required fields are set', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -73,7 +73,7 @@ test('hasMissingRequiredConfigurationFields returns false when all required fiel expect($plugin->hasMissingRequiredConfigurationFields())->toBeFalse(); }); -test('hasMissingRequiredConfigurationFields returns false when no custom fields exist', function (): void { +test('hasMissingRequiredConfigurationFields returns false when no custom fields exist', function () { $user = User::factory()->create(); $plugin = Plugin::factory()->create([ @@ -85,7 +85,7 @@ test('hasMissingRequiredConfigurationFields returns false when no custom fields expect($plugin->hasMissingRequiredConfigurationFields())->toBeFalse(); }); -test('hasMissingRequiredConfigurationFields returns true when explicitly required field is null', function (): void { +test('hasMissingRequiredConfigurationFields returns true when explicitly required field is null', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -111,7 +111,7 @@ test('hasMissingRequiredConfigurationFields returns true when explicitly require expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); }); -test('hasMissingRequiredConfigurationFields returns true when required field is empty string', function (): void { +test('hasMissingRequiredConfigurationFields returns true when required field is empty string', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -137,7 +137,7 @@ test('hasMissingRequiredConfigurationFields returns true when required field is expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); }); -test('hasMissingRequiredConfigurationFields returns true when required array field is empty', function (): void { +test('hasMissingRequiredConfigurationFields returns true when required array field is empty', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -164,7 +164,7 @@ test('hasMissingRequiredConfigurationFields returns true when required array fie expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); }); -test('hasMissingRequiredConfigurationFields returns false when author_bio field is present but other required field is set', function (): void { +test('hasMissingRequiredConfigurationFields returns false when author_bio field is present but other required field is set', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -193,7 +193,7 @@ test('hasMissingRequiredConfigurationFields returns false when author_bio field expect($plugin->hasMissingRequiredConfigurationFields())->toBeFalse(); }); -test('hasMissingRequiredConfigurationFields returns false when field has default value', function (): void { +test('hasMissingRequiredConfigurationFields returns false when field has default value', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -217,7 +217,7 @@ test('hasMissingRequiredConfigurationFields returns false when field has default expect($plugin->hasMissingRequiredConfigurationFields())->toBeFalse(); }); -test('hasMissingRequiredConfigurationFields returns true when required xhrSelect field is missing', function (): void { +test('hasMissingRequiredConfigurationFields returns true when required xhrSelect field is missing', function () { $user = User::factory()->create(); $configurationTemplate = [ @@ -242,7 +242,7 @@ test('hasMissingRequiredConfigurationFields returns true when required xhrSelect expect($plugin->hasMissingRequiredConfigurationFields())->toBeTrue(); }); -test('hasMissingRequiredConfigurationFields returns false when required xhrSelect field is set', function (): void { +test('hasMissingRequiredConfigurationFields returns false when required xhrSelect field is set', function () { $user = User::factory()->create(); $configurationTemplate = [ diff --git a/tests/Feature/PluginWebhookTest.php b/tests/Feature/PluginWebhookTest.php index 22d1d54..70fa53a 100644 --- a/tests/Feature/PluginWebhookTest.php +++ b/tests/Feature/PluginWebhookTest.php @@ -3,7 +3,7 @@ use App\Models\Plugin; use Illuminate\Support\Str; -test('webhook updates plugin data for webhook strategy', function (): void { +test('webhook updates plugin data for webhook strategy', function () { // Create a plugin with webhook strategy $plugin = Plugin::factory()->create([ 'data_strategy' => 'webhook', @@ -26,7 +26,7 @@ test('webhook updates plugin data for webhook strategy', function (): void { ]); }); -test('webhook returns 400 for non-webhook strategy plugins', function (): void { +test('webhook returns 400 for non-webhook strategy plugins', function () { // Create a plugin with non-webhook strategy $plugin = Plugin::factory()->create([ 'data_strategy' => 'polling', @@ -43,7 +43,7 @@ test('webhook returns 400 for non-webhook strategy plugins', function (): void { ->assertJson(['error' => 'Plugin does not use webhook strategy']); }); -test('webhook returns 400 when merge_variables is missing', function (): void { +test('webhook returns 400 when merge_variables is missing', function () { // Create a plugin with webhook strategy $plugin = Plugin::factory()->create([ 'data_strategy' => 'webhook', @@ -58,7 +58,7 @@ test('webhook returns 400 when merge_variables is missing', function (): void { ->assertJson(['error' => 'Request must contain merge_variables key']); }); -test('webhook returns 404 for non-existent plugin', function (): void { +test('webhook returns 404 for non-existent plugin', function () { // Make request with non-existent plugin UUID $response = $this->postJson('/api/custom_plugins/'.Str::uuid(), [ 'merge_variables' => ['new' => 'data'], diff --git a/tests/Feature/Settings/PasswordUpdateTest.php b/tests/Feature/Settings/PasswordUpdateTest.php index 0e33955..3252860 100644 --- a/tests/Feature/Settings/PasswordUpdateTest.php +++ b/tests/Feature/Settings/PasswordUpdateTest.php @@ -6,7 +6,7 @@ use Livewire\Volt\Volt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('password can be updated', function (): void { +test('password can be updated', function () { $user = User::factory()->create([ 'password' => Hash::make('password'), ]); @@ -24,7 +24,7 @@ test('password can be updated', function (): void { expect(Hash::check('new-password', $user->refresh()->password))->toBeTrue(); }); -test('correct password must be provided to update password', function (): void { +test('correct password must be provided to update password', function () { $user = User::factory()->create([ 'password' => Hash::make('password'), ]); diff --git a/tests/Feature/Settings/ProfileUpdateTest.php b/tests/Feature/Settings/ProfileUpdateTest.php index cbf424c..48ea114 100644 --- a/tests/Feature/Settings/ProfileUpdateTest.php +++ b/tests/Feature/Settings/ProfileUpdateTest.php @@ -5,13 +5,13 @@ use Livewire\Volt\Volt; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('profile page is displayed', function (): void { +test('profile page is displayed', function () { $this->actingAs($user = User::factory()->create()); $this->get('/settings/profile')->assertOk(); }); -test('profile information can be updated', function (): void { +test('profile information can be updated', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -30,7 +30,7 @@ test('profile information can be updated', function (): void { expect($user->email_verified_at)->toBeNull(); }); -test('email verification status is unchanged when email address is unchanged', function (): void { +test('email verification status is unchanged when email address is unchanged', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -45,7 +45,7 @@ test('email verification status is unchanged when email address is unchanged', f expect($user->refresh()->email_verified_at)->not->toBeNull(); }); -test('user can delete their account', function (): void { +test('user can delete their account', function () { $user = User::factory()->create(); $this->actingAs($user); @@ -62,7 +62,7 @@ test('user can delete their account', function (): void { expect(auth()->check())->toBeFalse(); }); -test('correct password must be provided to delete account', function (): void { +test('correct password must be provided to delete account', function () { $user = User::factory()->create(); $this->actingAs($user); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php index 963bc0c..44a4f33 100644 --- a/tests/Unit/ExampleTest.php +++ b/tests/Unit/ExampleTest.php @@ -1,5 +1,5 @@ toBeTrue(); }); diff --git a/tests/Unit/Liquid/Filters/DataTest.php b/tests/Unit/Liquid/Filters/DataTest.php index abd4114..bdf649f 100644 --- a/tests/Unit/Liquid/Filters/DataTest.php +++ b/tests/Unit/Liquid/Filters/DataTest.php @@ -2,14 +2,14 @@ use App\Liquid\Filters\Data; -test('json filter converts arrays to JSON', function (): void { +test('json filter converts arrays to JSON', function () { $filter = new Data(); $array = ['foo' => 'bar', 'baz' => 'qux']; expect($filter->json($array))->toBe('{"foo":"bar","baz":"qux"}'); }); -test('json filter converts objects to JSON', function (): void { +test('json filter converts objects to JSON', function () { $filter = new Data(); $object = new stdClass(); $object->foo = 'bar'; @@ -18,7 +18,7 @@ test('json filter converts objects to JSON', function (): void { expect($filter->json($object))->toBe('{"foo":"bar","baz":"qux"}'); }); -test('json filter handles nested structures', function (): void { +test('json filter handles nested structures', function () { $filter = new Data(); $nested = [ 'foo' => 'bar', @@ -31,7 +31,7 @@ test('json filter handles nested structures', function (): void { expect($filter->json($nested))->toBe('{"foo":"bar","nested":{"baz":"qux","items":[1,2,3]}}'); }); -test('json filter handles scalar values', function (): void { +test('json filter handles scalar values', function () { $filter = new Data(); expect($filter->json('string'))->toBe('"string"'); @@ -40,21 +40,21 @@ test('json filter handles scalar values', function (): void { expect($filter->json(null))->toBe('null'); }); -test('json filter preserves unicode characters', function (): void { +test('json filter preserves unicode characters', function () { $filter = new Data(); $data = ['message' => 'Hello, 世界']; expect($filter->json($data))->toBe('{"message":"Hello, 世界"}'); }); -test('json filter does not escape slashes', function (): void { +test('json filter does not escape slashes', function () { $filter = new Data(); $data = ['url' => 'https://example.com/path']; expect($filter->json($data))->toBe('{"url":"https://example.com/path"}'); }); -test('find_by filter finds object by key-value pair', function (): void { +test('find_by filter finds object by key-value pair', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'age' => 35], @@ -66,7 +66,7 @@ test('find_by filter finds object by key-value pair', function (): void { expect($result)->toBe(['name' => 'Ryan', 'age' => 35]); }); -test('find_by filter returns null when no match found', function (): void { +test('find_by filter returns null when no match found', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'age' => 35], @@ -78,7 +78,7 @@ test('find_by filter returns null when no match found', function (): void { expect($result)->toBeNull(); }); -test('find_by filter returns fallback when no match found', function (): void { +test('find_by filter returns fallback when no match found', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'age' => 35], @@ -90,7 +90,7 @@ test('find_by filter returns fallback when no match found', function (): void { expect($result)->toBe('Not Found'); }); -test('find_by filter finds by age', function (): void { +test('find_by filter finds by age', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'age' => 35], @@ -102,7 +102,7 @@ test('find_by filter finds by age', function (): void { expect($result)->toBe(['name' => 'Sara', 'age' => 29]); }); -test('find_by filter handles empty collection', function (): void { +test('find_by filter handles empty collection', function () { $filter = new Data(); $collection = []; @@ -110,7 +110,7 @@ test('find_by filter handles empty collection', function (): void { expect($result)->toBeNull(); }); -test('find_by filter handles collection with non-array items', function (): void { +test('find_by filter handles collection with non-array items', function () { $filter = new Data(); $collection = [ 'not an array', @@ -122,7 +122,7 @@ test('find_by filter handles collection with non-array items', function (): void expect($result)->toBe(['name' => 'Ryan', 'age' => 35]); }); -test('find_by filter handles items without the specified key', function (): void { +test('find_by filter handles items without the specified key', function () { $filter = new Data(); $collection = [ ['age' => 35], @@ -134,7 +134,7 @@ test('find_by filter handles items without the specified key', function (): void expect($result)->toBe(['name' => 'Ryan', 'age' => 35]); }); -test('group_by filter groups collection by age', function (): void { +test('group_by filter groups collection by age', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'age' => 35], @@ -153,7 +153,7 @@ test('group_by filter groups collection by age', function (): void { ]); }); -test('group_by filter groups collection by name', function (): void { +test('group_by filter groups collection by name', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'age' => 35], @@ -172,7 +172,7 @@ test('group_by filter groups collection by name', function (): void { ]); }); -test('group_by filter handles empty collection', function (): void { +test('group_by filter handles empty collection', function () { $filter = new Data(); $collection = []; @@ -180,7 +180,7 @@ test('group_by filter handles empty collection', function (): void { expect($result)->toBe([]); }); -test('group_by filter handles collection with non-array items', function (): void { +test('group_by filter handles collection with non-array items', function () { $filter = new Data(); $collection = [ 'not an array', @@ -197,7 +197,7 @@ test('group_by filter handles collection with non-array items', function (): voi ]); }); -test('group_by filter handles items without the specified key', function (): void { +test('group_by filter handles items without the specified key', function () { $filter = new Data(); $collection = [ ['age' => 35], @@ -217,7 +217,7 @@ test('group_by filter handles items without the specified key', function (): voi ]); }); -test('group_by filter handles mixed data types as keys', function (): void { +test('group_by filter handles mixed data types as keys', function () { $filter = new Data(); $collection = [ ['name' => 'Ryan', 'active' => true], @@ -238,7 +238,7 @@ test('group_by filter handles mixed data types as keys', function (): void { ]); }); -test('sample filter returns a random element from array', function (): void { +test('sample filter returns a random element from array', function () { $filter = new Data(); $array = ['1', '2', '3', '4', '5']; @@ -246,7 +246,7 @@ test('sample filter returns a random element from array', function (): void { expect($result)->toBeIn($array); }); -test('sample filter returns a random element from string array', function (): void { +test('sample filter returns a random element from string array', function () { $filter = new Data(); $array = ['cat', 'dog']; @@ -254,7 +254,7 @@ test('sample filter returns a random element from string array', function (): vo expect($result)->toBeIn($array); }); -test('sample filter returns null for empty array', function (): void { +test('sample filter returns null for empty array', function () { $filter = new Data(); $array = []; @@ -262,7 +262,7 @@ test('sample filter returns null for empty array', function (): void { expect($result)->toBeNull(); }); -test('sample filter returns the only element from single element array', function (): void { +test('sample filter returns the only element from single element array', function () { $filter = new Data(); $array = ['single']; @@ -270,7 +270,7 @@ test('sample filter returns the only element from single element array', functio expect($result)->toBe('single'); }); -test('sample filter works with mixed data types', function (): void { +test('sample filter works with mixed data types', function () { $filter = new Data(); $array = [1, 'string', true, null, ['nested']]; @@ -278,7 +278,7 @@ test('sample filter works with mixed data types', function (): void { expect($result)->toBeIn($array); }); -test('parse_json filter parses JSON string to array', function (): void { +test('parse_json filter parses JSON string to array', function () { $filter = new Data(); $jsonString = '[{"a":1,"b":"c"},"d"]'; @@ -286,7 +286,7 @@ test('parse_json filter parses JSON string to array', function (): void { expect($result)->toBe([['a' => 1, 'b' => 'c'], 'd']); }); -test('parse_json filter parses simple JSON object', function (): void { +test('parse_json filter parses simple JSON object', function () { $filter = new Data(); $jsonString = '{"name":"John","age":30,"city":"New York"}'; @@ -294,7 +294,7 @@ test('parse_json filter parses simple JSON object', function (): void { expect($result)->toBe(['name' => 'John', 'age' => 30, 'city' => 'New York']); }); -test('parse_json filter parses JSON array', function (): void { +test('parse_json filter parses JSON array', function () { $filter = new Data(); $jsonString = '["apple","banana","cherry"]'; @@ -302,7 +302,7 @@ test('parse_json filter parses JSON array', function (): void { expect($result)->toBe(['apple', 'banana', 'cherry']); }); -test('parse_json filter parses nested JSON structure', function (): void { +test('parse_json filter parses nested JSON structure', function () { $filter = new Data(); $jsonString = '{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}],"total":2}'; @@ -316,7 +316,7 @@ test('parse_json filter parses nested JSON structure', function (): void { ]); }); -test('parse_json filter handles primitive values', function (): void { +test('parse_json filter handles primitive values', function () { $filter = new Data(); expect($filter->parse_json('"hello"'))->toBe('hello'); diff --git a/tests/Unit/Liquid/Filters/DateTest.php b/tests/Unit/Liquid/Filters/DateTest.php index d967951..5813e10 100644 --- a/tests/Unit/Liquid/Filters/DateTest.php +++ b/tests/Unit/Liquid/Filters/DateTest.php @@ -3,28 +3,28 @@ use App\Liquid\Filters\Date; use Carbon\Carbon; -test('days_ago filter returns correct date', function (): void { +test('days_ago filter returns correct date', function () { $filter = new Date(); $threeDaysAgo = Carbon::now()->subDays(3)->toDateString(); expect($filter->days_ago(3))->toBe($threeDaysAgo); }); -test('days_ago filter handles string input', function (): void { +test('days_ago filter handles string input', function () { $filter = new Date(); $fiveDaysAgo = Carbon::now()->subDays(5)->toDateString(); expect($filter->days_ago('5'))->toBe($fiveDaysAgo); }); -test('days_ago filter with zero days returns today', function (): void { +test('days_ago filter with zero days returns today', function () { $filter = new Date(); $today = Carbon::now()->toDateString(); expect($filter->days_ago(0))->toBe($today); }); -test('days_ago filter with large number works correctly', function (): void { +test('days_ago filter with large number works correctly', function () { $filter = new Date(); $hundredDaysAgo = Carbon::now()->subDays(100)->toDateString(); diff --git a/tests/Unit/Liquid/Filters/LocalizationTest.php b/tests/Unit/Liquid/Filters/LocalizationTest.php index a52623f..2ba3dd2 100644 --- a/tests/Unit/Liquid/Filters/LocalizationTest.php +++ b/tests/Unit/Liquid/Filters/LocalizationTest.php @@ -2,7 +2,7 @@ use App\Liquid\Filters\Localization; -test('l_date formats date with default format', function (): void { +test('l_date formats date with default format', function () { $filter = new Localization(); $date = '2025-01-11'; @@ -15,7 +15,7 @@ test('l_date formats date with default format', function (): void { expect($result)->toContain('11'); }); -test('l_date formats date with custom format', function (): void { +test('l_date formats date with custom format', function () { $filter = new Localization(); $date = '2025-01-11'; @@ -27,7 +27,7 @@ test('l_date formats date with custom format', function (): void { // We can't check for 'Jan' specifically as it might be localized }); -test('l_date handles DateTime objects', function (): void { +test('l_date handles DateTime objects', function () { $filter = new Localization(); $date = new DateTimeImmutable('2025-01-11'); @@ -36,32 +36,32 @@ test('l_date handles DateTime objects', function (): void { expect($result)->toContain('2025-01-11'); }); -test('l_word translates common words', function (): void { +test('l_word translates common words', function () { $filter = new Localization(); expect($filter->l_word('today', 'de'))->toBe('heute'); }); -test('l_word returns original word if no translation exists', function (): void { +test('l_word returns original word if no translation exists', function () { $filter = new Localization(); expect($filter->l_word('hello', 'es-ES'))->toBe('hello'); expect($filter->l_word('world', 'ko'))->toBe('world'); }); -test('l_word is case-insensitive', function (): void { +test('l_word is case-insensitive', function () { $filter = new Localization(); expect($filter->l_word('TODAY', 'de'))->toBe('heute'); }); -test('l_word returns original word for unknown locales', function (): void { +test('l_word returns original word for unknown locales', function () { $filter = new Localization(); expect($filter->l_word('today', 'unknown-locale'))->toBe('today'); }); -test('l_date handles locale parameter', function (): void { +test('l_date handles locale parameter', function () { $filter = new Localization(); $date = '2025-01-11'; @@ -73,7 +73,7 @@ test('l_date handles locale parameter', function (): void { expect($result)->toContain('11'); }); -test('l_date handles null locale parameter', function (): void { +test('l_date handles null locale parameter', function () { $filter = new Localization(); $date = '2025-01-11'; @@ -85,7 +85,7 @@ test('l_date handles null locale parameter', function (): void { expect($result)->toContain('11'); }); -test('l_date handles different date formats with locale', function (): void { +test('l_date handles different date formats with locale', function () { $filter = new Localization(); $date = '2025-01-11'; @@ -96,7 +96,7 @@ test('l_date handles different date formats with locale', function (): void { expect($result)->toContain('11'); }); -test('l_date handles DateTimeInterface objects with locale', function (): void { +test('l_date handles DateTimeInterface objects with locale', function () { $filter = new Localization(); $date = new DateTimeImmutable('2025-01-11'); @@ -108,29 +108,29 @@ test('l_date handles DateTimeInterface objects with locale', function (): void { expect($result)->toContain('11'); }); -test('l_date handles invalid date gracefully', function (): void { +test('l_date handles invalid date gracefully', function () { $filter = new Localization(); $invalidDate = 'invalid-date'; // This should throw an exception or return a default value // The exact behavior depends on Carbon's implementation - expect(fn (): string => $filter->l_date($invalidDate))->toThrow(Exception::class); + expect(fn () => $filter->l_date($invalidDate))->toThrow(Exception::class); }); -test('l_word handles empty string', function (): void { +test('l_word handles empty string', function () { $filter = new Localization(); expect($filter->l_word('', 'de'))->toBe(''); }); -test('l_word handles special characters', function (): void { +test('l_word handles special characters', function () { $filter = new Localization(); // Test with a word that has special characters expect($filter->l_word('café', 'de'))->toBe('café'); }); -test('l_word handles numeric strings', function (): void { +test('l_word handles numeric strings', function () { $filter = new Localization(); expect($filter->l_word('123', 'de'))->toBe('123'); diff --git a/tests/Unit/Liquid/Filters/NumbersTest.php b/tests/Unit/Liquid/Filters/NumbersTest.php index 42deffb..7ce736a 100644 --- a/tests/Unit/Liquid/Filters/NumbersTest.php +++ b/tests/Unit/Liquid/Filters/NumbersTest.php @@ -2,7 +2,7 @@ use App\Liquid\Filters\Numbers; -test('number_with_delimiter formats numbers with commas by default', function (): void { +test('number_with_delimiter formats numbers with commas by default', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(1234))->toBe('1,234'); @@ -10,21 +10,21 @@ test('number_with_delimiter formats numbers with commas by default', function () expect($filter->number_with_delimiter(0))->toBe('0'); }); -test('number_with_delimiter handles custom delimiters', function (): void { +test('number_with_delimiter handles custom delimiters', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(1234, '.'))->toBe('1.234'); expect($filter->number_with_delimiter(1000000, ' '))->toBe('1 000 000'); }); -test('number_with_delimiter handles decimal values with custom separators', function (): void { +test('number_with_delimiter handles decimal values with custom separators', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(1234.57, ' ', ','))->toBe('1 234,57'); expect($filter->number_with_delimiter(1234.5, '.', ','))->toBe('1.234,50'); }); -test('number_to_currency formats numbers with dollar sign by default', function (): void { +test('number_to_currency formats numbers with dollar sign by default', function () { $filter = new Numbers(); expect($filter->number_to_currency(1234))->toBe('$1,234'); @@ -32,14 +32,14 @@ test('number_to_currency formats numbers with dollar sign by default', function expect($filter->number_to_currency(0))->toBe('$0'); }); -test('number_to_currency handles custom currency symbols', function (): void { +test('number_to_currency handles custom currency symbols', function () { $filter = new Numbers(); expect($filter->number_to_currency(1234, '£'))->toBe('£1,234'); expect($filter->number_to_currency(152350.69, '€'))->toBe('€152,350.69'); }); -test('number_to_currency handles custom delimiters and separators', function (): void { +test('number_to_currency handles custom delimiters and separators', function () { $filter = new Numbers(); $result1 = $filter->number_to_currency(1234.57, '£', '.', ','); @@ -51,56 +51,56 @@ test('number_to_currency handles custom delimiters and separators', function (): expect($result2)->toContain('€'); }); -test('number_with_delimiter handles string numbers', function (): void { +test('number_with_delimiter handles string numbers', function () { $filter = new Numbers(); expect($filter->number_with_delimiter('1234'))->toBe('1,234'); expect($filter->number_with_delimiter('1234.56'))->toBe('1,234.56'); }); -test('number_with_delimiter handles negative numbers', function (): void { +test('number_with_delimiter handles negative numbers', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(-1234))->toBe('-1,234'); expect($filter->number_with_delimiter(-1234.56))->toBe('-1,234.56'); }); -test('number_with_delimiter handles zero', function (): void { +test('number_with_delimiter handles zero', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(0))->toBe('0'); expect($filter->number_with_delimiter(0.0))->toBe('0.00'); }); -test('number_with_delimiter handles very small numbers', function (): void { +test('number_with_delimiter handles very small numbers', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(0.01))->toBe('0.01'); expect($filter->number_with_delimiter(0.001))->toBe('0.00'); }); -test('number_to_currency handles string numbers', function (): void { +test('number_to_currency handles string numbers', function () { $filter = new Numbers(); expect($filter->number_to_currency('1234'))->toBe('$1,234'); expect($filter->number_to_currency('1234.56'))->toBe('$1,234.56'); }); -test('number_to_currency handles negative numbers', function (): void { +test('number_to_currency handles negative numbers', function () { $filter = new Numbers(); expect($filter->number_to_currency(-1234))->toBe('-$1,234'); expect($filter->number_to_currency(-1234.56))->toBe('-$1,234.56'); }); -test('number_to_currency handles zero', function (): void { +test('number_to_currency handles zero', function () { $filter = new Numbers(); expect($filter->number_to_currency(0))->toBe('$0'); expect($filter->number_to_currency(0.0))->toBe('$0.00'); }); -test('number_to_currency handles currency code conversion', function (): void { +test('number_to_currency handles currency code conversion', function () { $filter = new Numbers(); expect($filter->number_to_currency(1234, '$'))->toBe('$1,234'); @@ -108,7 +108,7 @@ test('number_to_currency handles currency code conversion', function (): void { expect($filter->number_to_currency(1234, '£'))->toBe('£1,234'); }); -test('number_to_currency handles German locale formatting', function (): void { +test('number_to_currency handles German locale formatting', function () { $filter = new Numbers(); // When delimiter is '.' and separator is ',', it should use German locale @@ -116,21 +116,21 @@ test('number_to_currency handles German locale formatting', function (): void { expect($result)->toContain('1.234,56'); }); -test('number_with_delimiter handles different decimal separators', function (): void { +test('number_with_delimiter handles different decimal separators', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(1234.56, ',', ','))->toBe('1,234,56'); expect($filter->number_with_delimiter(1234.56, ' ', ','))->toBe('1 234,56'); }); -test('number_to_currency handles very large numbers', function (): void { +test('number_to_currency handles very large numbers', function () { $filter = new Numbers(); expect($filter->number_to_currency(1000000))->toBe('$1,000,000'); expect($filter->number_to_currency(1000000.50))->toBe('$1,000,000.50'); }); -test('number_with_delimiter handles very large numbers', function (): void { +test('number_with_delimiter handles very large numbers', function () { $filter = new Numbers(); expect($filter->number_with_delimiter(1000000))->toBe('1,000,000'); diff --git a/tests/Unit/Liquid/Filters/StringMarkupTest.php b/tests/Unit/Liquid/Filters/StringMarkupTest.php index bfd1a07..b3498c3 100644 --- a/tests/Unit/Liquid/Filters/StringMarkupTest.php +++ b/tests/Unit/Liquid/Filters/StringMarkupTest.php @@ -2,35 +2,35 @@ use App\Liquid\Filters\StringMarkup; -test('pluralize returns singular form with count 1', function (): void { +test('pluralize returns singular form with count 1', function () { $filter = new StringMarkup(); expect($filter->pluralize('book', 1))->toBe('1 book'); expect($filter->pluralize('person', 1))->toBe('1 person'); }); -test('pluralize returns plural form with count greater than 1', function (): void { +test('pluralize returns plural form with count greater than 1', function () { $filter = new StringMarkup(); expect($filter->pluralize('book', 2))->toBe('2 books'); expect($filter->pluralize('person', 4))->toBe('4 people'); }); -test('pluralize handles irregular plurals correctly', function (): void { +test('pluralize handles irregular plurals correctly', function () { $filter = new StringMarkup(); expect($filter->pluralize('child', 3))->toBe('3 children'); expect($filter->pluralize('sheep', 5))->toBe('5 sheep'); }); -test('pluralize uses default count of 2 when not specified', function (): void { +test('pluralize uses default count of 2 when not specified', function () { $filter = new StringMarkup(); expect($filter->pluralize('book'))->toBe('2 books'); expect($filter->pluralize('person'))->toBe('2 people'); }); -test('markdown_to_html converts basic markdown to HTML', function (): void { +test('markdown_to_html converts basic markdown to HTML', function () { $filter = new StringMarkup(); $markdown = 'This is *italic* and **bold**.'; @@ -42,7 +42,7 @@ test('markdown_to_html converts basic markdown to HTML', function (): void { expect($result)->toContain('bold'); }); -test('markdown_to_html converts links correctly', function (): void { +test('markdown_to_html converts links correctly', function () { $filter = new StringMarkup(); $markdown = 'This is [a link](https://example.com).'; @@ -51,7 +51,7 @@ test('markdown_to_html converts links correctly', function (): void { expect($result)->toContain('a link'); }); -test('markdown_to_html handles fallback when Parsedown is not available', function (): void { +test('markdown_to_html handles fallback when Parsedown is not available', function () { // Create a mock that simulates Parsedown not being available $filter = new class extends StringMarkup { @@ -68,28 +68,28 @@ test('markdown_to_html handles fallback when Parsedown is not available', functi expect($result)->toBe('This is *italic* and [a link](https://example.com).'); }); -test('strip_html removes HTML tags', function (): void { +test('strip_html removes HTML tags', function () { $filter = new StringMarkup(); $html = '

This is bold and italic.

'; expect($filter->strip_html($html))->toBe('This is bold and italic.'); }); -test('strip_html preserves text content', function (): void { +test('strip_html preserves text content', function () { $filter = new StringMarkup(); $html = '
Hello, world!
'; expect($filter->strip_html($html))->toBe('Hello, world!'); }); -test('strip_html handles nested tags', function (): void { +test('strip_html handles nested tags', function () { $filter = new StringMarkup(); $html = '

Paragraph with nested tags.

'; expect($filter->strip_html($html))->toBe('Paragraph with nested tags.'); }); -test('markdown_to_html handles CommonMarkException gracefully', function (): void { +test('markdown_to_html handles CommonMarkException gracefully', function () { $filter = new StringMarkup(); // Create a mock that throws CommonMarkException @@ -113,7 +113,7 @@ test('markdown_to_html handles CommonMarkException gracefully', function (): voi expect($result)->toBeNull(); }); -test('markdown_to_html handles empty string', function (): void { +test('markdown_to_html handles empty string', function () { $filter = new StringMarkup(); $result = $filter->markdown_to_html(''); @@ -121,7 +121,7 @@ test('markdown_to_html handles empty string', function (): void { expect($result)->toBe(''); }); -test('markdown_to_html handles complex markdown', function (): void { +test('markdown_to_html handles complex markdown', function () { $filter = new StringMarkup(); $markdown = "# Heading\n\nThis is a paragraph with **bold** and *italic* text.\n\n- List item 1\n- List item 2\n\n[Link](https://example.com)"; @@ -135,34 +135,34 @@ test('markdown_to_html handles complex markdown', function (): void { expect($result)->toContain('Link'); }); -test('strip_html handles empty string', function (): void { +test('strip_html handles empty string', function () { $filter = new StringMarkup(); expect($filter->strip_html(''))->toBe(''); }); -test('strip_html handles string without HTML tags', function (): void { +test('strip_html handles string without HTML tags', function () { $filter = new StringMarkup(); $text = 'This is plain text without any HTML tags.'; expect($filter->strip_html($text))->toBe($text); }); -test('strip_html handles self-closing tags', function (): void { +test('strip_html handles self-closing tags', function () { $filter = new StringMarkup(); $html = '

Text with
line break and


horizontal rule.

'; expect($filter->strip_html($html))->toBe('Text with line break and horizontal rule.'); }); -test('pluralize handles zero count', function (): void { +test('pluralize handles zero count', function () { $filter = new StringMarkup(); expect($filter->pluralize('book', 0))->toBe('0 books'); expect($filter->pluralize('person', 0))->toBe('0 people'); }); -test('pluralize handles negative count', function (): void { +test('pluralize handles negative count', function () { $filter = new StringMarkup(); expect($filter->pluralize('book', -1))->toBe('-1 book'); diff --git a/tests/Unit/Liquid/Filters/UniquenessTest.php b/tests/Unit/Liquid/Filters/UniquenessTest.php index 76840e1..291f312 100644 --- a/tests/Unit/Liquid/Filters/UniquenessTest.php +++ b/tests/Unit/Liquid/Filters/UniquenessTest.php @@ -2,7 +2,7 @@ use App\Liquid\Filters\Uniqueness; -test('append_random appends a random string with 4 characters', function (): void { +test('append_random appends a random string with 4 characters', function () { $filter = new Uniqueness(); $result = $filter->append_random('chart-'); diff --git a/tests/Unit/Models/DeviceLogTest.php b/tests/Unit/Models/DeviceLogTest.php index f28f4cd..37e128f 100644 --- a/tests/Unit/Models/DeviceLogTest.php +++ b/tests/Unit/Models/DeviceLogTest.php @@ -6,7 +6,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -test('device log belongs to a device', function (): void { +test('device log belongs to a device', function () { $device = Device::factory()->create(); $log = DeviceLog::factory()->create(['device_id' => $device->id]); @@ -14,7 +14,7 @@ test('device log belongs to a device', function (): void { ->and($log->device->id)->toBe($device->id); }); -test('device log casts log_entry to array', function (): void { +test('device log casts log_entry to array', function () { Device::factory()->create(); $log = DeviceLog::factory()->create([ 'log_entry' => [ @@ -29,7 +29,7 @@ test('device log casts log_entry to array', function (): void { ->and($log->log_entry['level'])->toBe('info'); }); -test('device log casts device_timestamp to datetime', function (): void { +test('device log casts device_timestamp to datetime', function () { Device::factory()->create(); $timestamp = now(); $log = DeviceLog::factory()->create([ @@ -40,7 +40,7 @@ test('device log casts device_timestamp to datetime', function (): void { ->and($log->device_timestamp->timestamp)->toBe($timestamp->timestamp); }); -test('device log factory creates valid data', function (): void { +test('device log factory creates valid data', function () { Device::factory()->create(); $log = DeviceLog::factory()->create(); @@ -50,7 +50,7 @@ test('device log factory creates valid data', function (): void { ->and($log->log_entry)->toHaveKeys(['creation_timestamp', 'device_status_stamp', 'log_id', 'log_message', 'log_codeline', 'log_sourcefile', 'additional_info']); }); -test('device log can be created with minimal required fields', function (): void { +test('device log can be created with minimal required fields', function () { $device = Device::factory()->create(); $log = DeviceLog::create([ 'device_id' => $device->id, diff --git a/tests/Unit/Models/DeviceModelTest.php b/tests/Unit/Models/DeviceModelTest.php index 8c2b6e9..24904d6 100644 --- a/tests/Unit/Models/DeviceModelTest.php +++ b/tests/Unit/Models/DeviceModelTest.php @@ -4,7 +4,7 @@ declare(strict_types=1); use App\Models\DeviceModel; -test('device model has required attributes', function (): void { +test('device model has required attributes', function () { $deviceModel = DeviceModel::factory()->create([ 'name' => 'Test Model', 'width' => 800, @@ -28,7 +28,7 @@ test('device model has required attributes', function (): void { expect($deviceModel->offset_y)->toBe(0); }); -test('device model casts attributes correctly', function (): void { +test('device model casts attributes correctly', function () { $deviceModel = DeviceModel::factory()->create([ 'width' => '800', 'height' => '480', @@ -50,61 +50,61 @@ test('device model casts attributes correctly', function (): void { expect($deviceModel->offset_y)->toBeInt(); }); -test('get color depth attribute returns correct format for bit depth 2', function (): void { +test('get color depth attribute returns correct format for bit depth 2', function () { $deviceModel = DeviceModel::factory()->create(['bit_depth' => 2]); expect($deviceModel->getColorDepthAttribute())->toBe('2bit'); }); -test('get color depth attribute returns correct format for bit depth 4', function (): void { +test('get color depth attribute returns correct format for bit depth 4', function () { $deviceModel = DeviceModel::factory()->create(['bit_depth' => 4]); expect($deviceModel->getColorDepthAttribute())->toBe('4bit'); }); -test('get color depth attribute returns 4bit for bit depth greater than 4', function (): void { +test('get color depth attribute returns 4bit for bit depth greater than 4', function () { $deviceModel = DeviceModel::factory()->create(['bit_depth' => 8]); expect($deviceModel->getColorDepthAttribute())->toBe('4bit'); }); -test('get color depth attribute returns null when bit depth is null', function (): void { +test('get color depth attribute returns null when bit depth is null', function () { $deviceModel = new DeviceModel(['bit_depth' => null]); expect($deviceModel->getColorDepthAttribute())->toBeNull(); }); -test('get scale level attribute returns null for width 800 or less', function (): void { +test('get scale level attribute returns null for width 800 or less', function () { $deviceModel = DeviceModel::factory()->create(['width' => 800]); expect($deviceModel->getScaleLevelAttribute())->toBeNull(); }); -test('get scale level attribute returns large for width between 801 and 1000', function (): void { +test('get scale level attribute returns large for width between 801 and 1000', function () { $deviceModel = DeviceModel::factory()->create(['width' => 900]); expect($deviceModel->getScaleLevelAttribute())->toBe('large'); }); -test('get scale level attribute returns xlarge for width between 1001 and 1400', function (): void { +test('get scale level attribute returns xlarge for width between 1001 and 1400', function () { $deviceModel = DeviceModel::factory()->create(['width' => 1200]); expect($deviceModel->getScaleLevelAttribute())->toBe('xlarge'); }); -test('get scale level attribute returns xxlarge for width greater than 1400', function (): void { +test('get scale level attribute returns xxlarge for width greater than 1400', function () { $deviceModel = DeviceModel::factory()->create(['width' => 1500]); expect($deviceModel->getScaleLevelAttribute())->toBe('xxlarge'); }); -test('get scale level attribute returns null when width is null', function (): void { +test('get scale level attribute returns null when width is null', function () { $deviceModel = new DeviceModel(['width' => null]); expect($deviceModel->getScaleLevelAttribute())->toBeNull(); }); -test('device model factory creates valid data', function (): void { +test('device model factory creates valid data', function () { $deviceModel = DeviceModel::factory()->create(); expect($deviceModel->name)->not->toBeEmpty(); diff --git a/tests/Unit/Models/PlaylistItemTest.php b/tests/Unit/Models/PlaylistItemTest.php index 428a165..6bfe00c 100644 --- a/tests/Unit/Models/PlaylistItemTest.php +++ b/tests/Unit/Models/PlaylistItemTest.php @@ -4,7 +4,7 @@ use App\Models\Playlist; use App\Models\PlaylistItem; use App\Models\Plugin; -test('playlist item belongs to playlist', function (): void { +test('playlist item belongs to playlist', function () { $playlist = Playlist::factory()->create(); $playlistItem = PlaylistItem::factory()->create(['playlist_id' => $playlist->id]); @@ -13,7 +13,7 @@ test('playlist item belongs to playlist', function (): void { ->id->toBe($playlist->id); }); -test('playlist item belongs to plugin', function (): void { +test('playlist item belongs to plugin', function () { $plugin = Plugin::factory()->create(); $playlistItem = PlaylistItem::factory()->create(['plugin_id' => $plugin->id]); @@ -22,7 +22,7 @@ test('playlist item belongs to plugin', function (): void { ->id->toBe($plugin->id); }); -test('playlist item can check if it is a mashup', function (): void { +test('playlist item can check if it is a mashup', function () { $plugin = Plugin::factory()->create(); $regularItem = PlaylistItem::factory()->create([ 'mashup' => null, @@ -44,7 +44,7 @@ test('playlist item can check if it is a mashup', function (): void { ->and($mashupItem->isMashup())->toBeTrue(); }); -test('playlist item can get mashup name', function (): void { +test('playlist item can get mashup name', function () { $plugin1 = Plugin::factory()->create(); $plugin2 = Plugin::factory()->create(); $mashupItem = PlaylistItem::factory()->create([ @@ -59,7 +59,7 @@ test('playlist item can get mashup name', function (): void { expect($mashupItem->getMashupName())->toBe('Test Mashup'); }); -test('playlist item can get mashup layout type', function (): void { +test('playlist item can get mashup layout type', function () { $plugin1 = Plugin::factory()->create(); $plugin2 = Plugin::factory()->create(); $mashupItem = PlaylistItem::factory()->create([ @@ -74,7 +74,7 @@ test('playlist item can get mashup layout type', function (): void { expect($mashupItem->getMashupLayoutType())->toBe('1Lx1R'); }); -test('playlist item can get mashup plugin ids', function (): void { +test('playlist item can get mashup plugin ids', function () { $plugin1 = Plugin::factory()->create(); $plugin2 = Plugin::factory()->create(); $mashupItem = PlaylistItem::factory()->create([ @@ -89,7 +89,7 @@ test('playlist item can get mashup plugin ids', function (): void { expect($mashupItem->getMashupPluginIds())->toBe([$plugin1->id, $plugin2->id]); }); -test('playlist item can get required plugin count for different layouts', function (): void { +test('playlist item can get required plugin count for different layouts', function () { $layouts = [ '1Lx1R' => 2, '1Tx1B' => 2, @@ -117,7 +117,7 @@ test('playlist item can get required plugin count for different layouts', functi } }); -test('playlist item can get layout type', function (): void { +test('playlist item can get layout type', function () { $layoutTypes = [ '1Lx1R' => 'vertical', '1Lx2R' => 'vertical', @@ -144,7 +144,7 @@ test('playlist item can get layout type', function (): void { } }); -test('playlist item can get layout size for different positions', function (): void { +test('playlist item can get layout size for different positions', function () { $plugin1 = Plugin::factory()->create(); $plugin2 = Plugin::factory()->create(); $plugin3 = Plugin::factory()->create(); @@ -163,7 +163,7 @@ test('playlist item can get layout size for different positions', function (): v ->and($mashupItem->getLayoutSize(2))->toBe('half_vertical'); }); -test('playlist item can get available layouts', function (): void { +test('playlist item can get available layouts', function () { $layouts = PlaylistItem::getAvailableLayouts(); expect($layouts)->toBeArray() @@ -171,7 +171,7 @@ test('playlist item can get available layouts', function (): void { ->and($layouts['1Lx1R'])->toBe('1 Left - 1 Right (2 plugins)'); }); -test('playlist item can get required plugin count for layout', function (): void { +test('playlist item can get required plugin count for layout', function () { $layouts = [ '1Lx1R' => 2, '1Tx1B' => 2, @@ -187,7 +187,7 @@ test('playlist item can get required plugin count for layout', function (): void } }); -test('playlist item can create mashup', function (): void { +test('playlist item can create mashup', function () { $playlist = Playlist::factory()->create(); $plugins = Plugin::factory()->count(3)->create(); $pluginIds = $plugins->pluck('id')->toArray(); diff --git a/tests/Unit/Models/PlaylistTest.php b/tests/Unit/Models/PlaylistTest.php index 62d3aaf..55d31c7 100644 --- a/tests/Unit/Models/PlaylistTest.php +++ b/tests/Unit/Models/PlaylistTest.php @@ -4,7 +4,7 @@ use App\Models\Device; use App\Models\Playlist; use App\Models\PlaylistItem; -test('playlist has required attributes', function (): void { +test('playlist has required attributes', function () { $playlist = Playlist::factory()->create([ 'name' => 'Test Playlist', 'is_active' => true, @@ -21,7 +21,7 @@ test('playlist has required attributes', function (): void { ->active_until->format('H:i')->toBe('17:00'); }); -test('playlist belongs to device', function (): void { +test('playlist belongs to device', function () { $device = Device::factory()->create(); $playlist = Playlist::factory()->create(['device_id' => $device->id]); @@ -30,7 +30,7 @@ test('playlist belongs to device', function (): void { ->id->toBe($device->id); }); -test('playlist has many items', function (): void { +test('playlist has many items', function () { $playlist = Playlist::factory()->create(); $items = PlaylistItem::factory()->count(3)->create(['playlist_id' => $playlist->id]); @@ -39,7 +39,7 @@ test('playlist has many items', function (): void { ->each->toBeInstanceOf(PlaylistItem::class); }); -test('getNextPlaylistItem returns null when playlist is inactive', function (): void { +test('getNextPlaylistItem returns null when playlist is inactive', function () { $playlist = Playlist::factory()->create(['is_active' => false]); expect($playlist->getNextPlaylistItem())->toBeNull(); diff --git a/tests/Unit/Models/PluginTest.php b/tests/Unit/Models/PluginTest.php index ef054b1..248e6f5 100644 --- a/tests/Unit/Models/PluginTest.php +++ b/tests/Unit/Models/PluginTest.php @@ -5,7 +5,7 @@ use Illuminate\Support\Facades\Http; uses(Illuminate\Foundation\Testing\RefreshDatabase::class); -test('plugin has required attributes', function (): void { +test('plugin has required attributes', function () { $plugin = Plugin::factory()->create([ 'name' => 'Test Plugin', 'data_payload' => ['key' => 'value'], @@ -18,7 +18,7 @@ test('plugin has required attributes', function (): void { ->uuid->toMatch('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/'); }); -test('plugin automatically generates uuid on creation', function (): void { +test('plugin automatically generates uuid on creation', function () { $plugin = Plugin::factory()->create(); expect($plugin->uuid) @@ -26,14 +26,14 @@ test('plugin automatically generates uuid on creation', function (): void { ->toMatch('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/'); }); -test('plugin can have custom uuid', function (): void { +test('plugin can have custom uuid', function () { $uuid = Illuminate\Support\Str::uuid(); $plugin = Plugin::factory()->create(['uuid' => $uuid]); expect($plugin->uuid)->toBe($uuid); }); -test('plugin data_payload is cast to array', function (): void { +test('plugin data_payload is cast to array', function () { $data = ['key' => 'value']; $plugin = Plugin::factory()->create(['data_payload' => $data]); @@ -42,7 +42,7 @@ test('plugin data_payload is cast to array', function (): void { ->toBe($data); }); -test('plugin can have polling body for POST requests', function (): void { +test('plugin can have polling body for POST requests', function () { $plugin = Plugin::factory()->create([ 'polling_verb' => 'post', 'polling_body' => '{"query": "query { user { id name } }"}', @@ -51,7 +51,7 @@ test('plugin can have polling body for POST requests', function (): void { expect($plugin->polling_body)->toBe('{"query": "query { user { id name } }"}'); }); -test('updateDataPayload sends POST request with body when polling_verb is post', function (): void { +test('updateDataPayload sends POST request with body when polling_verb is post', function () { Http::fake([ 'https://example.com/api' => Http::response(['success' => true], 200), ]); @@ -65,12 +65,14 @@ test('updateDataPayload sends POST request with body when polling_verb is post', $plugin->updateDataPayload(); - Http::assertSent(fn ($request): bool => $request->url() === 'https://example.com/api' && - $request->method() === 'POST' && - $request->body() === '{"query": "query { user { id name } }"}'); + Http::assertSent(function ($request) { + return $request->url() === 'https://example.com/api' && + $request->method() === 'POST' && + $request->body() === '{"query": "query { user { id name } }"}'; + }); }); -test('updateDataPayload handles multiple URLs with IDX_ prefixes', function (): void { +test('updateDataPayload handles multiple URLs with IDX_ prefixes', function () { $plugin = Plugin::factory()->create([ 'data_strategy' => 'polling', 'polling_url' => "https://api1.example.com/data\nhttps://api2.example.com/weather\nhttps://api3.example.com/news", @@ -97,7 +99,7 @@ test('updateDataPayload handles multiple URLs with IDX_ prefixes', function (): expect($plugin->data_payload['IDX_2'])->toBe(['headline' => 'test']); }); -test('updateDataPayload handles single URL without nesting', function (): void { +test('updateDataPayload handles single URL without nesting', function () { $plugin = Plugin::factory()->create([ 'data_strategy' => 'polling', 'polling_url' => 'https://api.example.com/data', @@ -118,7 +120,7 @@ test('updateDataPayload handles single URL without nesting', function (): void { expect($plugin->data_payload)->not->toHaveKey('IDX_0'); }); -test('updateDataPayload resolves Liquid variables in polling_header', function (): void { +test('updateDataPayload resolves Liquid variables in polling_header', function () { $plugin = Plugin::factory()->create([ 'data_strategy' => 'polling', 'polling_url' => 'https://api.example.com/data', @@ -137,13 +139,15 @@ test('updateDataPayload resolves Liquid variables in polling_header', function ( $plugin->updateDataPayload(); - Http::assertSent(fn ($request): bool => $request->url() === 'https://api.example.com/data' && - $request->method() === 'GET' && - $request->header('Authorization')[0] === 'Bearer test123' && - $request->header('X-Custom-Header')[0] === 'custom_header_value'); + Http::assertSent(function ($request) { + return $request->url() === 'https://api.example.com/data' && + $request->method() === 'GET' && + $request->header('Authorization')[0] === 'Bearer test123' && + $request->header('X-Custom-Header')[0] === 'custom_header_value'; + }); }); -test('updateDataPayload resolves Liquid variables in polling_body', function (): void { +test('updateDataPayload resolves Liquid variables in polling_body', function () { $plugin = Plugin::factory()->create([ 'data_strategy' => 'polling', 'polling_url' => 'https://api.example.com/data', @@ -162,7 +166,7 @@ test('updateDataPayload resolves Liquid variables in polling_body', function (): $plugin->updateDataPayload(); - Http::assertSent(function ($request): bool { + Http::assertSent(function ($request) { $expectedBody = '{"query": "query { user { id name } }", "api_key": "test123", "user_id": "456"}'; return $request->url() === 'https://api.example.com/data' && @@ -171,7 +175,7 @@ test('updateDataPayload resolves Liquid variables in polling_body', function (): }); }); -test('webhook plugin is stale if webhook event occurred', function (): void { +test('webhook plugin is stale if webhook event occurred', function () { $plugin = Plugin::factory()->create([ 'data_strategy' => 'webhook', 'data_payload_updated_at' => now()->subMinutes(10), @@ -182,7 +186,7 @@ test('webhook plugin is stale if webhook event occurred', function (): void { }); -test('webhook plugin data not stale if no webhook event occurred for 1 hour', function (): void { +test('webhook plugin data not stale if no webhook event occurred for 1 hour', function () { $plugin = Plugin::factory()->create([ 'data_strategy' => 'webhook', 'data_payload_updated_at' => now()->subMinutes(60), @@ -193,7 +197,7 @@ test('webhook plugin data not stale if no webhook event occurred for 1 hour', fu }); -test('plugin configuration is cast to array', function (): void { +test('plugin configuration is cast to array', function () { $config = ['timezone' => 'UTC', 'refresh_interval' => 30]; $plugin = Plugin::factory()->create(['configuration' => $config]); @@ -202,7 +206,7 @@ test('plugin configuration is cast to array', function (): void { ->toBe($config); }); -test('plugin can get configuration value by key', function (): void { +test('plugin can get configuration value by key', function () { $config = ['timezone' => 'UTC', 'refresh_interval' => 30]; $plugin = Plugin::factory()->create(['configuration' => $config]); @@ -211,7 +215,7 @@ test('plugin can get configuration value by key', function (): void { expect($plugin->getConfiguration('nonexistent', 'default'))->toBe('default'); }); -test('plugin configuration template is cast to array', function (): void { +test('plugin configuration template is cast to array', function () { $template = [ 'custom_fields' => [ [ @@ -229,7 +233,7 @@ test('plugin configuration template is cast to array', function (): void { ->toBe($template); }); -test('resolveLiquidVariables resolves variables from configuration', function (): void { +test('resolveLiquidVariables resolves variables from configuration', function () { $plugin = Plugin::factory()->create([ 'configuration' => [ 'api_key' => '12345', @@ -259,7 +263,7 @@ test('resolveLiquidVariables resolves variables from configuration', function () expect($result)->toBe('High'); }); -test('resolveLiquidVariables handles invalid Liquid syntax gracefully', function (): void { +test('resolveLiquidVariables handles invalid Liquid syntax gracefully', function () { $plugin = Plugin::factory()->create([ 'configuration' => [ 'api_key' => '12345', @@ -273,7 +277,7 @@ test('resolveLiquidVariables handles invalid Liquid syntax gracefully', function ->toThrow(Keepsuit\Liquid\Exceptions\SyntaxException::class); }); -test('plugin can extract default values from custom fields configuration template', function (): void { +test('plugin can extract default values from custom fields configuration template', function () { $configurationTemplate = [ 'custom_fields' => [ [ @@ -319,7 +323,7 @@ test('plugin can extract default values from custom fields configuration templat expect($plugin->getConfiguration('timezone'))->toBeNull(); }); -test('resolveLiquidVariables resolves configuration variables correctly', function (): void { +test('resolveLiquidVariables resolves configuration variables correctly', function () { $plugin = Plugin::factory()->create([ 'configuration' => [ 'Latitude' => '48.2083', @@ -334,7 +338,7 @@ test('resolveLiquidVariables resolves configuration variables correctly', functi expect($plugin->resolveLiquidVariables($template))->toBe($expected); }); -test('resolveLiquidVariables handles missing variables gracefully', function (): void { +test('resolveLiquidVariables handles missing variables gracefully', function () { $plugin = Plugin::factory()->create([ 'configuration' => [ 'Latitude' => '48.2083', @@ -347,7 +351,7 @@ test('resolveLiquidVariables handles missing variables gracefully', function (): expect($plugin->resolveLiquidVariables($template))->toBe($expected); }); -test('resolveLiquidVariables handles empty configuration', function (): void { +test('resolveLiquidVariables handles empty configuration', function () { $plugin = Plugin::factory()->create([ 'configuration' => [], ]); diff --git a/tests/Unit/Notifications/BatteryLowTest.php b/tests/Unit/Notifications/BatteryLowTest.php index a809e5e..ba53356 100644 --- a/tests/Unit/Notifications/BatteryLowTest.php +++ b/tests/Unit/Notifications/BatteryLowTest.php @@ -8,14 +8,14 @@ use App\Notifications\BatteryLow; use App\Notifications\Channels\WebhookChannel; use Illuminate\Notifications\Messages\MailMessage; -test('battery low notification has correct via channels', function (): void { +test('battery low notification has correct via channels', function () { $device = Device::factory()->create(); $notification = new BatteryLow($device); expect($notification->via(new User()))->toBe(['mail', WebhookChannel::class]); }); -test('battery low notification creates correct mail message', function (): void { +test('battery low notification creates correct mail message', function () { $device = Device::factory()->create([ 'name' => 'Test Device', 'last_battery_voltage' => 3.0, @@ -29,7 +29,7 @@ test('battery low notification creates correct mail message', function (): void expect($mailMessage->viewData['device'])->toBe($device); }); -test('battery low notification creates correct webhook message', function (): void { +test('battery low notification creates correct webhook message', function () { config([ 'services.webhook.notifications.topic' => 'battery.low', 'app.name' => 'Test App', @@ -60,7 +60,7 @@ test('battery low notification creates correct webhook message', function (): vo ]); }); -test('battery low notification creates correct array representation', function (): void { +test('battery low notification creates correct array representation', function () { $device = Device::factory()->create([ 'name' => 'Test Device', 'last_battery_voltage' => 3.0, diff --git a/tests/Unit/Notifications/WebhookChannelTest.php b/tests/Unit/Notifications/WebhookChannelTest.php index 16dbd4b..cdefbdd 100644 --- a/tests/Unit/Notifications/WebhookChannelTest.php +++ b/tests/Unit/Notifications/WebhookChannelTest.php @@ -11,13 +11,13 @@ use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Psr7\Response; use Illuminate\Notifications\Notification; -test('webhook channel returns null when no webhook url is configured', function (): void { +test('webhook channel returns null when no webhook url is configured', function () { $client = Mockery::mock(Client::class); $channel = new WebhookChannel($client); $user = new class extends User { - public function routeNotificationFor($driver, $notification = null): null + public function routeNotificationFor($driver, $notification = null) { return null; // No webhook URL configured } @@ -30,13 +30,13 @@ test('webhook channel returns null when no webhook url is configured', function expect($result)->toBeNull(); }); -test('webhook channel throws exception when notification does not implement toWebhook', function (): void { +test('webhook channel throws exception when notification does not implement toWebhook', function () { $client = Mockery::mock(Client::class); $channel = new WebhookChannel($client); $user = new class extends User { - public function routeNotificationFor($driver, $notification = null): string + public function routeNotificationFor($driver, $notification = null) { return 'https://example.com/webhook'; } @@ -44,23 +44,23 @@ test('webhook channel throws exception when notification does not implement toWe $notification = new class extends Notification { - public function via($notifiable): array + public function via($notifiable) { return []; } }; - expect(fn (): ?\GuzzleHttp\Psr7\Response => $channel->send($user, $notification)) + expect(fn () => $channel->send($user, $notification)) ->toThrow(Exception::class, 'Notification does not implement toWebhook method.'); }); -test('webhook channel sends successful webhook request', function (): void { +test('webhook channel sends successful webhook request', function () { $client = Mockery::mock(Client::class); $channel = new WebhookChannel($client); $user = new class extends User { - public function routeNotificationFor($driver, $notification = null): string + public function routeNotificationFor($driver, $notification = null) { return 'https://example.com/webhook'; } @@ -86,13 +86,13 @@ test('webhook channel sends successful webhook request', function (): void { expect($result)->toBe($expectedResponse); }); -test('webhook channel throws exception when response status is not successful', function (): void { +test('webhook channel throws exception when response status is not successful', function () { $client = Mockery::mock(Client::class); $channel = new WebhookChannel($client); $user = new class extends User { - public function routeNotificationFor($driver, $notification = null): string + public function routeNotificationFor($driver, $notification = null) { return 'https://example.com/webhook'; } @@ -107,17 +107,17 @@ test('webhook channel throws exception when response status is not successful', ->once() ->andReturn($errorResponse); - expect(fn (): ?\GuzzleHttp\Psr7\Response => $channel->send($user, $notification)) + expect(fn () => $channel->send($user, $notification)) ->toThrow(Exception::class, 'Webhook request failed with status code: 400'); }); -test('webhook channel handles guzzle exceptions', function (): void { +test('webhook channel handles guzzle exceptions', function () { $client = Mockery::mock(Client::class); $channel = new WebhookChannel($client); $user = new class extends User { - public function routeNotificationFor($driver, $notification = null): string + public function routeNotificationFor($driver, $notification = null) { return 'https://example.com/webhook'; } @@ -130,6 +130,6 @@ test('webhook channel handles guzzle exceptions', function (): void { ->once() ->andThrow(new class extends Exception implements GuzzleException {}); - expect(fn (): ?\GuzzleHttp\Psr7\Response => $channel->send($user, $notification)) + expect(fn () => $channel->send($user, $notification)) ->toThrow(Exception::class); }); diff --git a/tests/Unit/Notifications/WebhookMessageTest.php b/tests/Unit/Notifications/WebhookMessageTest.php index a6ed027..a79f580 100644 --- a/tests/Unit/Notifications/WebhookMessageTest.php +++ b/tests/Unit/Notifications/WebhookMessageTest.php @@ -4,26 +4,26 @@ declare(strict_types=1); use App\Notifications\Messages\WebhookMessage; -test('webhook message can be created with static method', function (): void { +test('webhook message can be created with static method', function () { $message = WebhookMessage::create('test data'); expect($message)->toBeInstanceOf(WebhookMessage::class); }); -test('webhook message can be created with constructor', function (): void { +test('webhook message can be created with constructor', function () { $message = new WebhookMessage('test data'); expect($message)->toBeInstanceOf(WebhookMessage::class); }); -test('webhook message can set query parameters', function (): void { +test('webhook message can set query parameters', function () { $message = WebhookMessage::create() ->query(['param1' => 'value1', 'param2' => 'value2']); expect($message->toArray()['query'])->toBe(['param1' => 'value1', 'param2' => 'value2']); }); -test('webhook message can set data', function (): void { +test('webhook message can set data', function () { $data = ['key' => 'value', 'nested' => ['array' => 'data']]; $message = WebhookMessage::create() ->data($data); @@ -31,7 +31,7 @@ test('webhook message can set data', function (): void { expect($message->toArray()['data'])->toBe($data); }); -test('webhook message can add headers', function (): void { +test('webhook message can add headers', function () { $message = WebhookMessage::create() ->header('X-Custom-Header', 'custom-value') ->header('Authorization', 'Bearer token'); @@ -41,7 +41,7 @@ test('webhook message can add headers', function (): void { expect($headers['Authorization'])->toBe('Bearer token'); }); -test('webhook message can set user agent', function (): void { +test('webhook message can set user agent', function () { $message = WebhookMessage::create() ->userAgent('Test App/1.0'); @@ -49,20 +49,20 @@ test('webhook message can set user agent', function (): void { expect($headers['User-Agent'])->toBe('Test App/1.0'); }); -test('webhook message can set verify option', function (): void { +test('webhook message can set verify option', function () { $message = WebhookMessage::create() ->verify(true); expect($message->toArray()['verify'])->toBeTrue(); }); -test('webhook message verify defaults to false', function (): void { +test('webhook message verify defaults to false', function () { $message = WebhookMessage::create(); expect($message->toArray()['verify'])->toBeFalse(); }); -test('webhook message can chain methods', function (): void { +test('webhook message can chain methods', function () { $message = WebhookMessage::create(['initial' => 'data']) ->query(['param' => 'value']) ->data(['updated' => 'data']) @@ -79,7 +79,7 @@ test('webhook message can chain methods', function (): void { expect($array['verify'])->toBeTrue(); }); -test('webhook message toArray returns correct structure', function (): void { +test('webhook message toArray returns correct structure', function () { $message = WebhookMessage::create(['test' => 'data']); $array = $message->toArray(); diff --git a/tests/Unit/Services/ImageGenerationServiceTest.php b/tests/Unit/Services/ImageGenerationServiceTest.php index 5e3dc47..37ed4e2 100644 --- a/tests/Unit/Services/ImageGenerationServiceTest.php +++ b/tests/Unit/Services/ImageGenerationServiceTest.php @@ -6,15 +6,10 @@ use App\Enums\ImageFormat; use App\Models\Device; use App\Models\DeviceModel; use App\Services\ImageGenerationService; -use Bnussbau\TrmnlPipeline\TrmnlPipeline; use Illuminate\Foundation\Testing\RefreshDatabase; uses(RefreshDatabase::class); -beforeEach(function (): void { - TrmnlPipeline::fake(); -}); - it('get_image_settings returns device model settings when available', function (): void { // Create a DeviceModel $deviceModel = DeviceModel::factory()->create([ @@ -37,6 +32,7 @@ it('get_image_settings returns device model settings when available', function ( // Use reflection to access private method $reflection = new ReflectionClass(ImageGenerationService::class); $method = $reflection->getMethod('getImageSettings'); + $method->setAccessible(true); $settings = $method->invoke(null, $device); @@ -51,7 +47,7 @@ it('get_image_settings returns device model settings when available', function ( expect($settings['offset_x'])->toBe(10); expect($settings['offset_y'])->toBe(20); expect($settings['use_model_settings'])->toBe(true); -}); +})->skipOnCi(); it('get_image_settings falls back to device settings when no device model', function (): void { // Create a device without DeviceModel @@ -65,6 +61,7 @@ it('get_image_settings falls back to device settings when no device model', func // Use reflection to access private method $reflection = new ReflectionClass(ImageGenerationService::class); $method = $reflection->getMethod('getImageSettings'); + $method->setAccessible(true); $settings = $method->invoke(null, $device); @@ -74,7 +71,7 @@ it('get_image_settings falls back to device settings when no device model', func expect($settings['rotation'])->toBe(180); expect($settings['image_format'])->toBe(ImageFormat::PNG_8BIT_GRAYSCALE->value); expect($settings['use_model_settings'])->toBe(false); -}); +})->skipOnCi(); it('get_image_settings uses defaults for missing device properties', function (): void { // Create a device without DeviceModel and missing properties @@ -88,6 +85,7 @@ it('get_image_settings uses defaults for missing device properties', function () // Use reflection to access private method $reflection = new ReflectionClass(ImageGenerationService::class); $method = $reflection->getMethod('getImageSettings'); + $method->setAccessible(true); $settings = $method->invoke(null, $device); @@ -103,12 +101,13 @@ it('get_image_settings uses defaults for missing device properties', function () expect($settings['offset_y'])->toBe(0); // image_format defaults to 'auto' when not set expect($settings['image_format'])->toBe('auto'); -}); +})->skipOnCi(); it('determine_image_format_from_model returns correct formats', function (): void { // Use reflection to access private method $reflection = new ReflectionClass(ImageGenerationService::class); $method = $reflection->getMethod('determineImageFormatFromModel'); + $method->setAccessible(true); // Test BMP format $bmpModel = DeviceModel::factory()->create([ @@ -154,7 +153,7 @@ it('determine_image_format_from_model returns correct formats', function (): voi ]); $format = $method->invoke(null, $unknownModel); expect($format)->toBe(ImageFormat::AUTO->value); -}); +})->skipOnCi(); it('cleanup_folder identifies active images correctly', function (): void { // Create devices with images @@ -190,7 +189,7 @@ it('reset_if_not_cacheable detects device models', function (): void { $plugin->refresh(); expect($plugin->current_image)->toBeNull(); -}); +})->skipOnCi(); it('reset_if_not_cacheable detects custom dimensions', function (): void { // Create a plugin @@ -207,7 +206,7 @@ it('reset_if_not_cacheable detects custom dimensions', function (): void { $plugin->refresh(); expect($plugin->current_image)->toBeNull(); -}); +})->skipOnCi(); it('reset_if_not_cacheable preserves cache for standard devices', function (): void { // Create a plugin @@ -225,7 +224,7 @@ it('reset_if_not_cacheable preserves cache for standard devices', function (): v $plugin->refresh(); expect($plugin->current_image)->toBe('test-uuid'); -}); +})->skipOnCi(); it('reset_if_not_cacheable preserves cache for og_png and og_plus device models', function (): void { // Create a plugin @@ -256,7 +255,7 @@ it('reset_if_not_cacheable preserves cache for og_png and og_plus device models' $plugin->refresh(); expect($plugin->current_image)->toBe('test-uuid'); -}); +})->skipOnCi(); it('reset_if_not_cacheable resets cache for non-standard device models', function (): void { // Create a plugin @@ -278,12 +277,12 @@ it('reset_if_not_cacheable resets cache for non-standard device models', functio $plugin->refresh(); expect($plugin->current_image)->toBeNull(); -}); +})->skipOnCi(); it('reset_if_not_cacheable handles null plugin', function (): void { // Test that the method handles null plugin gracefully expect(fn () => ImageGenerationService::resetIfNotCacheable(null))->not->toThrow(Exception::class); -}); +})->skipOnCi(); it('image_format enum includes new 2bit 4c format', function (): void { // Test that the new format is properly defined in the enum diff --git a/tests/Unit/Services/OidcProviderTest.php b/tests/Unit/Services/OidcProviderTest.php index 1976872..06da1dd 100644 --- a/tests/Unit/Services/OidcProviderTest.php +++ b/tests/Unit/Services/OidcProviderTest.php @@ -9,10 +9,10 @@ use GuzzleHttp\Psr7\Response; use Illuminate\Http\Request; use Laravel\Socialite\Two\User; -test('oidc provider throws exception when endpoint is not configured', function (): void { +test('oidc provider throws exception when endpoint is not configured', function () { config(['services.oidc.endpoint' => null]); - expect(fn (): OidcProvider => new OidcProvider( + expect(fn () => new OidcProvider( new Request(), 'client-id', 'client-secret', @@ -20,7 +20,7 @@ test('oidc provider throws exception when endpoint is not configured', function ))->toThrow(Exception::class, 'OIDC endpoint is not configured'); }); -test('oidc provider handles well-known endpoint url', function (): void { +test('oidc provider handles well-known endpoint url', function () { config(['services.oidc.endpoint' => 'https://example.com/.well-known/openid-configuration']); $mockClient = Mockery::mock(Client::class); @@ -48,7 +48,7 @@ test('oidc provider handles well-known endpoint url', function (): void { expect($provider)->toBeInstanceOf(OidcProvider::class); }); -test('oidc provider handles base url endpoint', function (): void { +test('oidc provider handles base url endpoint', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -76,7 +76,7 @@ test('oidc provider handles base url endpoint', function (): void { expect($provider)->toBeInstanceOf(OidcProvider::class); }); -test('oidc provider throws exception when configuration is empty', function (): void { +test('oidc provider throws exception when configuration is empty', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -90,7 +90,7 @@ test('oidc provider throws exception when configuration is empty', function (): $this->app->instance(Client::class, $mockClient); - expect(fn (): OidcProvider => new OidcProvider( + expect(fn () => new OidcProvider( new Request(), 'client-id', 'client-secret', @@ -98,7 +98,7 @@ test('oidc provider throws exception when configuration is empty', function (): ))->toThrow(Exception::class, 'OIDC configuration is empty or invalid JSON'); }); -test('oidc provider throws exception when authorization endpoint is missing', function (): void { +test('oidc provider throws exception when authorization endpoint is missing', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -115,7 +115,7 @@ test('oidc provider throws exception when authorization endpoint is missing', fu $this->app->instance(Client::class, $mockClient); - expect(fn (): OidcProvider => new OidcProvider( + expect(fn () => new OidcProvider( new Request(), 'client-id', 'client-secret', @@ -123,7 +123,7 @@ test('oidc provider throws exception when authorization endpoint is missing', fu ))->toThrow(Exception::class, 'authorization_endpoint not found in OIDC configuration'); }); -test('oidc provider throws exception when configuration request fails', function (): void { +test('oidc provider throws exception when configuration request fails', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -133,7 +133,7 @@ test('oidc provider throws exception when configuration request fails', function $this->app->instance(Client::class, $mockClient); - expect(fn (): OidcProvider => new OidcProvider( + expect(fn () => new OidcProvider( new Request(), 'client-id', 'client-secret', @@ -141,7 +141,7 @@ test('oidc provider throws exception when configuration request fails', function ))->toThrow(Exception::class, 'Failed to load OIDC configuration'); }); -test('oidc provider uses default scopes when none provided', function (): void { +test('oidc provider uses default scopes when none provided', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -169,7 +169,7 @@ test('oidc provider uses default scopes when none provided', function (): void { expect($provider)->toBeInstanceOf(OidcProvider::class); }); -test('oidc provider uses custom scopes when provided', function (): void { +test('oidc provider uses custom scopes when provided', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -198,7 +198,7 @@ test('oidc provider uses custom scopes when provided', function (): void { expect($provider)->toBeInstanceOf(OidcProvider::class); }); -test('oidc provider maps user data correctly', function (): void { +test('oidc provider maps user data correctly', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class); @@ -241,7 +241,7 @@ test('oidc provider maps user data correctly', function (): void { expect($user->getAvatar())->toBe('https://example.com/avatar.jpg'); }); -test('oidc provider handles missing user fields gracefully', function (): void { +test('oidc provider handles missing user fields gracefully', function () { config(['services.oidc.endpoint' => 'https://example.com']); $mockClient = Mockery::mock(Client::class);