fakeCommunities(); } private function fakeCommunities(): void { Http::fake(['*/api/v3/community/list*' => Http::response([ 'communities' => [ ['community' => ['id' => 8, 'name' => 'tech_community', 'title' => 'Tech Community']], ['community' => ['id' => 9, 'name' => 'other_community', 'title' => 'Other Community']], ], ])]); } private function instanceWithActiveAccount(): PlatformInstance { $instance = PlatformInstance::factory()->create(['url' => 'https://lemmy.world']); PlatformAccount::factory()->create([ 'instance_url' => 'https://lemmy.world', 'is_active' => true, ]); return $instance; } public function test_add_button_renders_when_channels_exist(): void { PlatformChannel::factory()->create(['name' => 'existing_channel']); Livewire::test(Channels::class) ->assertSee('Add Channel') ->assertSee('existing_channel'); } public function test_add_button_renders_in_empty_state(): void { Livewire::test(Channels::class) ->assertSee('No channels') ->assertSee('Add Channel'); } public function test_open_create_modal_shows_modal(): void { Livewire::test(Channels::class) ->assertSet('showCreateModal', false) ->call('openCreateModal') ->assertSet('showCreateModal', true); } public function test_create_channel_requires_community(): void { $instance = $this->instanceWithActiveAccount(); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->call('createChannel') ->assertHasErrors(['newCommunityId' => 'required']); } public function test_selecting_an_instance_loads_its_communities(): void { $instance = $this->instanceWithActiveAccount(); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->assertSet('communityLoadError', null) ->assertCount('availableCommunities', 2); } public function test_unreachable_instance_surfaces_an_error_and_no_communities(): void { $instance = PlatformInstance::factory()->create(['url' => 'https://unreachable.test']); PlatformAccount::factory()->create(['instance_url' => 'https://unreachable.test', 'is_active' => true]); Cache::flush(); // Http::fake() merges stubs, so setUp's success stub would still win — // swap the whole fake out instead. app()->forgetInstance(Factory::class); Http::swap(new Factory); Http::fake(['*' => Http::response('nope', 500)]); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->assertSet('availableCommunities', []) ->assertNotSet('communityLoadError', null); } public function test_create_channel_requires_platform_instance(): void { Livewire::test(Channels::class) ->call('openCreateModal') ->set('newCommunityId', 8) ->call('createChannel') ->assertHasErrors(['newPlatformInstanceId' => 'required']); } public function test_create_channel_succeeds_and_attaches_account(): void { $instance = $this->instanceWithActiveAccount(); $language = Language::factory()->create(); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->set('newCommunityId', 8) ->set('newLanguageId', $language->id) ->set('newDescription', 'A tech community') ->call('createChannel') ->assertHasNoErrors() ->assertSet('showCreateModal', false); $this->assertDatabaseHas('platform_channels', [ 'name' => 'tech_community', 'display_name' => 'Tech_community', 'platform_instance_id' => $instance->id, 'language_id' => $language->id, 'description' => 'A tech community', 'is_active' => true, ]); $channel = PlatformChannel::where('name', 'tech_community')->firstOrFail(); $this->assertCount(1, $channel->platformAccounts); } public function test_create_channel_leaves_description_null_when_blank(): void { $instance = $this->instanceWithActiveAccount(); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->set('newCommunityId', 8) ->call('createChannel') ->assertHasNoErrors(); $this->assertDatabaseHas('platform_channels', [ 'name' => 'tech_community', 'description' => null, ]); } public function test_create_channel_rejects_a_community_not_on_the_instance(): void { $instance = $this->instanceWithActiveAccount(); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->set('newCommunityId', 4242) ->call('createChannel') ->assertHasErrors(['newCommunityId' => 'in']); $this->assertDatabaseCount('platform_channels', 0); } public function test_create_channel_rejects_duplicate_community_on_same_instance(): void { $instance = $this->instanceWithActiveAccount(); PlatformChannel::factory()->create([ 'platform_instance_id' => $instance->id, 'name' => 'tech_community', 'channel_id' => 8, ]); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->set('newCommunityId', 8) ->call('createChannel') ->assertHasErrors(['newCommunityId' => 'unique']) ->assertSet('showCreateModal', true); $this->assertDatabaseCount('platform_channels', 1); } public function test_create_channel_allows_same_community_on_different_instance(): void { $instanceA = $this->instanceWithActiveAccount(); $instanceB = PlatformInstance::factory()->create(['url' => 'https://lemmy.other']); PlatformAccount::factory()->create([ 'instance_url' => 'https://lemmy.other', 'is_active' => true, ]); PlatformChannel::factory()->create([ 'platform_instance_id' => $instanceB->id, 'name' => 'tech_community', 'channel_id' => 8, ]); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instanceA->id) ->set('newCommunityId', 8) ->call('createChannel') ->assertHasNoErrors(); $this->assertDatabaseCount('platform_channels', 2); } public function test_create_channel_surfaces_no_active_accounts_error(): void { // Instance exists but has no active account for its url. $instance = PlatformInstance::factory()->create(['url' => 'https://lemmy.world']); Livewire::test(Channels::class) ->call('openCreateModal') ->set('newPlatformInstanceId', $instance->id) ->set('newCommunityId', 8) ->call('createChannel') ->assertHasErrors('newPlatformInstanceId') ->assertSet('showCreateModal', true); $this->assertDatabaseCount('platform_channels', 0); } public function test_toggle_flips_active_state(): void { $channel = PlatformChannel::factory()->create(['is_active' => true]); Livewire::test(Channels::class) ->call('toggle', $channel->id); $this->assertFalse($channel->fresh()->is_active); } public function test_channel_cards_show_an_edit_action(): void { PlatformChannel::factory()->create(['display_name' => 'Tech Community']); Livewire::test(Channels::class) ->assertSee('Edit Tech Community'); } public function test_open_edit_modal_prefills_the_current_values(): void { $language = Language::factory()->create(); $channel = PlatformChannel::factory()->create([ 'display_name' => 'Tech Community', 'description' => 'A place for tech', 'language_id' => $language->id, ]); Livewire::test(Channels::class) ->assertSet('editingChannelId', null) ->call('openEditModal', $channel->id) ->assertSet('editingChannelId', $channel->id) ->assertSet('editDisplayName', 'Tech Community') ->assertSet('editDescription', 'A place for tech') ->assertSet('editLanguageId', $language->id) ->assertSee('Edit Channel'); } public function test_open_edit_modal_prefills_a_null_description_as_blank(): void { $channel = PlatformChannel::factory()->create(['description' => null]); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->assertSet('editDescription', ''); } public function test_update_channel_persists_the_changes_and_closes_the_modal(): void { $language = Language::factory()->create(); $channel = PlatformChannel::factory()->create([ 'display_name' => 'Old Name', 'description' => 'Old description', 'language_id' => null, ]); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editDisplayName', 'New Name') ->set('editDescription', 'New description') ->set('editLanguageId', $language->id) ->call('updateChannel') ->assertSet('editingChannelId', null) ->assertHasNoErrors(); $channel->refresh(); $this->assertSame('New Name', $channel->display_name); $this->assertSame('New description', $channel->description); $this->assertSame($language->id, $channel->language_id); } public function test_update_channel_requires_a_display_name(): void { $channel = PlatformChannel::factory()->create(['display_name' => 'Original']); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editDisplayName', '') ->call('updateChannel') ->assertHasErrors(['editDisplayName' => 'required']); $this->assertSame('Original', $channel->fresh()->display_name); } public function test_update_channel_rejects_a_display_name_over_the_length_limit(): void { $channel = PlatformChannel::factory()->create(['display_name' => 'Original']); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editDisplayName', str_repeat('a', 256)) ->call('updateChannel') ->assertHasErrors(['editDisplayName' => 'max']); $this->assertSame('Original', $channel->fresh()->display_name); } public function test_update_channel_rejects_an_unknown_language(): void { $channel = PlatformChannel::factory()->create(['display_name' => 'Original']); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editLanguageId', 999999) ->call('updateChannel') ->assertHasErrors(['editLanguageId' => 'exists']); } public function test_update_channel_allows_clearing_the_language(): void { $language = Language::factory()->create(); $channel = PlatformChannel::factory()->create(['language_id' => $language->id]); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editLanguageId', null) ->call('updateChannel') ->assertHasNoErrors(); $this->assertNull($channel->fresh()->language_id); } public function test_update_channel_stores_a_blank_description_as_null(): void { $channel = PlatformChannel::factory()->create(['description' => 'Has one']); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editDescription', '') ->call('updateChannel'); $this->assertNull($channel->fresh()->description); } public function test_update_channel_leaves_the_community_pairing_untouched(): void { $channel = PlatformChannel::factory()->create(['display_name' => 'Original']); $before = $channel->only(['name', 'channel_id', 'platform_instance_id']); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editDisplayName', 'Renamed') ->call('updateChannel'); $this->assertSame($before, $channel->fresh()->only(['name', 'channel_id', 'platform_instance_id'])); } public function test_close_edit_modal_discards_the_edit(): void { $channel = PlatformChannel::factory()->create(['display_name' => 'Original']); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->set('editDisplayName', 'Discarded') ->call('closeEditModal') ->assertSet('editingChannelId', null); $this->assertSame('Original', $channel->fresh()->display_name); } public function test_update_channel_does_nothing_without_an_open_modal(): void { $channel = PlatformChannel::factory()->create(['display_name' => 'Original']); Livewire::test(Channels::class) ->set('editDisplayName', 'Should not apply') ->call('updateChannel') ->assertHasNoErrors(); $this->assertSame('Original', $channel->fresh()->display_name); } public function test_channel_cards_show_a_delete_action(): void { PlatformChannel::factory()->create(['display_name' => 'Tech Community']); Livewire::test(Channels::class) ->assertSee('Delete Tech Community'); } public function test_deleting_a_channel_removes_it(): void { $channel = PlatformChannel::factory()->create(); $survivor = PlatformChannel::factory()->create(); Livewire::test(Channels::class)->call('deleteChannel', $channel->id); $this->assertDatabaseMissing('platform_channels', ['id' => $channel->id]); $this->assertDatabaseHas('platform_channels', ['id' => $survivor->id]); } public function test_deleting_an_unknown_channel_does_nothing(): void { PlatformChannel::factory()->create(); Livewire::test(Channels::class) ->call('deleteChannel', 999999) ->assertHasNoErrors(); $this->assertSame(1, PlatformChannel::count()); } public function test_deleting_the_channel_being_edited_closes_the_edit_modal(): void { $channel = PlatformChannel::factory()->create(); Livewire::test(Channels::class) ->call('openEditModal', $channel->id) ->assertSet('editingChannelId', $channel->id) ->call('deleteChannel', $channel->id) ->assertSet('editingChannelId', null); } public function test_deleting_the_channel_being_managed_closes_the_account_modal(): void { $channel = PlatformChannel::factory()->create(); Livewire::test(Channels::class) ->call('openAccountModal', $channel->id) ->assertSet('managingChannelId', $channel->id) ->call('deleteChannel', $channel->id) ->assertSet('managingChannelId', null); } public function test_the_confirmation_states_what_will_be_removed(): void { $feed = Feed::factory()->create(); $channel = PlatformChannel::factory()->create(['display_name' => 'Tech Community']); $article = Article::factory()->create(['feed_id' => $feed->id]); RouteArticle::factory()->create([ 'feed_id' => $feed->id, 'platform_channel_id' => $channel->id, 'article_id' => $article->id, ]); ArticlePublication::factory()->create([ 'article_id' => $article->id, 'platform_channel_id' => $channel->id, ]); Livewire::test(Channels::class) ->assertSee('1 article routed to it') ->assertSee('1 publication record'); } public function test_each_card_shows_its_own_counts_not_the_totals(): void { $feed = Feed::factory()->create(); $busy = PlatformChannel::factory()->create(['name' => 'aaa-busy', 'display_name' => 'Busy Channel']); $quiet = PlatformChannel::factory()->create(['name' => 'zzz-quiet', 'display_name' => 'Quiet Channel']); foreach (range(1, 3) as $ignored) { $article = Article::factory()->create(['feed_id' => $feed->id]); RouteArticle::factory()->create([ 'feed_id' => $feed->id, 'platform_channel_id' => $busy->id, 'article_id' => $article->id, ]); } $quietArticle = Article::factory()->create(['feed_id' => $feed->id]); RouteArticle::factory()->create([ 'feed_id' => $feed->id, 'platform_channel_id' => $quiet->id, 'article_id' => $quietArticle->id, ]); Livewire::test(Channels::class) ->assertSee('3 articles routed to it') ->assertSee('1 article routed to it'); } public function test_the_confirmation_pluralises_counts(): void { $feed = Feed::factory()->create(); $channel = PlatformChannel::factory()->create(); foreach (range(1, 2) as $ignored) { $article = Article::factory()->create(['feed_id' => $feed->id]); RouteArticle::factory()->create([ 'feed_id' => $feed->id, 'platform_channel_id' => $channel->id, 'article_id' => $article->id, ]); } Livewire::test(Channels::class) ->assertSee('2 articles routed to it') ->assertSee('0 publication records'); } }