|
- using CartWise.Application.Services;
- using CartWise.Infrastructure.Data;
- using Microsoft.EntityFrameworkCore;
-
- namespace CartWise.Application.Tests;
-
- public class ShoppingListServiceTests : IDisposable
- {
- private readonly CartWiseDbContext _db;
- private readonly ShoppingListService _sut;
-
- public ShoppingListServiceTests()
- {
- var options = new DbContextOptionsBuilder<CartWiseDbContext>()
- .UseInMemoryDatabase(Guid.NewGuid().ToString())
- .Options;
-
- _db = new CartWiseDbContext(options);
- _sut = new ShoppingListService(_db, TimeProvider.System);
- }
-
- public void Dispose()
- {
- _db.Dispose();
- GC.SuppressFinalize(this);
- }
-
- [Fact]
- public async Task CreateListAsync_CreatesActiveList()
- {
- var householdId = Guid.NewGuid();
-
- var result = await _sut.CreateListAsync(householdId, "Groceries", "user-1");
-
- Assert.True(result.IsSuccess);
- Assert.Equal("Groceries", result.Value!.Name);
- Assert.Equal(householdId, result.Value.HouseholdId);
- }
-
- [Fact]
- public async Task CreateListAsync_FailsWhenHouseholdAlreadyHasAnActiveList()
- {
- var householdId = Guid.NewGuid();
- await _sut.CreateListAsync(householdId, "Groceries", "user-1");
-
- var result = await _sut.CreateListAsync(householdId, "Second List", "user-1");
-
- Assert.False(result.IsSuccess);
- Assert.NotNull(result.Error);
- }
-
- [Fact]
- public async Task CreateListAsync_FailsWhenNameIsMissing()
- {
- var result = await _sut.CreateListAsync(Guid.NewGuid(), " ", "user-1");
-
- Assert.False(result.IsSuccess);
- }
-
- [Fact]
- public async Task GetActiveListAsync_ReturnsNullWhenHouseholdHasNoList()
- {
- var list = await _sut.GetActiveListAsync(Guid.NewGuid());
-
- Assert.Null(list);
- }
-
- [Fact]
- public async Task GetActiveListAsync_ReturnsTheActiveList()
- {
- var householdId = Guid.NewGuid();
- var created = await _sut.CreateListAsync(householdId, "Groceries", "user-1");
-
- var list = await _sut.GetActiveListAsync(householdId);
-
- Assert.NotNull(list);
- Assert.Equal(created.Value!.ShoppingListId, list!.ShoppingListId);
- }
-
- [Fact]
- public async Task GetActiveListAsync_DoesNotReturnAnotherHouseholdsList()
- {
- var householdA = Guid.NewGuid();
- var householdB = Guid.NewGuid();
- await _sut.CreateListAsync(householdA, "Household A's List", "user-1");
-
- var list = await _sut.GetActiveListAsync(householdB);
-
- Assert.Null(list);
- }
-
- [Fact]
- public async Task AddItemAsync_AddsItemAndPersistsIt()
- {
- var created = await _sut.CreateListAsync(Guid.NewGuid(), "Groceries", "user-1");
-
- var result = await _sut.AddItemAsync(created.Value!.ShoppingListId, "Milk", 2m, "gal", "user-1");
-
- Assert.True(result.IsSuccess);
- Assert.Equal("Milk", result.Value!.DisplayName);
-
- var reloaded = await _sut.GetActiveListAsync(created.Value.HouseholdId);
- Assert.Single(reloaded!.Items);
- Assert.Equal("Milk", reloaded.Items.Single().DisplayName);
- }
-
- [Fact]
- public async Task AddItemAsync_FailsWhenListDoesNotExist()
- {
- var result = await _sut.AddItemAsync(Guid.NewGuid(), "Milk", null, null, "user-1");
-
- Assert.False(result.IsSuccess);
- }
-
- [Fact]
- public async Task AddItemAsync_FailsWhenDisplayNameIsMissing()
- {
- var created = await _sut.CreateListAsync(Guid.NewGuid(), "Groceries", "user-1");
-
- var result = await _sut.AddItemAsync(created.Value!.ShoppingListId, " ", null, null, "user-1");
-
- Assert.False(result.IsSuccess);
- }
-
- [Fact]
- public async Task TogglePurchasedAsync_MarksItemPurchased()
- {
- var (householdId, item) = await CreateItemAsync();
-
- var result = await _sut.TogglePurchasedAsync(householdId, item.ShoppingListItemId, item.RowVersion);
-
- Assert.True(result.IsSuccess);
- Assert.Equal(Domain.Enums.ShoppingListItemStatus.Purchased, result.Value!.Status);
- }
-
- [Fact]
- public async Task TogglePurchasedAsync_FailsForItemInAnotherHousehold()
- {
- var (_, item) = await CreateItemAsync();
-
- var result = await _sut.TogglePurchasedAsync(Guid.NewGuid(), item.ShoppingListItemId, item.RowVersion);
-
- Assert.False(result.IsSuccess);
- }
-
- [Fact]
- public async Task TogglePurchasedAsync_FailsOnConcurrencyConflict()
- {
- var (householdId, item) = await CreateItemAsync();
- var staleRowVersion = Guid.NewGuid();
-
- var result = await _sut.TogglePurchasedAsync(householdId, item.ShoppingListItemId, staleRowVersion);
-
- Assert.False(result.IsSuccess);
- Assert.NotNull(result.Error);
- }
-
- [Fact]
- public async Task ToggleSkippedAsync_MarksItemSkipped()
- {
- var (householdId, item) = await CreateItemAsync();
-
- var result = await _sut.ToggleSkippedAsync(householdId, item.ShoppingListItemId, item.RowVersion);
-
- Assert.True(result.IsSuccess);
- Assert.Equal(Domain.Enums.ShoppingListItemStatus.Skipped, result.Value!.Status);
- }
-
- [Fact]
- public async Task ToggleSkippedAsync_UnskipsOnSecondCall()
- {
- var (householdId, item) = await CreateItemAsync();
- var firstResult = await _sut.ToggleSkippedAsync(householdId, item.ShoppingListItemId, item.RowVersion);
-
- var secondResult = await _sut.ToggleSkippedAsync(householdId, item.ShoppingListItemId, firstResult.Value!.RowVersion);
-
- Assert.True(secondResult.IsSuccess);
- Assert.Equal(Domain.Enums.ShoppingListItemStatus.Needed, secondResult.Value!.Status);
- }
-
- [Fact]
- public async Task DeleteItemAsync_RemovesItemFromList()
- {
- var (householdId, item) = await CreateItemAsync();
-
- var result = await _sut.DeleteItemAsync(householdId, item.ShoppingListItemId, item.RowVersion);
-
- Assert.True(result.IsSuccess);
- var list = await _sut.GetActiveListAsync(householdId);
- Assert.Empty(list!.Items);
- }
-
- [Fact]
- public async Task DeleteItemAsync_FailsForItemInAnotherHousehold()
- {
- var (_, item) = await CreateItemAsync();
-
- var result = await _sut.DeleteItemAsync(Guid.NewGuid(), item.ShoppingListItemId, item.RowVersion);
-
- Assert.False(result.IsSuccess);
- }
-
- [Fact]
- public async Task DeleteItemAsync_FailsOnConcurrencyConflict()
- {
- var (householdId, item) = await CreateItemAsync();
- var staleRowVersion = Guid.NewGuid();
-
- var result = await _sut.DeleteItemAsync(householdId, item.ShoppingListItemId, staleRowVersion);
-
- Assert.False(result.IsSuccess);
- var list = await _sut.GetActiveListAsync(householdId);
- Assert.Single(list!.Items);
- }
-
- private async Task<(Guid HouseholdId, Domain.Entities.ShoppingListItem Item)> CreateItemAsync()
- {
- var householdId = Guid.NewGuid();
- var list = await _sut.CreateListAsync(householdId, "Groceries", "user-1");
- var item = await _sut.AddItemAsync(list.Value!.ShoppingListId, "Milk", null, null, "user-1");
-
- return (householdId, item.Value!);
- }
- }
|