Add Registrations and Payments controller tests
- Create RegistrationsControllerTests with 17 test cases - Registration creation, retrieval, cancellation - Authorization checks (participant vs organizer) - Duplicate registration prevention - Event capacity validation - Create PaymentsControllerTests with 13 test cases - Payment recording (cash and online) - Payment status tracking - Payment reports for organizers - Authorization validation All backend tests passing: 55 passed, 2 skipped
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user