Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6dfd2fd302 | |||
| c8f2f13f6c | |||
| eb4e527cbd | |||
| 877c7877ee | |||
| 2f76fd7858 | |||
| 0dc30f29c5 | |||
| f4e2c28869 | |||
| d4c078a5c8 | |||
| 7cf6211d4d |
@@ -72,6 +72,7 @@ public class AnnouncementsController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult<AnnouncementDto>> GetAnnouncement(Guid id)
|
||||
{
|
||||
var announcement = await _context.Announcements
|
||||
@@ -98,6 +99,7 @@ public class AnnouncementsController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("event/{eventId}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult<IEnumerable<AnnouncementDto>>> GetEventAnnouncements(Guid eventId)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
|
||||
@@ -0,0 +1,528 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
using FluentAssertions;
|
||||
using RacePlannerApi.Controllers;
|
||||
using RacePlannerApi.Data;
|
||||
using RacePlannerApi.DTOs;
|
||||
using RacePlannerApi.Models;
|
||||
using backend.Tests.Utilities;
|
||||
|
||||
namespace backend.Tests.Controllers;
|
||||
|
||||
public class AnnouncementsControllerTests : IDisposable
|
||||
{
|
||||
private readonly RacePlannerDbContext _context;
|
||||
private readonly AnnouncementsController _controller;
|
||||
|
||||
public AnnouncementsControllerTests()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RacePlannerDbContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
|
||||
_context = new RacePlannerDbContext(options);
|
||||
_controller = new AnnouncementsController(_context);
|
||||
}
|
||||
|
||||
private void SetUserContext(Guid userId, string role = "Participant")
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
||||
new Claim(ClaimTypes.Role, role)
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuthType");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = principal }
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
#region Create Announcement - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAnnouncement_WithValidData_CreatesAnnouncement()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreateAnnouncementRequest
|
||||
{
|
||||
EventId = eventEntity.Id,
|
||||
Title = "Important Update",
|
||||
Content = "Event details have been updated."
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateAnnouncement(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
|
||||
response.Title.Should().Be(request.Title);
|
||||
response.Content.Should().Be(request.Content);
|
||||
response.IsPublished.Should().BeTrue();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create Announcement - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAnnouncement_ForNonExistentEvent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreateAnnouncementRequest
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Title = "Test",
|
||||
Content = "Content"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateAnnouncement(request);
|
||||
|
||||
// Assert
|
||||
var notFoundResult = result.Result.Should().BeOfType<NotFoundObjectResult>().Subject;
|
||||
notFoundResult.Value.Should().BeEquivalentTo(new { error = "Event not found" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAnnouncement_NonOrganizer_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var otherOrganizer = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
|
||||
_context.Users.AddRange(organizer, otherOrganizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(otherOrganizer.Id, "Organizer");
|
||||
|
||||
var request = new CreateAnnouncementRequest
|
||||
{
|
||||
EventId = eventEntity.Id,
|
||||
Title = "Test",
|
||||
Content = "Content"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateAnnouncement(request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<ForbidResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Announcement - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetAnnouncement_ReturnsPublishedAnnouncement()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Title", "Content", organizer.Id);
|
||||
announcement.IsPublished = true;
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetAnnouncement(announcement.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
|
||||
response.Title.Should().Be("Title");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAnnouncement_OrganizerCanViewUnpublishedAnnouncement()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft Title", "Content", organizer.Id);
|
||||
announcement.IsPublished = false;
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetAnnouncement(announcement.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<OkObjectResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Announcement - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetAnnouncement_UnpublishedNotVisibleToPublic()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content", organizer.Id);
|
||||
announcement.IsPublished = false;
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetAnnouncement(announcement.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Event Announcements
|
||||
|
||||
[Fact]
|
||||
public async Task GetEventAnnouncements_ReturnsPublishedAnnouncements()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var published = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Published", "Content", organizer.Id);
|
||||
published.IsPublished = true;
|
||||
var unpublished = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content", organizer.Id);
|
||||
unpublished.IsPublished = false;
|
||||
_context.Announcements.AddRange(published, unpublished);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEventAnnouncements(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
|
||||
announcements.Should().HaveCount(1);
|
||||
announcements.First().Title.Should().Be("Published");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEventAnnouncements_OrganizerSeesAll()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var published = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Published", "Content", organizer.Id);
|
||||
published.IsPublished = true;
|
||||
var unpublished = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content", organizer.Id);
|
||||
unpublished.IsPublished = false;
|
||||
_context.Announcements.AddRange(published, unpublished);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEventAnnouncements(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
|
||||
announcements.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Announcement - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAnnouncement_WithValidData_UpdatesAnnouncement()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Original", "Content", organizer.Id);
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new UpdateAnnouncementRequest
|
||||
{
|
||||
Title = "Updated Title",
|
||||
Content = "Updated Content"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateAnnouncement(announcement.Id, request);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
|
||||
response.Title.Should().Be("Updated Title");
|
||||
response.Content.Should().Be("Updated Content");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAnnouncement_PublishUnpublishedAnnouncement()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Draft", "Content", organizer.Id);
|
||||
announcement.IsPublished = false;
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new UpdateAnnouncementRequest { IsPublished = true };
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateAnnouncement(announcement.Id, request);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<AnnouncementDto>().Subject;
|
||||
response.IsPublished.Should().BeTrue();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Announcement - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAnnouncement_NonExistent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new UpdateAnnouncementRequest { Title = "Updated" };
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateAnnouncement(Guid.NewGuid(), request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAnnouncement_NonOrganizer_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var otherOrganizer = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
|
||||
_context.Users.AddRange(organizer, otherOrganizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Title", "Content", organizer.Id);
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(otherOrganizer.Id, "Organizer");
|
||||
|
||||
var request = new UpdateAnnouncementRequest { Title = "Hacked" };
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateAnnouncement(announcement.Id, request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<ForbidResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete Announcement - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAnnouncement_OrganizerCanDeleteOwnAnnouncement()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var announcement = TestDataFactory.CreateAnnouncement(eventEntity.Id, "To Delete", "Content", organizer.Id);
|
||||
_context.Announcements.Add(announcement);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.DeleteAnnouncement(announcement.Id);
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<NoContentResult>();
|
||||
|
||||
var deleted = await _context.Announcements.FindAsync(announcement.Id);
|
||||
deleted.Should().BeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete Announcement - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAnnouncement_NonExistent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.DeleteAnnouncement(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get My Announcements
|
||||
|
||||
[Fact]
|
||||
public async Task GetMyAnnouncements_ReturnsAnnouncementsForRegisteredEvents()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var event1 = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
var event2 = TestDataFactory.CreateEvent(name: "Event 2", organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.AddRange(event1, event2);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(event1.Id, participant.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(registration);
|
||||
|
||||
var announcement1 = TestDataFactory.CreateAnnouncement(event1.Id, "Announcement 1", "Content", organizer.Id);
|
||||
announcement1.IsPublished = true;
|
||||
var announcement2 = TestDataFactory.CreateAnnouncement(event2.Id, "Announcement 2", "Content", organizer.Id);
|
||||
announcement2.IsPublished = true;
|
||||
_context.Announcements.AddRange(announcement1, announcement2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetMyAnnouncements();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
|
||||
announcements.Should().HaveCount(1);
|
||||
announcements.First().Title.Should().Be("Announcement 1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetMyAnnouncements_ExcludesUnpublished()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant2@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(registration);
|
||||
|
||||
var published = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Published", "Content", organizer.Id);
|
||||
published.IsPublished = true;
|
||||
var unpublished = TestDataFactory.CreateAnnouncement(eventEntity.Id, "Unpublished", "Content", organizer.Id);
|
||||
unpublished.IsPublished = false;
|
||||
_context.Announcements.AddRange(published, unpublished);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetMyAnnouncements();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var announcements = okResult.Value.Should().BeAssignableTo<IEnumerable<AnnouncementDto>>().Subject;
|
||||
announcements.Should().HaveCount(1);
|
||||
announcements.First().Title.Should().Be("Published");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
using FluentAssertions;
|
||||
using RacePlannerApi.Controllers;
|
||||
using RacePlannerApi.Data;
|
||||
using RacePlannerApi.DTOs;
|
||||
using RacePlannerApi.Models;
|
||||
using backend.Tests.Utilities;
|
||||
|
||||
namespace backend.Tests.Controllers;
|
||||
|
||||
public class DashboardControllerTests : IDisposable
|
||||
{
|
||||
private readonly RacePlannerDbContext _context;
|
||||
private readonly DashboardController _controller;
|
||||
|
||||
public DashboardControllerTests()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RacePlannerDbContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
|
||||
_context = new RacePlannerDbContext(options);
|
||||
_controller = new DashboardController(_context);
|
||||
}
|
||||
|
||||
private void SetUserContext(Guid userId, string role = "Participant")
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
||||
new Claim(ClaimTypes.Role, role)
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuthType");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = principal }
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
#region Organizer Dashboard - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrganizerDashboard_ReturnsDashboardData()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
// Create events
|
||||
var pastEvent = TestDataFactory.CreateEvent(
|
||||
name: "Past Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(-10),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Completed);
|
||||
var draftEvent = TestDataFactory.CreateEvent(
|
||||
name: "Draft Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(30),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Draft);
|
||||
var publishedEvent = TestDataFactory.CreateEvent(
|
||||
name: "Published Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(15),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Published);
|
||||
publishedEvent.MaxParticipants = 100;
|
||||
|
||||
_context.Events.AddRange(pastEvent, draftEvent, publishedEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Add registrations with payments
|
||||
var participant1 = TestDataFactory.CreateUser(email: "p1@example.com", role: UserRole.Participant);
|
||||
var participant2 = TestDataFactory.CreateUser(email: "p2@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(participant1, participant2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var reg1 = TestDataFactory.CreateRegistration(publishedEvent.Id, participant1.Id, RegistrationStatus.Confirmed);
|
||||
var reg2 = TestDataFactory.CreateRegistration(publishedEvent.Id, participant2.Id, RegistrationStatus.Pending);
|
||||
_context.Registrations.AddRange(reg1, reg2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var payment = TestDataFactory.CreatePayment(reg1.Id, 50.00m, PaymentMethod.Cash);
|
||||
_context.Payments.Add(payment);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetOrganizerDashboard();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var dashboard = okResult.Value.Should().BeOfType<OrganizerDashboardDto>().Subject;
|
||||
dashboard.TotalEvents.Should().Be(3);
|
||||
dashboard.PublishedEvents.Should().Be(1);
|
||||
dashboard.DraftEvents.Should().Be(1);
|
||||
dashboard.TotalRegistrations.Should().Be(2);
|
||||
dashboard.ConfirmedRegistrations.Should().Be(1);
|
||||
dashboard.PendingRegistrations.Should().Be(1);
|
||||
dashboard.TotalRevenue.Should().Be(50.00m);
|
||||
dashboard.UpcomingEvents.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrganizerDashboard_EmptyOrganizer_ReturnsEmptyDashboard()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetOrganizerDashboard();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var dashboard = okResult.Value.Should().BeOfType<OrganizerDashboardDto>().Subject;
|
||||
dashboard.TotalEvents.Should().Be(0);
|
||||
dashboard.TotalRegistrations.Should().Be(0);
|
||||
dashboard.TotalRevenue.Should().Be(0);
|
||||
dashboard.UpcomingEvents.Should().BeEmpty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Participant Dashboard - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetParticipantDashboard_ReturnsDashboardData()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var upcomingEvent = TestDataFactory.CreateEvent(
|
||||
name: "Upcoming Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(15),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Published);
|
||||
var pastEvent = TestDataFactory.CreateEvent(
|
||||
name: "Past Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(-10),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Completed);
|
||||
|
||||
var cancelledEvent = TestDataFactory.CreateEvent(name: "Cancelled Event", organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.AddRange(upcomingEvent, pastEvent, cancelledEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var upcomingReg = TestDataFactory.CreateRegistration(upcomingEvent.Id, participant.Id, RegistrationStatus.Confirmed);
|
||||
var pastReg = TestDataFactory.CreateRegistration(pastEvent.Id, participant.Id, RegistrationStatus.Completed);
|
||||
var cancelledReg = TestDataFactory.CreateRegistration(cancelledEvent.Id, participant.Id, RegistrationStatus.Cancelled);
|
||||
_context.Registrations.AddRange(upcomingReg, pastReg, cancelledReg);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetParticipantDashboard();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var dashboard = okResult.Value.Should().BeOfType<ParticipantDashboardDto>().Subject;
|
||||
dashboard.TotalRegistrations.Should().Be(3);
|
||||
dashboard.UpcomingEvents.Should().Be(1);
|
||||
dashboard.CompletedEvents.Should().Be(1);
|
||||
dashboard.CancelledRegistrations.Should().Be(1);
|
||||
dashboard.MyRegistrations.Should().HaveCount(3);
|
||||
dashboard.UpcomingEventList.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetParticipantDashboard_NoRegistrations_ReturnsEmptyDashboard()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetParticipantDashboard();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var dashboard = okResult.Value.Should().BeOfType<ParticipantDashboardDto>().Subject;
|
||||
dashboard.TotalRegistrations.Should().Be(0);
|
||||
dashboard.UpcomingEvents.Should().Be(0);
|
||||
dashboard.MyRegistrations.Should().BeEmpty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dashboard - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrganizerDashboard_Unauthenticated_ReturnsUnauthorized()
|
||||
{
|
||||
// Arrange
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetOrganizerDashboard();
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<UnauthorizedResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetParticipantDashboard_Unauthenticated_ReturnsUnauthorized()
|
||||
{
|
||||
// Arrange
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetParticipantDashboard();
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<UnauthorizedResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Capacity Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrganizerDashboard_ShowsEventsNearCapacity()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
// Event at 90% capacity (should appear in near capacity list)
|
||||
var nearCapacityEvent = TestDataFactory.CreateEvent(
|
||||
name: "Near Capacity",
|
||||
eventDate: DateTime.UtcNow.AddDays(10),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Published);
|
||||
nearCapacityEvent.MaxParticipants = 10;
|
||||
|
||||
// Event at 50% capacity (should NOT appear)
|
||||
var normalEvent = TestDataFactory.CreateEvent(
|
||||
name: "Normal",
|
||||
eventDate: DateTime.UtcNow.AddDays(10),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Published);
|
||||
normalEvent.MaxParticipants = 100;
|
||||
|
||||
_context.Events.AddRange(nearCapacityEvent, normalEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Add registrations
|
||||
var participant1 = TestDataFactory.CreateUser(email: "p1@test.com", role: UserRole.Participant);
|
||||
var participant2 = TestDataFactory.CreateUser(email: "p2@test.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(participant1, participant2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Fill near capacity event to 90%
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
var p = TestDataFactory.CreateUser(email: $"test{i}@test.com", role: UserRole.Participant);
|
||||
_context.Users.Add(p);
|
||||
var reg = TestDataFactory.CreateRegistration(nearCapacityEvent.Id, p.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(reg);
|
||||
}
|
||||
|
||||
// Fill normal event to 50%
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
var p = TestDataFactory.CreateUser(email: $"normal{i}@test.com", role: UserRole.Participant);
|
||||
_context.Users.Add(p);
|
||||
var reg = TestDataFactory.CreateRegistration(normalEvent.Id, p.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(reg);
|
||||
}
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetOrganizerDashboard();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var dashboard = okResult.Value.Should().BeOfType<OrganizerDashboardDto>().Subject;
|
||||
dashboard.EventsNearCapacity.Should().HaveCount(1);
|
||||
dashboard.EventsNearCapacity.First().Name.Should().Be("Near Capacity");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
using FluentAssertions;
|
||||
using RacePlannerApi.Controllers;
|
||||
using RacePlannerApi.Data;
|
||||
using RacePlannerApi.DTOs;
|
||||
using RacePlannerApi.Models;
|
||||
using backend.Tests.Utilities;
|
||||
|
||||
namespace backend.Tests.Controllers;
|
||||
|
||||
public class EventsControllerTests : IDisposable
|
||||
{
|
||||
private readonly RacePlannerDbContext _context;
|
||||
private readonly EventsController _controller;
|
||||
|
||||
public EventsControllerTests()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RacePlannerDbContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
|
||||
_context = new RacePlannerDbContext(options);
|
||||
_controller = new EventsController(_context);
|
||||
}
|
||||
|
||||
private void SetUserContext(Guid userId, string role = "Participant")
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
||||
new Claim(ClaimTypes.Role, role)
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuthType");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = principal }
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
#region Create Event - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CreateEvent_WithValidData_CreatesEvent()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreateEventRequest
|
||||
{
|
||||
Name = "Test Marathon",
|
||||
Description = "A test marathon event",
|
||||
EventDate = DateTime.UtcNow.AddDays(30),
|
||||
Location = "Test City",
|
||||
Category = "Running",
|
||||
Tags = new List<string> { "marathon", "running" },
|
||||
MaxParticipants = 100
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateEvent(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<EventDto>().Subject;
|
||||
response.Name.Should().Be(request.Name);
|
||||
response.Status.Should().Be("Draft");
|
||||
response.Organizer.Id.Should().Be(organizer.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateEvent_SetsStatusToDraft()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreateEventRequest
|
||||
{
|
||||
Name = "Test Event",
|
||||
EventDate = DateTime.UtcNow.AddDays(10),
|
||||
Location = "Test Location",
|
||||
MaxParticipants = 50
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateEvent(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<EventDto>().Subject;
|
||||
response.Status.Should().Be("Draft");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create Event - Negative Tests
|
||||
|
||||
[Fact(Skip = "Authorization attributes require integration tests with full ASP.NET Core pipeline")]
|
||||
public async Task CreateEvent_WithoutOrganizerRole_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new CreateEventRequest
|
||||
{
|
||||
Name = "Test Event",
|
||||
EventDate = DateTime.UtcNow.AddDays(10),
|
||||
Location = "Test Location"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateEvent(request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<ForbidResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateEvent_WithUnauthenticatedUser_ReturnsUnauthorized()
|
||||
{
|
||||
// Arrange
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
var request = new CreateEventRequest
|
||||
{
|
||||
Name = "Test Event",
|
||||
EventDate = DateTime.UtcNow.AddDays(10),
|
||||
Location = "Test Location"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateEvent(request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<UnauthorizedResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Events - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvents_ReturnsPublishedEventsForAnonymous()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var publishedEvent = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
var draftEvent = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Draft);
|
||||
_context.Events.AddRange(publishedEvent, draftEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvents();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var events = okResult.Value.Should().BeAssignableTo<IEnumerable<EventDto>>().Subject;
|
||||
events.Should().HaveCount(1);
|
||||
events.First().Status.Should().Be("Published");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvents_WithCategoryFilter_ReturnsFilteredEvents()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var runningEvent = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
runningEvent.Category = "Running";
|
||||
var cyclingEvent = TestDataFactory.CreateEvent(name: "Cycling Event", organizerId: organizer.Id, status: EventStatus.Published);
|
||||
cyclingEvent.Category = "Cycling";
|
||||
|
||||
_context.Events.AddRange(runningEvent, cyclingEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Set anonymous context
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
var filter = new EventFilterRequest { Category = "Running" };
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvents(filter);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var events = okResult.Value.Should().BeAssignableTo<IEnumerable<EventDto>>().Subject;
|
||||
events.Should().HaveCount(1);
|
||||
events.First().Category.Should().Be("Running");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvents_WithDateRangeFilter_ReturnsFilteredEvents()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var futureEvent = TestDataFactory.CreateEvent(
|
||||
name: "Future Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(60),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Published);
|
||||
var pastEvent = TestDataFactory.CreateEvent(
|
||||
name: "Past Event",
|
||||
eventDate: DateTime.UtcNow.AddDays(-10),
|
||||
organizerId: organizer.Id,
|
||||
status: EventStatus.Published);
|
||||
|
||||
_context.Events.AddRange(futureEvent, pastEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Set anonymous context
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
var filter = new EventFilterRequest
|
||||
{
|
||||
FromDate = DateTime.UtcNow.AddDays(1),
|
||||
ToDate = DateTime.UtcNow.AddDays(100)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvents(filter);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var events = okResult.Value.Should().BeAssignableTo<IEnumerable<EventDto>>().Subject;
|
||||
events.Should().HaveCount(1);
|
||||
events.First().Name.Should().Be("Future Event");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Single Event - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvent_ReturnsPublishedEvent()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvent(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<EventDto>().Subject;
|
||||
response.Id.Should().Be(eventEntity.Id);
|
||||
response.Name.Should().Be(eventEntity.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvent_OrganizerCanViewOwnDraftEvent()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var draftEvent = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Draft);
|
||||
_context.Events.Add(draftEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvent(draftEvent.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<OkObjectResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Single Event - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvent_DraftEventNotVisibleToPublic()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var draftEvent = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Draft);
|
||||
_context.Events.Add(draftEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvent(draftEvent.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEvent_NonExistentEvent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var nonExistentId = Guid.NewGuid();
|
||||
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetEvent(nonExistentId);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Event - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateEvent_WithValidData_UpdatesEvent()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Draft);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new UpdateEventRequest
|
||||
{
|
||||
Name = "Updated Event Name",
|
||||
Description = "Updated description",
|
||||
Status = EventStatus.Published
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateEvent(eventEntity.Id, request);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<EventDto>().Subject;
|
||||
response.Name.Should().Be("Updated Event Name");
|
||||
response.Status.Should().Be("Published");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Event - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateEvent_NonOrganizer_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var otherUser = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
|
||||
_context.Users.AddRange(organizer, otherUser);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(otherUser.Id, "Organizer");
|
||||
|
||||
var request = new UpdateEventRequest { Name = "Hacked Name" };
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateEvent(eventEntity.Id, request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<ForbidResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateEvent_NonExistentEvent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new UpdateEventRequest { Name = "Updated Name" };
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateEvent(Guid.NewGuid(), request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete Event - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteEvent_OrganizerCanDeleteOwnEvent()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.DeleteEvent(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<NoContentResult>();
|
||||
|
||||
var deletedEvent = await _context.Events.FindAsync(eventEntity.Id);
|
||||
deletedEvent.Should().BeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delete Event - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteEvent_NonOrganizer_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var otherUser = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
|
||||
_context.Users.AddRange(organizer, otherUser);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(otherUser.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.DeleteEvent(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<ForbidResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteEvent_NonExistentEvent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.DeleteEvent(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
using FluentAssertions;
|
||||
using RacePlannerApi.Controllers;
|
||||
using RacePlannerApi.Data;
|
||||
using RacePlannerApi.DTOs;
|
||||
using RacePlannerApi.Models;
|
||||
using backend.Tests.Utilities;
|
||||
|
||||
namespace backend.Tests.Controllers;
|
||||
|
||||
public class PaymentsControllerTests : IDisposable
|
||||
{
|
||||
private readonly RacePlannerDbContext _context;
|
||||
private readonly PaymentsController _controller;
|
||||
|
||||
public PaymentsControllerTests()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RacePlannerDbContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
|
||||
_context = new RacePlannerDbContext(options);
|
||||
_controller = new PaymentsController(_context);
|
||||
}
|
||||
|
||||
private void SetUserContext(Guid userId, string role = "Participant")
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
||||
new Claim(ClaimTypes.Role, role)
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuthType");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = principal }
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
#region Record Payment - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task RecordPayment_WithValidData_RecordsPayment()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreatePaymentRequest
|
||||
{
|
||||
RegistrationId = registration.Id,
|
||||
Amount = 50.00m,
|
||||
Method = PaymentMethod.Cash,
|
||||
Notes = "Cash payment received"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.RecordPayment(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<PaymentDto>().Subject;
|
||||
response.Amount.Should().Be(50.00m);
|
||||
response.Method.Should().Be("Cash");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RecordPayment_OnlinePayment_WithTransactionId()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant2@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreatePaymentRequest
|
||||
{
|
||||
RegistrationId = registration.Id,
|
||||
Amount = 75.00m,
|
||||
Method = PaymentMethod.Online,
|
||||
TransactionId = "txn_12345",
|
||||
Notes = "Online payment"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.RecordPayment(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<PaymentDto>().Subject;
|
||||
response.Method.Should().Be("Online");
|
||||
response.TransactionId.Should().Be("txn_12345");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Record Payment - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task RecordPayment_ForCancelledRegistration_ReturnsBadRequest()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant3@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Cancelled);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreatePaymentRequest
|
||||
{
|
||||
RegistrationId = registration.Id,
|
||||
Amount = 50.00m,
|
||||
Method = PaymentMethod.Cash
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.RecordPayment(request);
|
||||
|
||||
// Assert
|
||||
var badRequestResult = result.Result.Should().BeOfType<BadRequestObjectResult>().Subject;
|
||||
badRequestResult.Value.Should().BeEquivalentTo(new { error = "Cannot record payment for cancelled registration" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RecordPayment_ForNonExistentRegistration_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
var request = new CreatePaymentRequest
|
||||
{
|
||||
RegistrationId = Guid.NewGuid(),
|
||||
Amount = 50.00m,
|
||||
Method = PaymentMethod.Cash
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.RecordPayment(request);
|
||||
|
||||
// Assert
|
||||
var notFoundResult = result.Result.Should().BeOfType<NotFoundObjectResult>().Subject;
|
||||
notFoundResult.Value.Should().BeEquivalentTo(new { error = "Registration not found" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RecordPayment_NonOrganizer_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant4@example.com", role: UserRole.Participant);
|
||||
var otherOrganizer = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
|
||||
_context.Users.AddRange(organizer, participant, otherOrganizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(otherOrganizer.Id, "Organizer");
|
||||
|
||||
var request = new CreatePaymentRequest
|
||||
{
|
||||
RegistrationId = registration.Id,
|
||||
Amount = 50.00m,
|
||||
Method = PaymentMethod.Cash
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.RecordPayment(request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<ForbidResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Payment Status - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentStatus_UnpaidRegistration_ReturnsUnpaid()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant5@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetPaymentStatus(registration.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value;
|
||||
response.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentStatus_PaidRegistration_ReturnsPaid()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant6@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Record a payment
|
||||
var payment = TestDataFactory.CreatePayment(registration.Id, 50.00m, PaymentMethod.Cash);
|
||||
_context.Payments.Add(payment);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetPaymentStatus(registration.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value;
|
||||
response.Should().NotBeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Payment Status - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentStatus_NonExistentRegistration_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetPaymentStatus(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Payment Report - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentReport_ReturnsEventPaymentSummary()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant1 = TestDataFactory.CreateUser(email: "p1@example.com", role: UserRole.Participant);
|
||||
var participant2 = TestDataFactory.CreateUser(email: "p2@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant1, participant2);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration1 = TestDataFactory.CreateRegistration(eventEntity.Id, participant1.Id, RegistrationStatus.Confirmed);
|
||||
var registration2 = TestDataFactory.CreateRegistration(eventEntity.Id, participant2.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.AddRange(registration1, registration2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Add payment for first registration
|
||||
var payment = TestDataFactory.CreatePayment(registration1.Id, 50.00m, PaymentMethod.Cash);
|
||||
_context.Payments.Add(payment);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetPaymentReport(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<PaymentReportDto>().Subject;
|
||||
response.TotalCollected.Should().Be(50.00m);
|
||||
response.TotalRegistrations.Should().Be(2);
|
||||
response.PaidRegistrations.Should().Be(1);
|
||||
response.UnpaidRegistrations.Should().Be(1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Payment Report - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentReport_NonOrganizer_ReturnsForbidden()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var otherOrganizer = TestDataFactory.CreateUser(email: "other@example.com", role: UserRole.Organizer);
|
||||
_context.Users.AddRange(organizer, otherOrganizer);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(otherOrganizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetPaymentReport(eventEntity.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentReport_NonExistentEvent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
_context.Users.Add(organizer);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetPaymentReport(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
using FluentAssertions;
|
||||
using RacePlannerApi.Controllers;
|
||||
using RacePlannerApi.Data;
|
||||
using RacePlannerApi.DTOs;
|
||||
using RacePlannerApi.Models;
|
||||
using backend.Tests.Utilities;
|
||||
|
||||
namespace backend.Tests.Controllers;
|
||||
|
||||
public class RegistrationsControllerTests : IDisposable
|
||||
{
|
||||
private readonly RacePlannerDbContext _context;
|
||||
private readonly RegistrationsController _controller;
|
||||
|
||||
public RegistrationsControllerTests()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<RacePlannerDbContext>()
|
||||
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
|
||||
_context = new RacePlannerDbContext(options);
|
||||
_controller = new RegistrationsController(_context);
|
||||
}
|
||||
|
||||
private void SetUserContext(Guid userId, string role = "Participant")
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
||||
new Claim(ClaimTypes.Role, role)
|
||||
};
|
||||
var identity = new ClaimsIdentity(claims, "TestAuthType");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
_controller.ControllerContext = new ControllerContext
|
||||
{
|
||||
HttpContext = new DefaultHttpContext { User = principal }
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
#region Create Registration - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CreateRegistration_WithValidData_CreatesRegistration()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new CreateRegistrationRequest
|
||||
{
|
||||
EventId = eventEntity.Id,
|
||||
Category = "Open",
|
||||
EmergencyContact = "Emergency Contact: 123-456-7890"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateRegistration(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<RegistrationDto>().Subject;
|
||||
response.EventId.Should().Be(eventEntity.Id);
|
||||
response.ParticipantId.Should().Be(participant.Id);
|
||||
response.Status.Should().Be("Pending");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateRegistration_SetsStatusToPending()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant2@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new CreateRegistrationRequest
|
||||
{
|
||||
EventId = eventEntity.Id,
|
||||
Category = "Open"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateRegistration(request);
|
||||
|
||||
// Assert
|
||||
var createdResult = result.Result.Should().BeOfType<CreatedAtActionResult>().Subject;
|
||||
var response = createdResult.Value.Should().BeOfType<RegistrationDto>().Subject;
|
||||
response.Status.Should().Be("Pending");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Create Registration - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CreateRegistration_ForDraftEvent_ReturnsBadRequest()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant3@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var draftEvent = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Draft);
|
||||
_context.Events.Add(draftEvent);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new CreateRegistrationRequest
|
||||
{
|
||||
EventId = draftEvent.Id,
|
||||
Category = "Open"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateRegistration(request);
|
||||
|
||||
// Assert
|
||||
var badRequestResult = result.Result.Should().BeOfType<BadRequestObjectResult>().Subject;
|
||||
badRequestResult.Value.Should().BeEquivalentTo(new { error = "Event is not open for registration" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateRegistration_DuplicateRegistration_ReturnsConflict()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant4@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
// Create existing registration
|
||||
var existingRegistration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(existingRegistration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new CreateRegistrationRequest
|
||||
{
|
||||
EventId = eventEntity.Id,
|
||||
Category = "Open"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateRegistration(request);
|
||||
|
||||
// Assert
|
||||
var conflictResult = result.Result.Should().BeOfType<ConflictObjectResult>().Subject;
|
||||
conflictResult.Value.Should().BeEquivalentTo(new { error = "Already registered for this event" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateRegistration_ForFullEvent_ReturnsBadRequest()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant1 = TestDataFactory.CreateUser(email: "participant1@example.com", role: UserRole.Participant);
|
||||
var participant2 = TestDataFactory.CreateUser(email: "participant2@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant1, participant2);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
eventEntity.MaxParticipants = 1;
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
// Fill the event
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant1.Id, RegistrationStatus.Confirmed);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant2.Id, "Participant");
|
||||
|
||||
var request = new CreateRegistrationRequest
|
||||
{
|
||||
EventId = eventEntity.Id,
|
||||
Category = "Open"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateRegistration(request);
|
||||
|
||||
// Assert
|
||||
var badRequestResult = result.Result.Should().BeOfType<BadRequestObjectResult>().Subject;
|
||||
badRequestResult.Value.Should().BeEquivalentTo(new { error = "Event is full" });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateRegistration_ForNonExistentEvent_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new CreateRegistrationRequest
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Category = "Open"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.CreateRegistration(request);
|
||||
|
||||
// Assert
|
||||
var notFoundResult = result.Result.Should().BeOfType<NotFoundObjectResult>().Subject;
|
||||
notFoundResult.Value.Should().BeEquivalentTo(new { error = "Event not found" });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Registration - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetRegistration_ParticipantCanViewOwnRegistration()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant5@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetRegistration(registration.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<OkObjectResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRegistration_OrganizerCanViewAnyRegistrationForTheirEvent()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant6@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetRegistration(registration.Id);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<OkObjectResult>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetMyRegistrations_ReturnsParticipantsRegistrations()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant7@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var event1 = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
var event2 = TestDataFactory.CreateEvent(name: "Event 2", organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.AddRange(event1, event2);
|
||||
|
||||
var registration1 = TestDataFactory.CreateRegistration(event1.Id, participant.Id);
|
||||
var registration2 = TestDataFactory.CreateRegistration(event2.Id, participant.Id);
|
||||
_context.Registrations.AddRange(registration1, registration2);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetMyRegistrations();
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var registrations = okResult.Value.Should().BeAssignableTo<IEnumerable<RegistrationDto>>().Subject;
|
||||
registrations.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Registration - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task GetRegistration_NonExistentRegistration_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.GetRegistration(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cancel Registration - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CancelRegistration_ParticipantCanCancelOwnRegistration()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant8@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Pending);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.CancelRegistration(registration.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<RegistrationDto>().Subject;
|
||||
response.Status.Should().Be("Cancelled");
|
||||
|
||||
// Verify in database
|
||||
var updatedRegistration = await _context.Registrations.FindAsync(registration.Id);
|
||||
updatedRegistration!.Status.Should().Be(RegistrationStatus.Cancelled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CancelRegistration_OrganizerCanCancelAnyRegistration()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant9@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id, RegistrationStatus.Pending);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(organizer.Id, "Organizer");
|
||||
|
||||
// Act
|
||||
var result = await _controller.CancelRegistration(registration.Id);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<RegistrationDto>().Subject;
|
||||
response.Status.Should().Be("Cancelled");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cancel Registration - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task CancelRegistration_NonExistentRegistration_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
// Act
|
||||
var result = await _controller.CancelRegistration(Guid.NewGuid());
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Registration - Positive Tests
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateRegistration_ParticipantCanUpdateOwnRegistration()
|
||||
{
|
||||
// Arrange
|
||||
var organizer = TestDataFactory.CreateUser(role: UserRole.Organizer);
|
||||
var participant = TestDataFactory.CreateUser(email: "participant10@example.com", role: UserRole.Participant);
|
||||
_context.Users.AddRange(organizer, participant);
|
||||
|
||||
var eventEntity = TestDataFactory.CreateEvent(organizerId: organizer.Id, status: EventStatus.Published);
|
||||
_context.Events.Add(eventEntity);
|
||||
|
||||
var registration = TestDataFactory.CreateRegistration(eventEntity.Id, participant.Id);
|
||||
_context.Registrations.Add(registration);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new UpdateRegistrationRequest
|
||||
{
|
||||
Category = "Updated Category",
|
||||
EmergencyContact = "Updated Emergency Contact"
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateRegistration(registration.Id, request);
|
||||
|
||||
// Assert
|
||||
var okResult = result.Result.Should().BeOfType<OkObjectResult>().Subject;
|
||||
var response = okResult.Value.Should().BeOfType<RegistrationDto>().Subject;
|
||||
response.Category.Should().Be("Updated Category");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Registration - Negative Tests
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateRegistration_NonExistentRegistration_ReturnsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var participant = TestDataFactory.CreateUser(role: UserRole.Participant);
|
||||
_context.Users.Add(participant);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
SetUserContext(participant.Id, "Participant");
|
||||
|
||||
var request = new UpdateRegistrationRequest { Category = "Updated" };
|
||||
|
||||
// Act
|
||||
var result = await _controller.UpdateRegistration(Guid.NewGuid(), request);
|
||||
|
||||
// Assert
|
||||
result.Result.Should().BeOfType<NotFoundResult>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -84,7 +84,8 @@ public static class TestDataFactory
|
||||
public static Announcement CreateAnnouncement(
|
||||
Guid eventId,
|
||||
string title = "Test Announcement",
|
||||
string content = "Test announcement content")
|
||||
string content = "Test announcement content",
|
||||
Guid? authorId = null)
|
||||
{
|
||||
return new Announcement
|
||||
{
|
||||
@@ -92,6 +93,7 @@ public static class TestDataFactory
|
||||
EventId = eventId,
|
||||
Title = title,
|
||||
Content = content,
|
||||
AuthorId = authorId ?? Guid.NewGuid(),
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user