userRole = Role::create([ 'name' => 'User', 'slug' => 'user', 'description' => 'Regular user', ]); $this->moderatorRole = Role::create([ 'name' => 'Moderator', 'slug' => 'moderator', 'description' => 'Moderator', ]); $this->adminRole = Role::create([ 'name' => 'Admin', 'slug' => 'admin', 'description' => 'Admin', ]); // Create category $this->category = Category::create([ 'name' => 'Test Category', 'slug' => 'test-category', 'description' => 'Test description', ]); }); // ============ UPVOTE TESTS ============ test('authenticated users can upvote a product', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->actingAs($user)->postJson(route('products.upvote', $product)); $response->assertStatus(200); $response->assertJson([ 'success' => true, 'upvoted' => true, 'upvotesCount' => 1, ]); $this->assertDatabaseHas('upvotes', [ 'user_id' => $user->id, 'product_id' => $product->id, ]); }); test('authenticated users can remove their upvote', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); // First upvote Upvote::create([ 'user_id' => $user->id, 'product_id' => $product->id, ]); // Remove upvote $response = $this->actingAs($user)->postJson(route('products.upvote', $product)); $response->assertStatus(200); $response->assertJson([ 'success' => true, 'upvoted' => false, 'upvotesCount' => 0, ]); $this->assertDatabaseMissing('upvotes', [ 'user_id' => $user->id, 'product_id' => $product->id, ]); }); test('guests cannot upvote products', function () { $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->postJson(route('products.upvote', $product)); $response->assertStatus(401); }); test('users cannot upvote the same product twice', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); // First upvote $this->actingAs($user)->postJson(route('products.upvote', $product)); // Second upvote should toggle (remove) $response = $this->actingAs($user)->postJson(route('products.upvote', $product)); $response->assertJson(['upvoted' => false]); expect(Upvote::where('user_id', $user->id)->where('product_id', $product->id)->count())->toBe(0); }); // ============ COMMENT TESTS ============ test('authenticated users can comment on products', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->actingAs($user)->post(route('products.comments.store', $product), [ 'body' => 'This is a great product!', ]); $response->assertRedirect(); $response->assertSessionHas('success'); $this->assertDatabaseHas('comments', [ 'user_id' => $user->id, 'product_id' => $product->id, 'body' => 'This is a great product!', ]); }); test('guests cannot comment on products', function () { $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->post(route('products.comments.store', $product), [ 'body' => 'This is a great product!', ]); $response->assertRedirect(route('login')); }); test('comment body is required', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->actingAs($user)->post(route('products.comments.store', $product), [ 'body' => '', ]); $response->assertSessionHasErrors('body'); }); test('comment body cannot exceed 1000 characters', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->actingAs($user)->post(route('products.comments.store', $product), [ 'body' => str_repeat('a', 1001), ]); $response->assertSessionHasErrors('body'); }); test('comment owners can delete their comments', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $comment = Comment::create([ 'user_id' => $user->id, 'product_id' => $product->id, 'body' => 'Test comment', ]); $response = $this->actingAs($user)->delete(route('comments.destroy', $comment)); $response->assertRedirect(); $response->assertSessionHas('success'); $this->assertDatabaseMissing('comments', ['id' => $comment->id]); }); test('non-owners cannot delete comments', function () { $user1 = User::factory()->create(); $user1->roles()->attach($this->userRole); $user2 = User::factory()->create(); $user2->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $comment = Comment::create([ 'user_id' => $user1->id, 'product_id' => $product->id, 'body' => 'Test comment', ]); $response = $this->actingAs($user2)->delete(route('comments.destroy', $comment)); $response->assertStatus(403); }); test('moderators can delete any comment', function () { $moderator = User::factory()->create(); $moderator->roles()->attach($this->moderatorRole); $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $comment = Comment::create([ 'user_id' => $user->id, 'product_id' => $product->id, 'body' => 'Test comment', ]); $response = $this->actingAs($moderator)->delete(route('comments.destroy', $comment)); $response->assertRedirect(); $response->assertSessionHas('success'); $this->assertDatabaseMissing('comments', ['id' => $comment->id]); }); // ============ BOOKMARK TESTS ============ test('authenticated users can bookmark a product', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->actingAs($user)->postJson(route('products.bookmark', $product)); $response->assertStatus(200); $response->assertJson([ 'success' => true, 'bookmarked' => true, ]); $this->assertDatabaseHas('bookmarks', [ 'user_id' => $user->id, 'product_id' => $product->id, ]); }); test('authenticated users can remove their bookmark', function () { $user = User::factory()->create(); $user->roles()->attach($this->userRole); $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); // First bookmark Bookmark::create([ 'user_id' => $user->id, 'product_id' => $product->id, ]); // Remove bookmark $response = $this->actingAs($user)->postJson(route('products.bookmark', $product)); $response->assertStatus(200); $response->assertJson([ 'success' => true, 'bookmarked' => false, ]); $this->assertDatabaseMissing('bookmarks', [ 'user_id' => $user->id, 'product_id' => $product->id, ]); }); test('guests cannot bookmark products', function () { $owner = User::factory()->create(); $owner->roles()->attach($this->userRole); $product = Product::create([ 'title' => 'Test Product', 'slug' => 'test-product', 'description' => 'Test description', 'website_url' => 'https://example.com', 'user_id' => $owner->id, 'category_id' => $this->category->id, 'status' => 'approved', ]); $response = $this->postJson(route('products.bookmark', $product)); $response->assertStatus(401); });