Files
AndyTranscribe/tests/Feature/Recordings/ShowTest.php
T
ben 3a9cf50529 Keep live Whisper segments on screen without a page refresh.
Treat streamed chunks as appends, stop Livewire from remorphing the Alpine tree, and hydrate from HTTP while a run is active so segment cards appear as they arrive.
2026-08-13 16:35:33 +02:00

285 lines
10 KiB
PHP

<?php
namespace Tests\Feature\Recordings;
use App\Livewire\Recordings\Show;
use App\Models\Recording;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
use Tests\TestCase;
class ShowTest extends TestCase
{
use RefreshDatabase;
public function test_show_page_renders_as_livewire(): void
{
$user = User::factory()->create();
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Show me',
'original_filename' => 'show.mp3',
'file_path' => 'recordings/show.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'done',
'transcript' => 'Finished text',
]);
$this->actingAs($user)
->get(route('recordings.show', $recording))
->assertOk()
->assertSeeLivewire(Show::class)
->assertSee('Show me')
->assertSee('Play', false);
}
public function test_user_can_delete_own_recording(): void
{
Storage::fake('local');
Storage::disk('local')->put('recordings/delete-me.mp3', 'bytes');
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Delete me',
'original_filename' => 'delete-me.mp3',
'file_path' => 'recordings/delete-me.mp3',
'file_size_bytes' => 5,
'transcription_status' => 'done',
]);
Livewire::test(Show::class, ['recording' => $recording])
->call('delete')
->assertRedirect(route('recordings.index'));
$this->assertDatabaseMissing('recordings', ['id' => $recording->id]);
}
public function test_show_uses_alpine_hydrate_while_transcription_is_queued(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'In progress',
'original_filename' => 'active.mp3',
'file_path' => 'recordings/active.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'pending',
'transcription_progress' => 'Queued — waiting to start…',
'transcription_percent' => null,
'transcription_driver' => 'local',
'transcription_started_at' => now(),
]);
Livewire::test(Show::class, ['recording' => $recording])
->assertDontSee('wire:poll', false)
->assertSee('wire:ignore', false)
->assertSee('transcriptionMonitor', false)
->assertSee('Queued — waiting to start…');
}
public function test_show_does_not_use_livewire_poll_while_transcription_is_processing(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Live stream',
'original_filename' => 'active.mp3',
'file_path' => 'recordings/active.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'processing',
'transcription_progress' => 'Transcribing locally…',
'transcription_percent' => 20,
'transcription_driver' => 'local',
'transcription_started_at' => now(),
]);
Livewire::test(Show::class, ['recording' => $recording])
->assertDontSee('wire:poll', false)
->assertSee('wire:ignore', false)
->assertSee('userId', false);
}
public function test_show_page_includes_partial_transcript_while_processing(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Live words',
'original_filename' => 'active.mp3',
'file_path' => 'recordings/active.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'processing',
'transcription_progress' => 'Transcribing locally…',
'transcription_percent' => 62,
'transcription_driver' => 'local',
'transcription_started_at' => now(),
'transcript' => 'Live partial sentence from whisper',
]);
Livewire::test(Show::class, ['recording' => $recording])
->assertSee('Live partial sentence from whisper')
->assertSee('status.transcript', false);
}
public function test_show_page_includes_live_whisper_segment_bindings(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Verbose live',
'original_filename' => 'active.mp3',
'file_path' => 'recordings/active.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'processing',
'transcription_driver' => 'local',
'transcription_started_at' => now(),
'transcript' => 'Hello',
'transcription_verbose' => [
'language' => 'en',
'duration' => 4.0,
'segments' => [
[
'text' => 'Hello',
'start' => 0.0,
'end' => 1.0,
'avg_logprob' => -0.1,
'words' => [
['word' => 'Hello', 'start' => 0.0, 'end' => 1.0, 'probability' => 0.9],
],
],
],
],
]);
Livewire::test(Show::class, ['recording' => $recording])
->assertSee('whisper.segments', false)
->assertSee('whisper.language', false)
->assertSee('segmentDomKey', false)
->assertSee('Hello');
}
public function test_show_does_not_poll_when_transcription_is_idle(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Finished',
'original_filename' => 'done.mp3',
'file_path' => 'recordings/done.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'done',
'transcript' => 'all done',
]);
Livewire::test(Show::class, ['recording' => $recording])
->assertDontSee('wire:poll', false);
}
public function test_show_poll_refresh_picks_up_processing_status(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Live update',
'original_filename' => 'live.mp3',
'file_path' => 'recordings/live.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'pending',
'transcription_progress' => 'Queued — waiting to start…',
'transcription_driver' => 'local',
'transcription_started_at' => now(),
]);
$component = Livewire::test(Show::class, ['recording' => $recording]);
$recording->update([
'transcription_status' => 'processing',
'transcription_progress' => 'Transcribing locally…',
'transcription_percent' => 40,
]);
$component
->call('$refresh')
->assertSet('recording.transcription_status', 'processing')
->assertSet('recording.transcription_percent', 40)
->assertSee('Transcribing locally…');
}
public function test_show_poll_refresh_picks_up_completed_transcript(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Almost done',
'original_filename' => 'live.mp3',
'file_path' => 'recordings/live.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'processing',
'transcription_progress' => 'Transcribing locally…',
'transcription_percent' => 90,
'transcription_driver' => 'local',
'transcription_started_at' => now(),
'transcript' => 'Partial',
]);
$component = Livewire::test(Show::class, ['recording' => $recording]);
$recording->update([
'transcription_status' => 'done',
'transcription_percent' => 100,
'transcript' => 'Finished live transcript',
'transcribed_at' => now(),
]);
$component
->call('$refresh')
->assertSet('recording.transcription_status', 'done')
->assertSet('recording.transcription_percent', 100)
->assertSee('Finished live transcript');
}
public function test_show_alpine_root_key_does_not_include_percent(): void
{
$user = User::factory()->create();
$this->actingAs($user);
$recording = Recording::query()->create([
'user_id' => $user->id,
'title' => 'Stable key',
'original_filename' => 'live.mp3',
'file_path' => 'recordings/live.mp3',
'file_size_bytes' => 100,
'transcription_status' => 'processing',
'transcription_progress' => 'Transcribing locally…',
'transcription_percent' => 62,
'transcription_driver' => 'local',
'transcription_started_at' => now(),
]);
Livewire::test(Show::class, ['recording' => $recording])
->assertSee('wire:ignore', false)
->assertSee('transcription-ui-'.$recording->id.'-processing-', false)
->assertDontSee('transcription-ui-'.$recording->id.'-processing-62', false);
}
}