supports(Post::factory()->make(['type' => 'reddit'])))->toBeTrue(); expect($publisher->supports(Post::factory()->make(['type' => 'blog'])))->toBeFalse(); }); test('it rejects a post with no title', function () { $post = Post::factory() ->hasAttached(SocialAccount::factory()->state(['network' => 'reddit']), [], 'socialAccounts') ->create(['type' => 'reddit', 'title' => null, 'target' => 'test']); $result = (new RedditPublisher)->publish($post); expect($result->success)->toBeFalse(); expect($result->attempted)->toBeFalse(); expect($result->error)->toContain('no title'); }); test('it rejects a post with no target subreddit', function () { $post = Post::factory() ->hasAttached(SocialAccount::factory()->state(['network' => 'reddit']), [], 'socialAccounts') ->create(['type' => 'reddit', 'title' => 'Hi', 'target' => null]); $result = (new RedditPublisher)->publish($post); expect($result->success)->toBeFalse(); expect($result->attempted)->toBeFalse(); expect($result->error)->toContain('no target subreddit'); }); test('it rejects a post with no linked reddit account', function () { $post = Post::factory()->create(['type' => 'reddit', 'title' => 'Hi', 'target' => 'test']); $result = (new RedditPublisher)->publish($post); expect($result->success)->toBeFalse(); expect($result->attempted)->toBeFalse(); expect($result->error)->toContain('no linked Reddit social account'); }); test('it publishes successfully via the sidecar', function () { Process::fake([ '*' => Process::result(output: json_encode(['success' => true, 'url' => 'https://reddit.com/r/test/comments/abc123'])), ]); $account = SocialAccount::factory()->create(['network' => 'reddit', 'username' => 'redditor']); $post = Post::factory()->create(['type' => 'reddit', 'title' => 'Hi', 'target' => 'test']); $post->socialAccounts()->attach($account); $result = (new RedditPublisher)->publish($post->fresh()); expect($result->success)->toBeTrue(); expect($result->url)->toBe('https://reddit.com/r/test/comments/abc123'); Process::assertRan(function ($process) use ($account) { return str_contains($process->command[0], 'sidecars/reddit-post/run.sh') && in_array("--username={$account->username}", $process->command) && in_array('--subreddit=test', $process->command); }); }); test('it treats a sidecar-reported failure as an attempted, failed publish', function () { Process::fake([ '*' => Process::result(output: json_encode(['success' => false, 'error' => 'invalid credentials'])), ]); $account = SocialAccount::factory()->create(['network' => 'reddit']); $post = Post::factory()->create(['type' => 'reddit', 'title' => 'Hi', 'target' => 'test']); $post->socialAccounts()->attach($account); $result = (new RedditPublisher)->publish($post->fresh()); expect($result->success)->toBeFalse(); expect($result->attempted)->toBeTrue(); expect($result->error)->toBe('invalid credentials'); }); test('it fails gracefully when the sidecar output is unparseable', function () { Process::fake([ '*' => Process::result(output: 'not json'), ]); $account = SocialAccount::factory()->create(['network' => 'reddit']); $post = Post::factory()->create(['type' => 'reddit', 'title' => 'Hi', 'target' => 'test']); $post->socialAccounts()->attach($account); $result = (new RedditPublisher)->publish($post->fresh()); expect($result->success)->toBeFalse(); expect($result->attempted)->toBeTrue(); expect($result->error)->toContain('unparseable'); });