Conversation
9f6978d to
f00799c
Compare
🏗️ PR Added to Squad Triage QueueThis PR has been labeled with Next steps:
|
Test Results Summary0 tests 0 ✅ 0s ⏱️ Results for commit f00799c. |
Test Results Summary0 tests 0 ✅ 0s ⏱️ Results for commit f00799c. |
There was a problem hiding this comment.
Pull request overview
Adds soft-delete (archive) coverage for Category and Status by introducing new unit and integration tests, plus updating DI registration tests and endpoint tests to cover the new DELETE routes.
Changes:
- Added unit tests for
DeleteCategoryHandlerandDeleteStatusHandler. - Added endpoint tests for
DELETE /api/v1/categories/{id}andDELETE /api/v1/statuses/{id}(204/401/404 paths). - Added integration tests that validate archived records are updated in MongoDB and excluded from paginated lists.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Api.Tests.Unit/Handlers/Statuses/DeleteStatusHandlerTests.cs | New unit tests for delete-status handler behavior. |
| tests/Api.Tests.Unit/Handlers/Categories/DeleteCategoryHandlerTests.cs | New unit tests for delete-category handler behavior. |
| tests/Api.Tests.Unit/Extensions/ServiceCollectionExtensionsTests.cs | Ensures new delete handlers are registered in DI. |
| tests/Api.Tests.Unit/Endpoints/StatusEndpointsTests.cs | Adds endpoint-level DELETE status coverage (204/401/404). |
| tests/Api.Tests.Unit/Endpoints/CategoryEndpointsTests.cs | Adds endpoint-level DELETE category coverage (204/401/404). |
| tests/Api.Tests.Integration/Handlers/DeleteStatusHandlerIntegrationTests.cs | New MongoDB-backed integration coverage for status archiving/list exclusion. |
| tests/Api.Tests.Integration/Handlers/DeleteCategoryHandlerIntegrationTests.cs | New MongoDB-backed integration coverage for category archiving/list exclusion. |
| // ======================================================= | ||
| // Copyright (c) 2026. All rights reserved. | ||
| // File Name : DeleteStatusHandlerIntegrationTests.cs | ||
| // Company : mpaulosky | ||
| // Author : Matthew Paulosky | ||
| // Solution Name : IssueManager | ||
| // Project Name : Api.Tests.Integration | ||
| // ======================================================= |
| // ======================================================= | ||
| // Copyright (c) 2026. All rights reserved. | ||
| // File Name : DeleteCategoryHandlerIntegrationTests.cs | ||
| // Company : mpaulosky | ||
| // Author : Matthew Paulosky | ||
| // Solution Name : IssueManager | ||
| // Project Name : Api.Tests.Integration | ||
| // ======================================================= |
| // ======================================================= | ||
| // Copyright (c) 2026. All rights reserved. | ||
| // File Name : DeleteStatusHandlerTests.cs | ||
| // Company : mpaulosky | ||
| // Author : Matthew Paulosky | ||
| // Solution Name : IssueManager | ||
| // Project Name : Api.Tests.Unit | ||
| // ======================================================= |
| public async Task Handle_ValidStatus_PassesCancellationToken() | ||
| { | ||
| // Arrange | ||
| var statusId = ObjectId.GenerateNewId(); | ||
| var cancellationToken = new CancellationToken(); | ||
| var status = new StatusDto( | ||
| statusId, | ||
| "Test Status", | ||
| "Test Description", | ||
| DateTime.UtcNow, | ||
| null, | ||
| false, | ||
| UserDto.Empty); | ||
|
|
||
| var command = new DeleteStatusCommand { Id = statusId }; | ||
|
|
||
| _repository.GetByIdAsync(statusId, Arg.Any<CancellationToken>()) | ||
| .Returns(Result<StatusDto>.Ok(status)); | ||
|
|
||
| _repository.ArchiveAsync(statusId, Arg.Any<CancellationToken>()) | ||
| .Returns(Result.Ok()); | ||
|
|
||
| // Act | ||
| await _handler.Handle(command, cancellationToken); | ||
|
|
||
| // Assert | ||
| await _repository.Received(1).GetByIdAsync(statusId, Arg.Any<CancellationToken>()); | ||
| await _repository.Received(1).ArchiveAsync(statusId, Arg.Any<CancellationToken>()); |
| // ======================================================= | ||
| // Copyright (c) 2026. All rights reserved. | ||
| // File Name : DeleteCategoryHandlerTests.cs | ||
| // Company : mpaulosky | ||
| // Author : Matthew Paulosky | ||
| // Solution Name : IssueManager | ||
| // Project Name : Api.Tests.Unit | ||
| // ======================================================= |
| public async Task Handle_ValidCategory_PassesCancellationToken() | ||
| { | ||
| // Arrange | ||
| var categoryId = ObjectId.GenerateNewId(); | ||
| var cancellationToken = new CancellationToken(); | ||
| var category = new CategoryDto( | ||
| categoryId, | ||
| "Test Category", | ||
| "Test Description", | ||
| DateTime.UtcNow, | ||
| null, | ||
| false, | ||
| UserDto.Empty); | ||
|
|
||
| var command = new DeleteCategoryCommand { Id = categoryId }; | ||
|
|
||
| _repository.GetByIdAsync(categoryId, Arg.Any<CancellationToken>()) | ||
| .Returns(Result<CategoryDto>.Ok(category)); | ||
|
|
||
| _repository.ArchiveAsync(categoryId, Arg.Any<CancellationToken>()) | ||
| .Returns(Result.Ok()); | ||
|
|
||
| // Act | ||
| await _handler.Handle(command, cancellationToken); | ||
|
|
||
| // Assert | ||
| await _repository.Received(1).GetByIdAsync(categoryId, Arg.Any<CancellationToken>()); | ||
| await _repository.Received(1).ArchiveAsync(categoryId, Arg.Any<CancellationToken>()); |
| { | ||
| fixture.ThrowIfUnavailable(); | ||
| _repository = new StatusRepository(fixture.ConnectionString, $"T{Guid.NewGuid():N}"); | ||
| _handler = new DeleteStatusHandler(_repository, new DeleteStatusValidator()); |
| { | ||
| fixture.ThrowIfUnavailable(); | ||
| _repository = new CategoryRepository(fixture.ConnectionString, $"T{Guid.NewGuid():N}"); | ||
| _handler = new DeleteCategoryHandler(_repository, new DeleteCategoryValidator()); |
…rage - Add DeleteCategoryCommand and DeleteCategoryValidator in Shared - Add DeleteStatusCommand and DeleteStatusValidator in Shared - Add DeleteCategoryHandler for soft-delete/archive of categories - Add DeleteStatusHandler for soft-delete/archive of statuses - Add DELETE routes to CategoryEndpoints and StatusEndpoints - Register new handlers and validators in ServiceCollectionExtensions - Add unit tests: DeleteCategoryHandlerTests and DeleteStatusHandlerTests - Add endpoint tests for delete to CategoryEndpointsTests and StatusEndpointsTests - Add integration tests: DeleteCategoryHandlerIntegrationTests and DeleteStatusHandlerIntegrationTests - Update ServiceCollectionExtensions tests to include new handlers/validators Closes #122 Agent-Logs-Url: https://github.com/mpaulosky/IssueManager/sessions/d979c7cf-da30-47e8-9ea3-9727c87db432 Co-authored-by: mpaulosky <60372079+mpaulosky@users.noreply.github.com>
…rences — handlers use inline validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ructors DeleteCategoryHandler and DeleteStatusHandler use inline validation and take only IRepository in their constructors — no validator class exists. Matches the pattern already fixed in the unit test project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
f00799c to
2120436
Compare
…d statuses found GetAllAsync paginated was returning Result.Fail when count=0, causing the integration test to receive a null Items collection. Now consistent with CategoryRepository which always returns Result.Ok with an empty list. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #132 +/- ##
==========================================
+ Coverage 54.52% 55.81% +1.29%
==========================================
Files 128 128
Lines 2986 2985 -1
Branches 339 338 -1
==========================================
+ Hits 1628 1666 +38
+ Misses 1108 1078 -30
+ Partials 250 241 -9
🚀 New features to boost your workflow:
|
Implements soft-delete (archive) handlers for Category and Status domains, along with complete unit, endpoint, and integration test coverage across all layers.
New Implementation
DeleteCategoryCommand/DeleteCategoryValidatorandDeleteStatusCommand/DeleteStatusValidatorinShared.ContractsDeleteCategoryHandlerandDeleteStatusHandler— follow existing soft-delete pattern: validate → get → skip if already archived →ArchiveAsyncDELETE /api/v1/categories/{id}andDELETE /api/v1/statuses/{id}endpoints — returns204 NoContentor404 NotFound, require authorizationServiceCollectionExtensionsTests
204,401,404paths for bothDELETE /categories/{id}andDELETE /statuses/{id}Archived=truein DB and excluded from paginated list