test(linkedin): end-to-end document publish + harden title resolution

- Add a PublishToSocialPlatform test that runs the real job -> publisher chain (no publisher mock) for a linkedin_document post, asserting the documents API flow and the published platform state
- resolveDocumentTitle selects the document item explicitly (first(isDocument)) to match publishDocument, instead of the first media item
This commit is contained in:
Paulo Castellano 2026-06-24 17:45:29 -03:00
parent c339f8cf28
commit 051c797cc1
3 changed files with 59 additions and 2 deletions

View file

@ -233,7 +233,7 @@ private function resolveDocumentTitle(PostPlatform $postPlatform): string
return (string) $title;
}
return $postPlatform->post->mediaItems->first()?->original_filename ?? 'Document';
return $postPlatform->post->mediaItems->first(fn ($media) => $media->isDocument())?->original_filename ?? 'Document';
}
private function publishDocument(string $organizationUrn, ?string $content, $mediaCollection, string $title, $account): array

View file

@ -215,7 +215,7 @@ private function resolveDocumentTitle(PostPlatform $postPlatform): string
return (string) $title;
}
return $postPlatform->post->mediaItems->first()?->original_filename ?? 'Document';
return $postPlatform->post->mediaItems->first(fn ($media) => $media->isDocument())?->original_filename ?? 'Document';
}
private function publishDocument(string $personUrn, ?string $content, $mediaCollection, string $title): array

View file

@ -3,6 +3,7 @@
declare(strict_types=1);
use App\Enums\Post\Status as PostStatus;
use App\Enums\PostPlatform\ContentType;
use App\Enums\PostPlatform\Status as PlatformStatus;
use App\Enums\SocialAccount\Status as AccountStatus;
use App\Enums\UserWorkspace\Role;
@ -23,6 +24,7 @@
use Carbon\Carbon;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
@ -79,6 +81,61 @@
expect($this->postPlatform->platform_url)->toBe('https://linkedin.com/post/123');
});
test('publish job runs the real document flow end-to-end for a LinkedIn PDF post', function () {
Event::fake();
// Real publisher (no mock) — exercise the full job -> getPublisher -> publishDocument chain.
$this->socialAccount->update([
'platform_user_id' => 'person-xyz',
'token_expires_at' => now()->addDays(60),
]);
$this->postPlatform->update(['content_type' => ContentType::LinkedInDocument]);
$this->post->update([
'content' => 'Our deck',
'media' => [[
'id' => 'doc-1', 'path' => 'media/deck.pdf', 'url' => 'https://example.com/deck.pdf',
'type' => 'document', 'mime_type' => 'application/pdf', 'original_filename' => 'deck.pdf',
]],
]);
$uploadUrl = 'https://www.linkedin.com/dms-uploads/document/e2e';
Http::fake(function ($request) use ($uploadUrl) {
$url = $request->url();
if (str_contains($url, '/rest/documents') && str_contains($url, 'initializeUpload')) {
return Http::response(['value' => ['uploadUrl' => $uploadUrl, 'document' => 'urn:li:document:E2E']], 200);
}
if ($url === $uploadUrl) {
return Http::response(null, 201);
}
if (str_contains($url, '/rest/documents/')) {
return Http::response(['status' => 'AVAILABLE'], 200);
}
if (str_contains($url, '/rest/posts')) {
return Http::response(null, 201, ['x-restli-id' => 'urn:li:share:e2e']);
}
return Http::response('fake-pdf-bytes', 200);
});
(new PublishToSocialPlatform($this->postPlatform))->handle();
$this->postPlatform->refresh();
expect($this->postPlatform->status)->toBe(PlatformStatus::Published);
expect($this->postPlatform->platform_post_id)->toBe('urn:li:share:e2e');
Http::assertSent(fn ($request) => str_contains($request->url(), '/rest/documents') && str_contains($request->url(), 'initializeUpload'));
Http::assertSent(function ($request) {
return str_contains($request->url(), '/rest/posts')
&& data_get($request->data(), 'content.media.id') === 'urn:li:document:E2E'
&& data_get($request->data(), 'content.media.title') === 'deck.pdf';
});
});
test('publish to social platform marks platform as failed on error', function () {
Event::fake();