Display CMS: Upload-Fehler abfangen und kaputte Bilder im Player überspringen.
Mediathek-Uploads legen keinen Datensatz mehr an, wenn der Datei-Write fehlschlägt (verhindert 404-Einträge auf den Displays). Der Player überspringt Bilder mit Ladefehler nach 2s statt Schwarzbild zu zeigen. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2a34adc515
commit
193d37b1ce
6 changed files with 211 additions and 62 deletions
|
|
@ -252,6 +252,63 @@ it('generates a poster thumbnail when a real video is uploaded', function () {
|
|||
@unlink($videoPath);
|
||||
});
|
||||
|
||||
it('throws and creates no record when the file cannot be written to storage', function () {
|
||||
$disk = Mockery::mock(\Illuminate\Contracts\Filesystem\Filesystem::class);
|
||||
$disk->shouldReceive('putFileAs')->once()->andReturn(false);
|
||||
Storage::shouldReceive('disk')->with('public')->andReturn($disk);
|
||||
|
||||
$service = app(DisplayMediaService::class);
|
||||
$file = UploadedFile::fake()->image('broken.jpg');
|
||||
|
||||
expect(fn () => $service->storeUpload($file))->toThrow(RuntimeException::class);
|
||||
expect(DisplayMedia::count())->toBe(0);
|
||||
});
|
||||
|
||||
it('throws and creates no record when the stored file does not exist afterwards', function () {
|
||||
$disk = Mockery::mock(\Illuminate\Contracts\Filesystem\Filesystem::class);
|
||||
$disk->shouldReceive('putFileAs')->once()->andReturn('display-media/2026/07/ghost.jpg');
|
||||
$disk->shouldReceive('exists')->once()->andReturn(false);
|
||||
Storage::shouldReceive('disk')->with('public')->andReturn($disk);
|
||||
|
||||
$service = app(DisplayMediaService::class);
|
||||
$file = UploadedFile::fake()->image('ghost.jpg');
|
||||
|
||||
expect(fn () => $service->storeUpload($file))->toThrow(RuntimeException::class);
|
||||
expect(DisplayMedia::count())->toBe(0);
|
||||
});
|
||||
|
||||
it('shows a validation error in the media library when the storage write fails', function () {
|
||||
$this->mock(DisplayMediaService::class)
|
||||
->shouldReceive('storeUpload')
|
||||
->once()
|
||||
->andThrow(new RuntimeException('Die Datei "broken.jpg" konnte nicht im Storage gespeichert werden. Bitte Schreibrechte und Speicherplatz prüfen.'));
|
||||
|
||||
$file = UploadedFile::fake()->image('broken.jpg');
|
||||
|
||||
Volt::test('admin.cms.display-media-library')
|
||||
->set('uploads', [$file])
|
||||
->call('handleUploads')
|
||||
->assertHasErrors('uploads');
|
||||
|
||||
expect(DisplayMedia::count())->toBe(0);
|
||||
});
|
||||
|
||||
it('shows a validation error in the media picker when the storage write fails', function () {
|
||||
$this->mock(DisplayMediaService::class)
|
||||
->shouldReceive('storeUpload')
|
||||
->once()
|
||||
->andThrow(new RuntimeException('Die Datei "broken.jpg" konnte nicht im Storage gespeichert werden. Bitte Schreibrechte und Speicherplatz prüfen.'));
|
||||
|
||||
$file = UploadedFile::fake()->image('broken.jpg');
|
||||
|
||||
Livewire\Livewire::test(\App\Livewire\Admin\Cms\DisplayMediaPicker::class)
|
||||
->set('quickUploads', [$file])
|
||||
->assertHasErrors('quickUploads')
|
||||
->assertNotDispatched('display-media-selected');
|
||||
|
||||
expect(DisplayMedia::count())->toBe(0);
|
||||
});
|
||||
|
||||
it('does not set a thumbnail when the video cannot be decoded', function () {
|
||||
$service = app(DisplayMediaService::class);
|
||||
$file = UploadedFile::fake()->create('broken.mp4', 500, 'video/mp4');
|
||||
|
|
|
|||
|
|
@ -444,6 +444,15 @@ test('display player keeps previews in a strict 9 by 16 viewport', function () {
|
|||
->toContain('container-type: size;')
|
||||
->toContain("if (hostname === 'cabinet.b2in.eu') {")
|
||||
->toContain("return 'https://portal.b2in.eu';")
|
||||
->toContain('startConfigPolling')
|
||||
->toContain('startFileVersionPolling')
|
||||
->toContain('playerFileCheckUrl')
|
||||
->toContain('readPlayerFileVersion')
|
||||
->toContain('Player-Datei geändert')
|
||||
->toContain('Playlist geändert')
|
||||
->toContain('DISPLAY_PORTAL_BASE_URL')
|
||||
->toContain("url.startsWith('/_cabinet/')")
|
||||
->toContain('`${DISPLAY_PORTAL_BASE_URL}${url}`')
|
||||
->toContain('/api/display/overview')
|
||||
->toContain('Aktive Live-Displays')
|
||||
->toContain('renderOverview(data.displays || [])')
|
||||
|
|
@ -481,6 +490,15 @@ test('display player keeps previews in a strict 9 by 16 viewport', function () {
|
|||
->toContain('background: none');
|
||||
});
|
||||
|
||||
test('display player skips broken images instead of showing a black frame', function () {
|
||||
$player = file_get_contents(public_path('_cabinet/display/index.html'));
|
||||
|
||||
expect($player)
|
||||
->toContain('img.onerror = () => {')
|
||||
->toContain('[B2in] Image error:')
|
||||
->toContain('setTimeout(finish, 2000);');
|
||||
});
|
||||
|
||||
test('display player stops looping when the playlist has no playable content', function () {
|
||||
$player = file_get_contents(public_path('_cabinet/display/index.html'));
|
||||
|
||||
|
|
@ -510,10 +528,12 @@ test('preview player is served with a revalidation cache header', function () {
|
|||
$display = Display::factory()->create(['preview_token' => 'fresh-token']);
|
||||
$version = DisplayVersion::factory()->create();
|
||||
|
||||
foreach ([
|
||||
'/preview/fresh-token',
|
||||
"/preview/module/{$version->id}",
|
||||
] as $url) {
|
||||
foreach (
|
||||
[
|
||||
'/preview/fresh-token',
|
||||
"/preview/module/{$version->id}",
|
||||
] as $url
|
||||
) {
|
||||
$response = $this->get($url);
|
||||
$response->assertSuccessful();
|
||||
expect($response->headers->get('Cache-Control'))->toContain('no-cache');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue