trove/packages/Lvl0/FediDiscover/tests/Feature/LemmyClientTest.php

150 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Lvl0\FediDiscover\Tests\Feature;
use Illuminate\Support\Facades\Http;
use Lvl0\FediDiscover\Clients\LemmyClient;
use Lvl0\FediDiscover\Config\InstanceType;
use Lvl0\FediDiscover\Models\Instance;
use Lvl0\FediDiscover\ValueObjects\FediversePost;
use Tests\TestCase;
class LemmyClientTest extends TestCase
{
public function test_it_maps_each_post_to_a_fediverse_post(): void
{
Http::fake([
'*' => Http::response([
'posts' => [
$this->lemmyPost(
id: 42,
apId: 'https://lemmy.world/post/42',
name: 'My Great Post',
body: 'Some body text',
published: '2026-04-25T10:00:00.000000',
),
],
], 200),
]);
$posts = (new LemmyClient)->fetchPostsSince($this->lemmyInstance(), null);
$this->assertCount(1, $posts);
$this->assertInstanceOf(FediversePost::class, $posts->first());
$this->assertSame('42', $posts->first()->cursorId);
$this->assertSame('https://lemmy.world/post/42', $posts->first()->selfUrl);
$this->assertSame('My Great Post', $posts->first()->title);
$this->assertSame('Some body text', $posts->first()->body);
$this->assertSame('2026-04-25T10:00:00.000000', $posts->first()->publishedAt);
}
public function test_url_field_is_appended_to_body(): void
{
Http::fake([
'*' => Http::response([
'posts' => [
$this->lemmyPost(
id: 42,
apId: 'https://lemmy.world/post/42',
url: 'https://example-garden.blog/post-42',
body: 'Some original text.',
),
],
], 200),
]);
$post = (new LemmyClient)->fetchPostsSince($this->lemmyInstance(), null)->first();
$this->assertStringContainsString('Some original text.', $post->body);
$this->assertStringContainsString('https://example-garden.blog/post-42', $post->body);
}
public function test_url_absent_leaves_body_clean(): void
{
Http::fake([
'*' => Http::response([
'posts' => [
$this->lemmyPost(
id: 7,
apId: 'https://lemmy.world/post/7',
body: 'Just a regular post.',
),
],
], 200),
]);
$post = (new LemmyClient)->fetchPostsSince($this->lemmyInstance(), null)->first();
$this->assertSame('Just a regular post.', $post->body);
}
public function test_it_handles_posts_without_a_body_key(): void
{
Http::fake([
'*' => Http::response([
'posts' => [
[
'post' => [
'id' => 99,
'ap_id' => 'https://lemmy.world/post/99',
'url' => null,
'name' => 'Link-only post',
'published' => '2026-04-25T10:00:00.000000',
// 'body' key intentionally absent — real Lemmy API omits it for link-only posts
],
],
],
], 200),
]);
$post = (new LemmyClient)->fetchPostsSince($this->lemmyInstance(), null)->first();
$this->assertNull($post->body);
}
public function test_it_hits_the_post_list_endpoint_of_the_instance(): void
{
Http::fake([
'lemmy.world/api/v3/post/list*' => Http::response(['posts' => []], 200),
]);
(new LemmyClient)->fetchPostsSince($this->lemmyInstance(), null);
Http::assertSent(fn ($request) => str_starts_with($request->url(), 'https://lemmy.world/api/v3/post/list')
&& $request->method() === 'GET'
);
}
private function lemmyInstance(): Instance
{
return new Instance([
'type' => InstanceType::Lemmy,
'url' => 'https://lemmy.world',
]);
}
/**
* @return array<string, mixed>
*/
private function lemmyPost(
int $id,
string $apId,
?string $url = null,
string $body = '',
string $name = 'A post title',
string $published = '2026-04-25T10:00:00.000000',
): array {
return [
'post' => [
'id' => $id,
'ap_id' => $apId,
'url' => $url,
'body' => $body,
'name' => $name,
'published' => $published,
],
];
}
}