create(); $artwork = Artwork::factory()->create(); $this->actingAs($user) ->postJson("/api/artworks/{$artwork->id}/comments", [ 'content' => 'Great work! Really love the **colours**.', ]) ->assertStatus(201) ->assertJsonPath('data.user.id', $user->id) ->assertJsonStructure(['data' => ['id', 'raw_content', 'rendered_content', 'user']]); }); test('guest cannot post a comment', function () { $artwork = Artwork::factory()->create(); $this->postJson("/api/artworks/{$artwork->id}/comments", ['content' => 'Nice!']) ->assertStatus(401); }); test('comment with raw HTML is rejected via validation', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); $this->actingAs($user) ->postJson("/api/artworks/{$artwork->id}/comments", [ 'content' => '', ]) ->assertStatus(422); }); test('user can view comments on public artwork', function () { $artwork = Artwork::factory()->create(); $comment = ArtworkComment::factory()->create(['artwork_id' => $artwork->id]); $this->getJson("/api/artworks/{$artwork->id}/comments") ->assertStatus(200) ->assertJsonStructure(['data', 'meta']) ->assertJsonCount(1, 'data'); }); // ── Reactions ───────────────────────────────────────────────────────────────── test('authenticated user can add an artwork reaction', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); $this->actingAs($user) ->postJson("/api/artworks/{$artwork->id}/reactions", [ 'reaction' => ReactionType::Heart->value, ]) ->assertStatus(200) ->assertJsonPath('reaction', ReactionType::Heart->value) ->assertJsonPath('active', true); }); test('reaction is toggled off when posted twice', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); // First toggle — on $this->actingAs($user) ->postJson("/api/artworks/{$artwork->id}/reactions", [ 'reaction' => ReactionType::ThumbsUp->value, ]) ->assertJsonPath('active', true); // Second toggle — off $this->actingAs($user) ->postJson("/api/artworks/{$artwork->id}/reactions", [ 'reaction' => ReactionType::ThumbsUp->value, ]) ->assertJsonPath('active', false); }); test('guest cannot add a reaction', function () { $artwork = Artwork::factory()->create(); $this->postJson("/api/artworks/{$artwork->id}/reactions", [ 'reaction' => ReactionType::Fire->value, ])->assertStatus(401); }); test('invalid reaction slug is rejected', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); $this->actingAs($user) ->postJson("/api/artworks/{$artwork->id}/reactions", [ 'reaction' => 'not_valid_slug', ]) ->assertStatus(422); }); test('reaction totals are returned for public artworks', function () { $artwork = Artwork::factory()->create(); $user = User::factory()->create(); // Insert a reaction directly \Illuminate\Support\Facades\DB::table('artwork_reactions')->insert([ 'artwork_id' => $artwork->id, 'user_id' => $user->id, 'reaction' => ReactionType::Clap->value, 'created_at' => now(), ]); $this->getJson("/api/artworks/{$artwork->id}/reactions") ->assertStatus(200) ->assertJsonPath('totals.' . ReactionType::Clap->value . '.count', 1) ->assertJsonPath('totals.' . ReactionType::Clap->value . '.emoji', '👏'); }); test('user can react to a comment', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); $comment = ArtworkComment::factory()->create(['artwork_id' => $artwork->id]); $this->actingAs($user) ->postJson("/api/comments/{$comment->id}/reactions", [ 'reaction' => ReactionType::Laugh->value, ]) ->assertStatus(200) ->assertJsonPath('active', true) ->assertJsonPath('entity_type', 'comment'); }); test('reaction uniqueness per user per slug', function () { $user = User::factory()->create(); $artwork = Artwork::factory()->create(); $slug = ReactionType::Wow->value; // Toggle on $this->actingAs($user)->postJson("/api/artworks/{$artwork->id}/reactions", ['reaction' => $slug]); // DB should have exactly 1 row $this->assertDatabaseCount('artwork_reactions', 1); // Toggle off $this->actingAs($user)->postJson("/api/artworks/{$artwork->id}/reactions", ['reaction' => $slug]); // DB should have 0 rows $this->assertDatabaseCount('artwork_reactions', 0); });