Auto-queue transcription on upload and clarify pending status.
Batch uploads were only storing files as pending without dispatching Whisper jobs; queue them immediately, add a bulk pending action, and show human-readable status labels.
This commit is contained in:
@@ -23,22 +23,26 @@ class RecordingUploadTest extends TestCase
|
||||
'original_filename' => 'note.mp3',
|
||||
'file_path' => 'recordings/note.mp3',
|
||||
'file_size_bytes' => 1024,
|
||||
'transcription_status' => 'pending',
|
||||
'transcription_status' => 'done',
|
||||
'transcript' => 'One two three four five',
|
||||
]);
|
||||
|
||||
$this->get(route('recordings.index'))
|
||||
->assertOk()
|
||||
->assertSee('Pocket note');
|
||||
->assertSee('Pocket note')
|
||||
->assertSee('Words')
|
||||
->assertSee('5');
|
||||
}
|
||||
|
||||
public function test_user_can_upload_an_mp3(): void
|
||||
{
|
||||
Storage::fake('local');
|
||||
Bus::fake();
|
||||
|
||||
$file = UploadedFile::fake()->create('meeting.mp3', 500, 'audio/mpeg');
|
||||
|
||||
$response = $this->post(route('recordings.store'), [
|
||||
'audio' => $file,
|
||||
'audio' => [$file],
|
||||
'title' => 'Team meeting',
|
||||
]);
|
||||
|
||||
@@ -48,12 +52,48 @@ class RecordingUploadTest extends TestCase
|
||||
$response->assertRedirect(route('recordings.show', $recording));
|
||||
$this->assertSame('Team meeting', $recording->title);
|
||||
$this->assertSame('pending', $recording->transcription_status);
|
||||
$this->assertSame('local', $recording->transcription_driver);
|
||||
$this->assertNotNull($recording->transcription_started_at);
|
||||
Storage::disk('local')->assertExists($recording->file_path);
|
||||
Bus::assertDispatched(TranscribeRecording::class);
|
||||
}
|
||||
|
||||
public function test_user_can_batch_upload_multiple_audio_files(): void
|
||||
{
|
||||
Storage::fake('local');
|
||||
Bus::fake();
|
||||
|
||||
$response = $this->post(route('recordings.store'), [
|
||||
'audio' => [
|
||||
UploadedFile::fake()->create('one.mp3', 400, 'audio/mpeg'),
|
||||
UploadedFile::fake()->create('two.wav', 400, 'audio/wav'),
|
||||
UploadedFile::fake()->create('three.ogg', 400, 'audio/ogg'),
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('recordings.index'));
|
||||
$response->assertSessionHas('success');
|
||||
$this->assertSame(3, Recording::query()->count());
|
||||
Bus::assertDispatched(TranscribeRecording::class, 3);
|
||||
|
||||
foreach (Recording::query()->get() as $recording) {
|
||||
Storage::disk('local')->assertExists($recording->file_path);
|
||||
$this->assertSame('pending', $recording->transcription_status);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_upload_page_includes_dropzone(): void
|
||||
{
|
||||
$this->get(route('recordings.create'))
|
||||
->assertOk()
|
||||
->assertSee('Drop audio files here')
|
||||
->assertSee('name="audio[]"', false);
|
||||
}
|
||||
|
||||
public function test_user_can_upload_wav_and_ogg(): void
|
||||
{
|
||||
Storage::fake('local');
|
||||
Bus::fake();
|
||||
|
||||
foreach ([
|
||||
['memo.wav', 'audio/wav'],
|
||||
@@ -61,7 +101,7 @@ class RecordingUploadTest extends TestCase
|
||||
['talk.m4a', 'audio/mp4'],
|
||||
] as [$name, $mime]) {
|
||||
$response = $this->post(route('recordings.store'), [
|
||||
'audio' => UploadedFile::fake()->create($name, 400, $mime),
|
||||
'audio' => [UploadedFile::fake()->create($name, 400, $mime)],
|
||||
'title' => $name,
|
||||
]);
|
||||
|
||||
@@ -71,6 +111,8 @@ class RecordingUploadTest extends TestCase
|
||||
$response->assertRedirect(route('recordings.show', $recording));
|
||||
Storage::disk('local')->assertExists($recording->file_path);
|
||||
}
|
||||
|
||||
Bus::assertDispatched(TranscribeRecording::class, 3);
|
||||
}
|
||||
|
||||
public function test_unsupported_audio_type_is_rejected(): void
|
||||
@@ -79,9 +121,9 @@ class RecordingUploadTest extends TestCase
|
||||
|
||||
$this->from(route('recordings.create'))
|
||||
->post(route('recordings.store'), [
|
||||
'audio' => UploadedFile::fake()->create('notes.txt', 10, 'text/plain'),
|
||||
'audio' => [UploadedFile::fake()->create('notes.txt', 10, 'text/plain')],
|
||||
])
|
||||
->assertSessionHasErrors('audio');
|
||||
->assertSessionHasErrors(['audio.0']);
|
||||
}
|
||||
|
||||
public function test_user_can_queue_local_transcription(): void
|
||||
@@ -385,4 +427,49 @@ class RecordingUploadTest extends TestCase
|
||||
$this->assertSame('pending', $recording->transcription_status);
|
||||
Bus::assertDispatched(TranscribeRecording::class);
|
||||
}
|
||||
|
||||
public function test_user_can_queue_all_pending_transcriptions(): void
|
||||
{
|
||||
Bus::fake();
|
||||
|
||||
Recording::query()->create([
|
||||
'title' => 'Needs work',
|
||||
'original_filename' => 'needs.mp3',
|
||||
'file_path' => 'recordings/needs.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'pending',
|
||||
]);
|
||||
|
||||
Recording::query()->create([
|
||||
'title' => 'Already done',
|
||||
'original_filename' => 'done.mp3',
|
||||
'file_path' => 'recordings/done.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'done',
|
||||
'transcript' => 'Finished text',
|
||||
]);
|
||||
|
||||
$this->from(route('recordings.index'))
|
||||
->post(route('recordings.transcribe-pending'))
|
||||
->assertRedirect(route('recordings.index'))
|
||||
->assertSessionHas('success');
|
||||
|
||||
Bus::assertDispatched(TranscribeRecording::class, 1);
|
||||
}
|
||||
|
||||
public function test_index_shows_human_status_labels(): void
|
||||
{
|
||||
Recording::query()->create([
|
||||
'title' => 'Label check',
|
||||
'original_filename' => 'label.mp3',
|
||||
'file_path' => 'recordings/label.mp3',
|
||||
'file_size_bytes' => 100,
|
||||
'transcription_status' => 'pending',
|
||||
]);
|
||||
|
||||
$this->get(route('recordings.index'))
|
||||
->assertOk()
|
||||
->assertSee('Queued')
|
||||
->assertDontSee('>pending<', false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user