create(); $actor = User::factory()->create(); $artwork = Artwork::factory()->create(['user_id' => $owner->id]); $this->actingAs($actor) ->postJson('/api/like', [ 'entity_type' => 'artwork', 'entity_id' => $artwork->id, 'state' => true, ]) ->assertOk() ->assertJsonPath('is_liked', true) ->assertJsonPath('stats.likes', 1); $this->assertDatabaseHas('artwork_likes', [ 'artwork_id' => $artwork->id, 'user_id' => $actor->id, ]); $notification = $owner->fresh() ->notifications() ->where('type', 'artwork_liked') ->latest() ->first(); expect($notification)->not->toBeNull(); expect($notification->data['type'] ?? null)->toBe('artwork_liked'); expect($notification->data['actor_id'] ?? null)->toBe($actor->id); }); test('authenticated user can comment on artwork through generic social endpoint and send owner and mention notifications', function () { $owner = User::factory()->create(); $actor = User::factory()->create(); $mentioned = User::factory()->create(); $artwork = Artwork::factory()->create(['user_id' => $owner->id]); $this->actingAs($actor) ->postJson('/api/comments', [ 'entity_type' => 'artwork', 'entity_id' => $artwork->id, 'content' => 'Great work @' . $mentioned->username, ]) ->assertCreated() ->assertJsonPath('data.user.id', $actor->id); $comment = ArtworkComment::query()->latest('id')->first(); expect($comment)->not->toBeNull(); expect($comment->artwork_id)->toBe($artwork->id); $ownerNotification = $owner->fresh() ->notifications() ->where('type', 'artwork_commented') ->latest() ->first(); $mentionedNotification = $mentioned->fresh() ->notifications() ->where('type', 'artwork_mentioned') ->latest() ->first(); expect($ownerNotification)->not->toBeNull(); expect($ownerNotification->data['type'] ?? null)->toBe('artwork_commented'); expect($mentionedNotification)->not->toBeNull(); expect($mentionedNotification->data['type'] ?? null)->toBe('artwork_mentioned'); $this->assertDatabaseHas('user_mentions', [ 'comment_id' => $comment->id, 'mentioned_user_id' => $mentioned->id, ]); }); test('generic comments endpoint lists artwork comments', function () { $artwork = Artwork::factory()->create(); $comment = ArtworkComment::factory()->create(['artwork_id' => $artwork->id]); $this->getJson('/api/comments?entity_type=artwork&entity_id=' . $artwork->id) ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.id', $comment->id); }); test('authenticated user can bookmark artwork through generic endpoint and see it in bookmarks list', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); $this->actingAs($user) ->postJson('/api/bookmark', [ 'entity_type' => 'artwork', 'entity_id' => $artwork->id, 'state' => true, ]) ->assertOk() ->assertJsonPath('is_bookmarked', true) ->assertJsonPath('stats.bookmarks', 1); $this->assertDatabaseHas('artwork_bookmarks', [ 'artwork_id' => $artwork->id, 'user_id' => $user->id, ]); $this->actingAs($user) ->getJson('/api/bookmarks?entity_type=artwork') ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.type', 'artwork') ->assertJsonPath('data.0.id', $artwork->id); }); test('authenticated user can like and bookmark a story through generic social endpoints', function () { $owner = User::factory()->create(); $actor = User::factory()->create(); $story = Story::query()->create([ 'creator_id' => $owner->id, 'title' => 'Published Story', 'slug' => 'published-story-' . strtolower((string) \Illuminate\Support\Str::random(6)), 'content' => '
Story body
', 'story_type' => 'creator_story', 'status' => 'published', 'published_at' => now()->subMinute(), ]); $this->actingAs($actor) ->postJson('/api/like', [ 'entity_type' => 'story', 'entity_id' => $story->id, 'state' => true, ]) ->assertOk() ->assertJsonPath('is_liked', true) ->assertJsonPath('stats.likes', 1); $this->assertDatabaseHas('story_likes', [ 'story_id' => $story->id, 'user_id' => $actor->id, ]); $likeNotification = $owner->fresh() ->notifications() ->where('type', 'story_liked') ->latest() ->first(); expect($likeNotification)->not->toBeNull(); expect($likeNotification->data['type'] ?? null)->toBe('story_liked'); $this->actingAs($actor) ->postJson('/api/bookmark', [ 'entity_type' => 'story', 'entity_id' => $story->id, 'state' => true, ]) ->assertOk() ->assertJsonPath('is_bookmarked', true) ->assertJsonPath('stats.bookmarks', 1); $this->assertDatabaseHas('story_bookmarks', [ 'story_id' => $story->id, 'user_id' => $actor->id, ]); $this->actingAs($actor) ->getJson('/api/bookmarks?entity_type=story') ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.type', 'story') ->assertJsonPath('data.0.id', $story->id); }); test('authenticated user can comment on a story through generic social endpoint and send owner and mention notifications', function () { $owner = User::factory()->create(); $actor = User::factory()->create(); $mentioned = User::factory()->create(); $story = Story::query()->create([ 'creator_id' => $owner->id, 'title' => 'Commentable Story', 'slug' => 'commentable-story-' . strtolower((string) \Illuminate\Support\Str::random(6)), 'content' => 'Story body
', 'story_type' => 'creator_story', 'status' => 'published', 'published_at' => now()->subMinute(), ]); $this->actingAs($actor) ->postJson('/api/comments', [ 'entity_type' => 'story', 'entity_id' => $story->id, 'content' => 'Great story @' . $mentioned->username, ]) ->assertCreated() ->assertJsonPath('data.user.id', $actor->id); $this->assertDatabaseHas('story_comments', [ 'story_id' => $story->id, 'user_id' => $actor->id, ]); $ownerNotification = $owner->fresh() ->notifications() ->where('type', 'story_commented') ->latest() ->first(); $mentionedNotification = $mentioned->fresh() ->notifications() ->where('type', 'story_mentioned') ->latest() ->first(); expect($ownerNotification)->not->toBeNull(); expect($ownerNotification->data['type'] ?? null)->toBe('story_commented'); expect($mentionedNotification)->not->toBeNull(); expect($mentionedNotification->data['type'] ?? null)->toBe('story_mentioned'); $this->actingAs($actor) ->getJson('/api/comments?entity_type=story&entity_id=' . $story->id) ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.user.id', $actor->id); });