Http::response($this->fixture('ok/video_success.html'), 200), ]); $strategy = new OkRuStrategy($this->app->make(HttpClient::class)); $info = $strategy->extract($this->ref()); self::assertSame('15019292494547', $info->id); self::assertSame('Falcon mystery in the hood', $info->title); self::assertSame('A radical shift of optics.', $info->description); self::assertSame(709, $info->duration); self::assertSame('Egor Akimov', $info->uploader); self::assertSame(45, $info->likeCount); self::assertSame(3419, $info->viewCount); self::assertSame(0, $info->ageLimit); self::assertFalse($info->isLive); self::assertSame(strtotime('2026-07-01T19:28:15+03:00'), $info->timestamp); // Thumbnail from movie.poster with OG dimensions. self::assertNotEmpty($info->thumbnails); self::assertSame(720, $info->bestThumbnail()?->width); self::assertStringContainsString('iv.okcdn.ru', (string) $info->thumbnailUrl()); // 6 mp4 + 1 hls = 7 formats. self::assertCount(7, $info->formats); $full = null; foreach ($info->formats as $format) { if ($format->formatId === 'full') { $full = $format; } } self::assertNotNull($full); self::assertSame(1080, $full->height); // expires=1784298004897 ms -> 1784298004 seconds. self::assertSame(1784298004, $full->expiresAt); self::assertSame(1784298004, $info->formatExpiresAt); } public function test_thumbnail_fast_path_uses_poster(): void { Http::fakeSequence()->push($this->fixture('ok/video_success.html'), 200); $strategy = new OkRuStrategy($this->app->make(HttpClient::class)); $url = $strategy->extractThumbnail($this->ref()); self::assertNotNull($url); self::assertStringContainsString('iv.okcdn.ru', $url); } public function test_falls_back_to_og_meta_when_no_data_options(): void { // Page without the inline player payload (external/restricted video). Http::fake([ 'ok.ru/video/*' => Http::response($this->fixture('ok/video_meta_only.html'), 200), ]); $strategy = new OkRuStrategy($this->app->make(HttpClient::class)); $info = $strategy->extract($this->ref()); self::assertSame('External embed video', $info->title); self::assertSame('Some Channel', $info->uploader); self::assertSame(1529, $info->duration); self::assertSame(12345, $info->viewCount); // No formats available from the OG fallback. self::assertSame([], $info->formats); // Thumbnail still recovered from og:image. self::assertStringContainsString('EXTERNAL', (string) $info->thumbnailUrl()); } public function test_thumbnail_falls_back_to_og_image(): void { Http::fakeSequence()->push($this->fixture('ok/video_meta_only.html'), 200); $strategy = new OkRuStrategy($this->app->make(HttpClient::class)); $url = $strategy->extractThumbnail($this->ref()); self::assertSame('https://iv.okcdn.ru/i?r=EXTERNAL&fn=external_8', $url); } public function test_throws_not_found_for_stub_error(): void { Http::fake([ 'ok.ru/video/*' => Http::response($this->fixture('ok/video_not_found.html'), 200), ]); $strategy = new OkRuStrategy($this->app->make(HttpClient::class)); $this->expectException(VideoNotFoundException::class); $this->expectExceptionMessage('author of this video has not been found'); $strategy->extract($this->ref()); } public function test_throws_login_required_for_restricted_video(): void { Http::fake([ 'ok.ru/video/*' => Http::response( '
Access to this video is restricted
', 200, ), ]); $strategy = new OkRuStrategy($this->app->make(HttpClient::class)); $this->expectException(LoginRequiredException::class); $strategy->extract($this->ref()); } }