user = User::factory()->create([]); $this->workspace = Workspace::factory()->create(['user_id' => $this->user->id]); $this->workspace->members()->attach($this->user->id, ['role' => Role::Member->value]); $this->user->update(['current_workspace_id' => $this->workspace->id]); $this->socialAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::LinkedIn, ]); }); // Index tests test('posts index requires authentication', function () { $response = $this->get(route('app.posts.index')); $response->assertRedirect(route('login')); }); test('posts index shows posts for current workspace', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->actingAs($this->user)->get(route('app.posts.index')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Index', false) ->has('posts.data', 1) ); }); test('posts index redirects to create workspace if no workspace', function () { $this->user->update(['current_workspace_id' => null]); $response = $this->actingAs($this->user)->get(route('app.posts.index')); $response->assertRedirect(route('app.workspaces.create')); }); // Calendar tests test('calendar requires authentication', function () { $response = $this->get(route('app.calendar')); $response->assertRedirect(route('login')); }); test('calendar shows posts for current week', function () { $response = $this->actingAs($this->user)->get(route('app.calendar')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Calendar') ->has('workspace') ->has('posts') ->has('currentWeekStart') ->has('view') ); }); test('calendar supports month view', function () { $response = $this->actingAs($this->user)->get(route('app.calendar', ['view' => 'month'])); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->where('view', 'month') ); }); // Create tests test('create requires authentication', function () { $response = $this->get(route('app.posts.create')); $response->assertRedirect(route('login')); }); test('create renders the wizard page', function () { $response = $this->actingAs($this->user)->get(route('app.posts.create')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Create', false) ->where('date', null) ->has('socialAccounts', 1) ->where('socialAccounts.0.id', $this->socialAccount->id) ); }); test('create forwards date query param to the page', function () { $response = $this->actingAs($this->user)->get(route('app.posts.create', ['date' => '2026-06-01'])); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Create', false) ->where('date', '2026-06-01') ); }); test('create redirects to workspaces.create when user has no workspace', function () { $newUser = User::factory()->create(); $response = $this->actingAs($newUser)->get(route('app.posts.create')); $response->assertRedirect(route('app.workspaces.create')); }); // Store tests test('store post requires authentication', function () { $response = $this->post(route('app.posts.store')); $response->assertRedirect(route('login')); }); test('store post redirects to accounts if no social accounts connected', function () { $this->socialAccount->delete(); $response = $this->actingAs($this->user)->post(route('app.posts.store')); $response->assertRedirect(route('app.accounts')); }); test('store post creates draft and redirects to edit', function () { $response = $this->actingAs($this->user)->post(route('app.posts.store')); $response->assertRedirect(); $post = Post::where('workspace_id', $this->workspace->id)->first(); expect($post)->not->toBeNull(); expect($post->status)->toBe(PostStatus::Draft); expect($post->postPlatforms)->toHaveCount(1); }); // Edit tests test('edit post requires authentication', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->get(route('app.posts.edit', $post)); $response->assertRedirect(route('login')); }); test('edit post shows edit page', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $response = $this->actingAs($this->user)->get(route('app.posts.edit', $post)); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Edit') ->has('post') ->has('socialAccounts') ); }); test('edit post returns 404 for post from different workspace', function () { $otherWorkspace = Workspace::factory()->create(); $post = Post::factory()->create([ 'workspace_id' => $otherWorkspace->id, 'user_id' => $this->user->id, ]); $response = $this->actingAs($this->user)->get(route('app.posts.edit', $post)); $response->assertNotFound(); }); test('edit redirects to show for non-editable statuses', function () { foreach ([PostStatus::Published, PostStatus::PartiallyPublished, PostStatus::Publishing] as $status) { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => $status, ]); PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $this->actingAs($this->user) ->get(route('app.posts.edit', $post)) ->assertRedirect(route('app.posts.show', $post)); } }); test('edit allows draft, scheduled, and failed posts', function () { foreach ([PostStatus::Draft, PostStatus::Scheduled, PostStatus::Failed] as $status) { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => $status, ]); PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $this->actingAs($this->user) ->get(route('app.posts.edit', $post)) ->assertOk(); } }); // Update tests test('update post requires authentication', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->put(route('app.posts.update', $post), []); $response->assertRedirect(route('login')); }); test('update post saves changes', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, 'content' => 'Original content', ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'content' => 'Updated content', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], ]); $response->assertRedirect(); $post->refresh(); expect($post->content)->toBe('Updated content'); $postPlatform->refresh(); expect($postPlatform->content_type)->toBe(ContentType::LinkedInPost); }); test('update post cannot update published posts', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Published, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'content' => 'Test content', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], ]); $response->assertRedirect(); }); test('publish now updates scheduled_at to current time', function () { Mail::fake(); $this->freezeTime(); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, 'content' => 'Test content', 'scheduled_at' => now()->addDays(7), ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'publishing', 'content' => 'Test content', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], ]); $response->assertRedirect(); $post->refresh(); expect($post->scheduled_at->toDateTimeString())->toBe(now()->toDateTimeString()); }); // Destroy tests test('destroy post requires authentication', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->delete(route('app.posts.destroy', $post)); $response->assertRedirect(route('login')); }); test('destroy post deletes the post and redirects to posts index', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->actingAs($this->user) ->delete(route('app.posts.destroy', $post)); $response->assertRedirect(route('app.posts.index')); expect(Post::find($post->id))->toBeNull(); }); test('destroy post with redirect param redirects to calendar', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->actingAs($this->user) ->delete(route('app.posts.destroy', $post).'?redirect=app.calendar'); $response->assertRedirect(route('app.calendar')); expect(Post::find($post->id))->toBeNull(); }); test('destroy post with redirect param redirects to specified route', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $response = $this->actingAs($this->user) ->delete(route('app.posts.destroy', $post).'?redirect=app.posts.index'); $response->assertRedirect(route('app.posts.index')); expect(Post::find($post->id))->toBeNull(); }); test('destroy post returns 404 for post from different workspace', function () { $otherWorkspace = Workspace::factory()->create(); $post = Post::factory()->create([ 'workspace_id' => $otherWorkspace->id, 'user_id' => $this->user->id, ]); $response = $this->actingAs($this->user)->delete(route('app.posts.destroy', $post)); $response->assertNotFound(); }); // Label tests test('edit post includes workspace labels', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $label = WorkspaceLabel::factory()->create([ 'workspace_id' => $this->workspace->id, 'name' => 'Marketing', 'color' => '#FF0000', ]); $response = $this->actingAs($this->user)->get(route('app.posts.edit', $post)); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Edit') ->has('labels', 1) ->where('labels.0.name', 'Marketing') ); }); test('update post can attach labels', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $label = WorkspaceLabel::factory()->create([ 'workspace_id' => $this->workspace->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], 'label_ids' => [$label->id], ]); $response->assertRedirect(); $post->refresh(); expect($post->labels)->toHaveCount(1); expect($post->labels->first()->id)->toBe($label->id); }); test('update post can detach labels', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $label = WorkspaceLabel::factory()->create([ 'workspace_id' => $this->workspace->id, ]); $post->labels()->attach($label); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], 'label_ids' => [], ]); $response->assertRedirect(); $post->refresh(); expect($post->labels)->toHaveCount(0); }); test('update post can sync multiple labels', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $label1 = WorkspaceLabel::factory()->create(['workspace_id' => $this->workspace->id]); $label2 = WorkspaceLabel::factory()->create(['workspace_id' => $this->workspace->id]); $label3 = WorkspaceLabel::factory()->create(['workspace_id' => $this->workspace->id]); // Attach initial label $post->labels()->attach($label1); // Update with different labels $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], 'label_ids' => [$label2->id, $label3->id], ]); $response->assertRedirect(); $post->refresh(); expect($post->labels)->toHaveCount(2); expect($post->labels->pluck('id')->toArray())->toEqualCanonicalizing([$label2->id, $label3->id]); }); test('platform metrics returns unsupported when post not published', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $pp = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, 'status' => Status::Pending, ]); $response = $this->actingAs($this->user) ->getJson(route('app.posts.platforms.metrics', ['post' => $post->id, 'postPlatform' => $pp->id])); $response->assertOk(); $response->assertJson(['unsupported' => true, 'reason' => 'not_published']); }); test('platform metrics returns 404 for post in another workspace', function () { $otherWorkspace = Workspace::factory()->create(); $otherPost = Post::factory()->create(['workspace_id' => $otherWorkspace->id]); $pp = PostPlatform::factory()->create([ 'post_id' => $otherPost->id, 'social_account_id' => $this->socialAccount->id, ]); $this->actingAs($this->user) ->getJson(route('app.posts.platforms.metrics', ['post' => $otherPost->id, 'postPlatform' => $pp->id])) ->assertNotFound(); }); test('platform metrics returns 404 when post platform belongs to different post', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $otherPost = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $pp = PostPlatform::factory()->create([ 'post_id' => $otherPost->id, 'social_account_id' => $this->socialAccount->id, ]); $this->actingAs($this->user) ->getJson(route('app.posts.platforms.metrics', ['post' => $post->id, 'postPlatform' => $pp->id])) ->assertNotFound(); }); test('platform metrics dispatches X analytics for X platform', function () { $xAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::X, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, ]); $pp = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $xAccount->id, 'platform' => Platform::X, 'status' => Status::Published, 'platform_post_id' => '1234567890', ]); Http::fake([ 'https://api.x.com/2/tweets/1234567890*' => Http::response([ 'data' => [ 'public_metrics' => [ 'impression_count' => 500, 'like_count' => 42, 'retweet_count' => 7, 'reply_count' => 3, 'quote_count' => 1, 'bookmark_count' => 4, ], ], ], 200), ]); $response = $this->actingAs($this->user) ->getJson(route('app.posts.platforms.metrics', ['post' => $post->id, 'postPlatform' => $pp->id])); $response->assertOk(); $response->assertJsonFragment(['label' => 'Impressions', 'value' => 500]); $response->assertJsonFragment(['label' => 'Likes', 'value' => 42]); }); test('show page renders for non-editable posts', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Published, 'content' => 'Hello world', ]); PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, 'enabled' => true, 'platform_url' => 'https://linkedin.com/posts/abc', ]); $response = $this->actingAs($this->user)->get(route('app.posts.show', $post)); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('posts/Show', false) ->has('post.platforms', 1) ); }); test('show page redirects editable posts to edit', function () { foreach ([PostStatus::Draft, PostStatus::Scheduled, PostStatus::Failed] as $status) { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => $status, ]); $this->actingAs($this->user) ->get(route('app.posts.show', $post)) ->assertRedirect(route('app.posts.edit', $post)); } }); test('destroy blocks published posts', function () { foreach ([PostStatus::Publishing, PostStatus::Published, PostStatus::PartiallyPublished] as $status) { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => $status, ]); $this->actingAs($this->user) ->delete(route('app.posts.destroy', $post)) ->assertRedirect(); expect(Post::find($post->id))->not->toBeNull(); } }); test('show page returns 404 for post in another workspace', function () { $otherWorkspace = Workspace::factory()->create(); $post = Post::factory()->create([ 'workspace_id' => $otherWorkspace->id, 'user_id' => $this->user->id, ]); $this->actingAs($this->user) ->get(route('app.posts.show', $post)) ->assertNotFound(); }); test('update post redirects to show page after publishing', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, 'content' => 'Test', ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'publishing', 'content' => 'Test', 'platforms' => [ ['id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value], ], ]); $response->assertRedirect(route('app.posts.show', $post)); }); test('update post rejects scheduling youtube short with image', function () { $youtubeAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::YouTube, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, 'content' => 'Test', ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $youtubeAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'scheduled', 'scheduled_at' => now()->addDay()->toIso8601String(), 'media' => [ [ 'id' => 'media-1', 'path' => 'media/foo.jpg', 'url' => 'https://example.com/foo.jpg', 'type' => 'image', 'mime_type' => 'image/jpeg', ], ], 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::YouTubeShort->value, ], ], ]); $response->assertSessionHasErrors('platforms.0.content_type'); }); test('update post rejects scheduling instagram reel with no media', function () { $instagramAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::Instagram, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, 'content' => 'Test', ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $instagramAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'scheduled', 'scheduled_at' => now()->addDay()->toIso8601String(), 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::InstagramReel->value, ], ], ]); $response->assertSessionHasErrors('platforms.0.content_type'); }); test('update post rejects invalid instagram aspect_ratio meta', function () { $instagramAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::Instagram, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $instagramAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::InstagramFeed->value, 'meta' => ['aspect_ratio' => '2:1'], ], ], ]); $response->assertSessionHasErrors('platforms.0.meta.aspect_ratio'); }); test('update post accepts valid instagram aspect_ratio meta', function () { $instagramAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::Instagram, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $instagramAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::InstagramFeed->value, 'meta' => ['aspect_ratio' => '4:5'], ], ], ]); $response->assertSessionDoesntHaveErrors('platforms.0.meta.aspect_ratio'); $postPlatform->refresh(); expect(data_get($postPlatform->meta, 'aspect_ratio'))->toBe('4:5'); }); test('scheduling without content_type per platform fails', function () { $youtubeAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::YouTube, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, 'content' => 'Test', ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $youtubeAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'scheduled', 'scheduled_at' => now()->addDay()->toIso8601String(), 'platforms' => [ ['id' => $postPlatform->id], ], ]); $response->assertSessionHasErrors('platforms.0.content_type'); }); test('draft post does not enforce media-vs-content-type compatibility', function () { $youtubeAccount = SocialAccount::factory()->create([ 'workspace_id' => $this->workspace->id, 'platform' => Platform::YouTube, ]); $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $youtubeAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'media' => [ [ 'id' => 'media-1', 'path' => 'media/foo.jpg', 'url' => 'https://example.com/foo.jpg', 'type' => 'image', 'mime_type' => 'image/jpeg', ], ], 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::YouTubeShort->value, ], ], ]); $response->assertSessionDoesntHaveErrors('platforms.0.content_type'); }); test('update post validates label_ids exist', function () { $post = Post::factory()->create([ 'workspace_id' => $this->workspace->id, 'user_id' => $this->user->id, 'status' => PostStatus::Draft, ]); $postPlatform = PostPlatform::factory()->create([ 'post_id' => $post->id, 'social_account_id' => $this->socialAccount->id, ]); $response = $this->actingAs($this->user)->put(route('app.posts.update', $post), [ 'status' => 'draft', 'platforms' => [ [ 'id' => $postPlatform->id, 'content_type' => ContentType::LinkedInPost->value, ], ], 'label_ids' => ['non-existent-uuid'], ]); $response->assertSessionHasErrors('label_ids.0'); }); // Member authorization tests test('member can view posts index', function () { $member = User::factory()->create([ 'account_id' => $this->workspace->account_id, ]); $this->workspace->members()->attach($member->id, ['role' => Role::Member->value]); $member->update(['current_workspace_id' => $this->workspace->id]); $response = $this->actingAs($member)->get(route('app.posts.index')); $response->assertOk(); }); test('member can create post', function () { $member = User::factory()->create([ 'account_id' => $this->workspace->account_id, ]); $this->workspace->members()->attach($member->id, ['role' => Role::Member->value]); $member->update(['current_workspace_id' => $this->workspace->id]); $response = $this->actingAs($member)->post(route('app.posts.store')); $response->assertRedirect(); });