Move recordings UI to Livewire pages with Flux components.

Replace controller-driven Blade views with full-page Livewire index/show/create flows so Flux tables, toasts, and uploads work natively.
This commit is contained in:
ben
2026-08-12 19:17:52 +02:00
parent bfcfc12f58
commit 34ccf0c32b
37 changed files with 1482 additions and 1103 deletions
+36 -45
View File
@@ -4,6 +4,9 @@ namespace Tests\Feature;
use App\Http\Requests\StoreRecordingRequest;
use App\Jobs\TranscribeRecording;
use App\Livewire\Recordings\Index;
use App\Livewire\Recordings\Show;
use App\Livewire\UploadRecordings;
use App\Models\Recording;
use App\Models\User;
use App\Services\TranscriptionService;
@@ -12,6 +15,7 @@ use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Storage;
use Laravel\Ai\Transcription;
use Livewire\Livewire;
use Tests\TestCase;
class RecordingUploadTest extends TestCase
@@ -54,15 +58,14 @@ class RecordingUploadTest extends TestCase
$file = UploadedFile::fake()->create('meeting.mp3', 500, 'audio/mpeg');
$response = $this->post(route('recordings.store'), [
'audio' => [$file],
'title' => 'Team meeting',
]);
Livewire::test(UploadRecordings::class)
->set('title', 'Team meeting')
->set('audio', [$file])
->assertRedirect(route('recordings.show', Recording::query()->first()));
$recording = Recording::query()->first();
$this->assertNotNull($recording);
$response->assertRedirect(route('recordings.show', $recording));
$this->assertSame('Team meeting', $recording->title);
$this->assertSame('pending', $recording->transcription_status);
$this->assertSame('local', $recording->transcription_driver);
@@ -76,16 +79,13 @@ class RecordingUploadTest extends TestCase
Storage::fake('local');
Bus::fake();
$response = $this->post(route('recordings.store'), [
'audio' => [
Livewire::test(UploadRecordings::class)
->set('audio', [
UploadedFile::fake()->createWithContent('one.mp3', str_repeat('a', 400)),
UploadedFile::fake()->createWithContent('two.wav', str_repeat('b', 400)),
UploadedFile::fake()->createWithContent('three.ogg', str_repeat('c', 400)),
],
]);
$response->assertRedirect(route('recordings.index'));
$response->assertSessionHas('success');
])
->assertRedirect(route('recordings.index'));
$this->assertSame(3, Recording::query()->count());
Bus::assertDispatched(TranscribeRecording::class, 3);
@@ -99,9 +99,9 @@ class RecordingUploadTest extends TestCase
{
$this->get(route('recordings.create'))
->assertOk()
->assertSee('Drop audio files here')
->assertSee('Drop audio files here or click to browse')
->assertSee('max 2 GB each', false)
->assertSee('name="audio[]"', false);
->assertSeeLivewire('upload-recordings');
}
public function test_files_larger_than_two_gigabytes_are_rejected(): void
@@ -113,11 +113,9 @@ class RecordingUploadTest extends TestCase
->create('huge.mp3', 10, 'audio/mpeg')
->size(StoreRecordingRequest::MAX_AUDIO_KILOBYTES + 1);
$this->from(route('recordings.create'))
->post(route('recordings.store'), [
'audio' => [$file],
])
->assertSessionHasErrors(['audio.0']);
Livewire::test(UploadRecordings::class)
->set('audio', [$file])
->assertHasErrors(['audio.0']);
$this->assertSame(0, Recording::query()->count());
Bus::assertNothingDispatched();
@@ -133,15 +131,14 @@ class RecordingUploadTest extends TestCase
['clip.ogg', 'audio/ogg', 'ogg-bytes'],
['talk.m4a', 'audio/mp4', 'm4a-bytes'],
] as [$name, $mime, $contents]) {
$response = $this->post(route('recordings.store'), [
'audio' => [UploadedFile::fake()->createWithContent($name, $contents)],
'title' => $name,
]);
Livewire::test(UploadRecordings::class)
->set('title', $name)
->set('audio', [UploadedFile::fake()->createWithContent($name, $contents)])
->assertRedirect();
$recording = Recording::query()->where('title', $name)->first();
$this->assertNotNull($recording, "Failed uploading {$name}");
$response->assertRedirect(route('recordings.show', $recording));
Storage::disk('local')->assertExists($recording->file_path);
}
@@ -152,11 +149,9 @@ class RecordingUploadTest extends TestCase
{
Storage::fake('local');
$this->from(route('recordings.create'))
->post(route('recordings.store'), [
'audio' => [UploadedFile::fake()->create('notes.txt', 10, 'text/plain')],
])
->assertSessionHasErrors(['audio.0']);
Livewire::test(UploadRecordings::class)
->set('audio', [UploadedFile::fake()->create('notes.txt', 10, 'text/plain')])
->assertHasErrors(['audio.0']);
}
public function test_user_can_queue_local_transcription(): void
@@ -173,8 +168,8 @@ class RecordingUploadTest extends TestCase
// Fake AI so the afterResponse job (sync) does not call a real provider.
Transcription::fake(['Queued transcription text.']);
$this->post(route('recordings.transcribe', $recording))
->assertRedirect();
Livewire::test(Show::class, ['recording' => $recording])
->call('startTranscription');
$recording->refresh();
$this->assertSame('local', $recording->transcription_driver);
@@ -332,8 +327,8 @@ class RecordingUploadTest extends TestCase
'updated_at' => now()->subMinutes(10),
]);
$this->post(route('recordings.transcribe', $recording))
->assertRedirect();
Livewire::test(Show::class, ['recording' => $recording])
->call('startTranscription');
$recording->refresh();
$this->assertSame('local', $recording->transcription_driver);
@@ -355,9 +350,8 @@ class RecordingUploadTest extends TestCase
'transcription_started_at' => now(),
]);
$this->post(route('recordings.transcribe.cancel', $recording))
->assertRedirect()
->assertSessionHas('success');
Livewire::test(Show::class, ['recording' => $recording])
->call('cancelTranscription');
$recording->refresh();
$this->assertSame('cancelled', $recording->transcription_status);
@@ -380,9 +374,8 @@ class RecordingUploadTest extends TestCase
'transcription_started_at' => now()->subMinute(),
]);
$this->post(route('recordings.transcribe', $recording))
->assertRedirect()
->assertSessionHas('success');
Livewire::test(Show::class, ['recording' => $recording])
->call('startTranscription');
$recording->refresh();
$this->assertSame('local', $recording->transcription_driver);
@@ -464,8 +457,8 @@ class RecordingUploadTest extends TestCase
'transcribed_at' => now()->subHour(),
]);
$this->post(route('recordings.transcribe', $recording))
->assertRedirect();
Livewire::test(Show::class, ['recording' => $recording])
->call('startTranscription');
$recording->refresh();
$this->assertSame('Old transcript text.', $recording->transcript);
@@ -497,10 +490,8 @@ class RecordingUploadTest extends TestCase
'transcript' => 'Finished text',
]);
$this->from(route('recordings.index'))
->post(route('recordings.transcribe-pending'))
->assertRedirect(route('recordings.index'))
->assertSessionHas('success');
Livewire::test(Index::class)
->call('queuePending');
Bus::assertDispatched(TranscribeRecording::class, 1);
}