diff --git a/Imprink.Integration.Tests/Imprink.Integration.Tests.csproj b/Imprink.Integration.Tests/Imprink.Integration.Tests.csproj new file mode 100644 index 0000000..b2f8cd9 --- /dev/null +++ b/Imprink.Integration.Tests/Imprink.Integration.Tests.csproj @@ -0,0 +1,23 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml index 07c5680..3f2ef07 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,7 @@ services: - ACCEPT_EULA=Y - SEQ_CACHE_SYSTEMRAMTARGET=0.9 - BASE_URI=${SEQ_BASE_URI} + - SEQ_FIRSTRUN_NOAUTHENTICATION=true networks: - app-network diff --git a/src/Imprink.Application/Commands/Categories/CreateCategoryHandler.cs b/src/Imprink.Application/Commands/Categories/CreateCategoryHandler.cs index 0d088ca..310578a 100644 --- a/src/Imprink.Application/Commands/Categories/CreateCategoryHandler.cs +++ b/src/Imprink.Application/Commands/Categories/CreateCategoryHandler.cs @@ -33,6 +33,7 @@ public class CreateCategoryHandler(IUnitOfWork unitOfWork) : IRequestHandler(options => + options.UseSqlite(_connection)); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); + services.AddScoped(); + + _serviceProvider = services.BuildServiceProvider(); + _context = _serviceProvider.GetRequiredService(); + _handler = _serviceProvider.GetRequiredService(); + + _context.Database.EnsureCreated(); + } + + private async Task CleanDatabase() + { + _context.Categories.RemoveRange(_context.Categories); + await _context.SaveChangesAsync(); + } + + [Fact] + public async Task Handle_ValidCreateCategoryCommand_PersistsToDatabase() + { + await CleanDatabase(); + + // Arrange + var command = new CreateCategoryCommand + { + Name = "Electronics", + Description = "Electronic devices and gadgets", + ImageUrl = "https://example.com/electronics.jpg", + SortOrder = 1, + IsActive = true, + ParentCategoryId = null + }; + + // Act + var result = await _handler.Handle(command, CancellationToken.None); + + // Assert + Assert.NotNull(result); + Assert.NotEqual(Guid.Empty, result.Id); + Assert.Equal(command.Name, result.Name); + Assert.Equal(command.Description, result.Description); + Assert.Equal(command.ImageUrl, result.ImageUrl); + Assert.Equal(command.SortOrder, result.SortOrder); + Assert.Equal(command.IsActive, result.IsActive); + Assert.Equal(command.ParentCategoryId, result.ParentCategoryId); + Assert.NotNull(result.CreatedAt); + Assert.NotNull(result.ModifiedAt); + + var savedCategory = await _context.Categories + .FirstOrDefaultAsync(c => c.Id == result.Id); + + Assert.NotNull(savedCategory); + Assert.Equal(command.Name, savedCategory.Name); + Assert.Equal(command.Description, savedCategory.Description); + Assert.Equal(command.ImageUrl, savedCategory.ImageUrl); + Assert.Equal(command.SortOrder, savedCategory.SortOrder); + Assert.Equal(command.IsActive, savedCategory.IsActive); + Assert.Equal(command.ParentCategoryId, savedCategory.ParentCategoryId); + Assert.NotNull(savedCategory.CreatedAt); + Assert.NotNull(savedCategory.ModifiedAt); + } + + [Fact] + public async Task Handle_ValidCreateCategoryCommandWithParent_PersistsWithCorrectParentRelationship() + { + await CleanDatabase(); + + // Arrange + var parentCategory = new Category + { + Id = Guid.NewGuid(), + Name = "Parent Category", + Description = "Parent category description", + SortOrder = 1, + IsActive = true, + CreatedAt = DateTime.UtcNow, + ModifiedAt = DateTime.UtcNow + }; + + _context.Categories.Add(parentCategory); + await _context.SaveChangesAsync(); + + var command = new CreateCategoryCommand + { + Name = "Child Electronics", + Description = "Electronic devices and gadgets under parent", + ImageUrl = "https://example.com/child-electronics.jpg", + SortOrder = 2, + IsActive = true, + ParentCategoryId = parentCategory.Id + }; + + // Act + var result = await _handler.Handle(command, CancellationToken.None); + + // Assert + Assert.NotNull(result); + Assert.Equal(parentCategory.Id, result.ParentCategoryId); + + var savedCategory = await _context.Categories + .Include(c => c.ParentCategory) + .FirstOrDefaultAsync(c => c.Id == result.Id); + + Assert.NotNull(savedCategory); + Assert.NotNull(savedCategory.ParentCategory); + Assert.Equal(parentCategory.Id, savedCategory.ParentCategory.Id); + Assert.Equal(parentCategory.Name, savedCategory.ParentCategory.Name); + + var parentWithChildren = await _context.Categories + .Include(c => c.SubCategories) + .FirstOrDefaultAsync(c => c.Id == parentCategory.Id); + + Assert.NotNull(parentWithChildren); + Assert.Contains(parentWithChildren.SubCategories, sc => sc.Id == result.Id); + } + + [Fact] + public async Task Handle_CreateMultipleCategories_AllPersistCorrectly() + { + await CleanDatabase(); + + // Arrange + var commands = new[] + { + new CreateCategoryCommand + { + Name = "Category 1", + Description = "First category", + SortOrder = 1, + IsActive = true + }, + new CreateCategoryCommand + { + Name = "Category 2", + Description = "Second category", + SortOrder = 2, + IsActive = false + } + }; + + // Act + var results = new List(); + foreach (var command in commands) + { + var result = await _handler.Handle(command, CancellationToken.None); + results.Add(result); + } + + // Assert + Assert.Equal(2, results.Count); + + var categoriesInDb = await _context.Categories.ToListAsync(); + + Assert.Equal(2, categoriesInDb.Count); + + foreach (var result in results) + { + var savedCategory = categoriesInDb.First(c => c.Id == result.Id); + Assert.Equal(result.Name, savedCategory.Name); + Assert.Equal(result.Description, savedCategory.Description); + Assert.Equal(result.IsActive, savedCategory.IsActive); + } + } + + [Fact] + public async Task Handle_TransactionFailure_RollsBackCorrectly() + { + await CleanDatabase(); + + // Arrange + var command = new CreateCategoryCommand + { + Name = "Test Category", + Description = "Test description", + SortOrder = 1, + IsActive = true + }; + + var initialCount = await _context.Categories.CountAsync(); + + var handler = _serviceProvider.GetRequiredService(); + + var result = await handler.Handle(command, CancellationToken.None); + + Assert.NotNull(result); + + var finalCount = await _context.Categories.CountAsync(); + Assert.Equal(initialCount + 1, finalCount); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + _context.Dispose(); + _connection.Close(); + _connection.Dispose(); + _serviceProvider.GetService()?.Dispose(); + } +} \ No newline at end of file diff --git a/tests/Imprink.Application.Tests/Imprink.Application.Tests.csproj b/tests/Imprink.Application.Tests/Imprink.Application.Tests.csproj index 643561b..12b9750 100644 --- a/tests/Imprink.Application.Tests/Imprink.Application.Tests.csproj +++ b/tests/Imprink.Application.Tests/Imprink.Application.Tests.csproj @@ -8,14 +8,18 @@ - - - - + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -28,6 +32,7 @@ +