Files
Randall/src/backend/tests/integration/Randall.Api.IntegrationTests/Reservations/ReservationTests.cs
2026-03-25 19:44:53 +01:00

187 lines
7.9 KiB
C#

using System.Net;
using System.Net.Http.Json;
using Randall.Api.IntegrationTests.Helpers;
namespace Randall.Api.IntegrationTests.Reservations;
public class ReservationTests(CustomWebApplicationFactory factory) : IClassFixture<CustomWebApplicationFactory>
{
[Fact]
public async Task Create_WithoutAuth_Returns401()
{
var client = factory.CreateClient();
var response = await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = Guid.NewGuid(), Date = DateOnly.FromDateTime(DateTime.UtcNow).AddDays(1) });
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Fact]
public async Task Create_ValidReservation_Returns201WithDetails()
{
var (client, workplaceId, date) = await SetupUserWithWorkplaceAsync(daysOffset: 1);
var response = await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaceId, Date = date });
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var created = await response.Content.ReadFromJsonAsync<CreatedReservationResponse>(AuthHelper.JsonOptions);
Assert.NotEqual(Guid.Empty, created!.Id);
Assert.Equal(workplaceId, created.WorkplaceId);
Assert.Equal(date.ToString("yyyy-MM-dd"), created.Date);
}
[Fact]
public async Task GetById_ForExistingReservation_ReturnsDetails()
{
var (client, workplaceId, date) = await SetupUserWithWorkplaceAsync(daysOffset: 2);
var createResponse = await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaceId, Date = date });
var created = await createResponse.Content.ReadFromJsonAsync<CreatedReservationResponse>(AuthHelper.JsonOptions);
var response = await client.GetAsync($"/api/reservations/{created!.Id}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var detail = await response.Content.ReadFromJsonAsync<ReservationDetailResponse>(AuthHelper.JsonOptions);
Assert.Equal(created.Id, detail!.Id);
Assert.Equal(workplaceId, detail.WorkplaceId);
Assert.Equal("Active", detail.Status);
}
[Fact]
public async Task GetById_ForNonExistentReservation_Returns404()
{
var client = factory.CreateClient();
var adminLogin = await AuthHelper.LoginAsAdminAsync(client);
AuthHelper.SetBearerToken(client, adminLogin.Token);
var response = await client.GetAsync($"/api/reservations/{Guid.NewGuid()}");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task GetMy_ReturnsOnlyOwnReservations()
{
var email = $"{Guid.NewGuid():N}@test.com";
var token = await AuthHelper.CreateApprovedUserAndLoginAsync(factory, email);
var client = factory.CreateClient();
AuthHelper.SetBearerToken(client, token);
var workplaces = await client.GetFromJsonAsync<List<WorkplaceResponse>>(
"/api/workplaces", AuthHelper.JsonOptions);
var date = DateOnly.FromDateTime(DateTime.UtcNow).AddDays(3);
await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaces![1].Id, Date = date });
var response = await client.GetAsync("/api/reservations/my");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var reservations = await response.Content.ReadFromJsonAsync<List<ReservationResponse>>(AuthHelper.JsonOptions);
Assert.NotNull(reservations);
Assert.NotEmpty(reservations);
Assert.All(reservations, r => Assert.Equal("Active", r.Status));
}
[Fact]
public async Task Create_SameWorkplaceSameDay_ReturnsBadRequest()
{
// Two different users try to reserve the same workplace on the same day
var email1 = $"{Guid.NewGuid():N}@test.com";
var email2 = $"{Guid.NewGuid():N}@test.com";
var token1 = await AuthHelper.CreateApprovedUserAndLoginAsync(factory, email1);
var token2 = await AuthHelper.CreateApprovedUserAndLoginAsync(factory, email2);
var client = factory.CreateClient();
AuthHelper.SetBearerToken(client, token1);
var workplaces = await client.GetFromJsonAsync<List<WorkplaceResponse>>(
"/api/workplaces", AuthHelper.JsonOptions);
var workplaceId = workplaces![2].Id;
var date = DateOnly.FromDateTime(DateTime.UtcNow).AddDays(4);
await client.PostAsJsonAsync("/api/reservations", new { WorkplaceId = workplaceId, Date = date });
var client2 = factory.CreateClient();
AuthHelper.SetBearerToken(client2, token2);
var response = await client2.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaceId, Date = date });
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
[Fact]
public async Task Create_SameEmployeeSameDay_ReturnsBadRequest()
{
var email = $"{Guid.NewGuid():N}@test.com";
var token = await AuthHelper.CreateApprovedUserAndLoginAsync(factory, email);
var client = factory.CreateClient();
AuthHelper.SetBearerToken(client, token);
var workplaces = await client.GetFromJsonAsync<List<WorkplaceResponse>>(
"/api/workplaces", AuthHelper.JsonOptions);
var date = DateOnly.FromDateTime(DateTime.UtcNow).AddDays(5);
// First reservation succeeds
await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaces![3].Id, Date = date });
// Same employee, different workplace, same day
var response = await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaces[4].Id, Date = date });
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
[Fact]
public async Task Cancel_OwnReservation_Returns204()
{
var (client, workplaceId, date) = await SetupUserWithWorkplaceAsync(daysOffset: 6);
var createResponse = await client.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaceId, Date = date });
var created = await createResponse.Content.ReadFromJsonAsync<CreatedReservationResponse>(AuthHelper.JsonOptions);
var response = await client.DeleteAsync($"/api/reservations/{created!.Id}");
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
}
[Fact]
public async Task Cancel_AnotherUsersReservation_ReturnsBadRequest()
{
// User 1 creates a reservation
var (client1, workplaceId, date) = await SetupUserWithWorkplaceAsync(daysOffset: 8);
var createResponse = await client1.PostAsJsonAsync("/api/reservations",
new { WorkplaceId = workplaceId, Date = date });
var created = await createResponse.Content.ReadFromJsonAsync<CreatedReservationResponse>(AuthHelper.JsonOptions);
// User 2 tries to cancel it
var email2 = $"{Guid.NewGuid():N}@test.com";
var token2 = await AuthHelper.CreateApprovedUserAndLoginAsync(factory, email2);
var client2 = factory.CreateClient();
AuthHelper.SetBearerToken(client2, token2);
var response = await client2.DeleteAsync($"/api/reservations/{created!.Id}");
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
// Helper: creates a fresh approved user and returns their authenticated client,
// the first available workplace ID, and a future date unique to the test.
private async Task<(HttpClient client, Guid workplaceId, DateOnly date)> SetupUserWithWorkplaceAsync(int daysOffset)
{
var email = $"{Guid.NewGuid():N}@test.com";
var token = await AuthHelper.CreateApprovedUserAndLoginAsync(factory, email);
var client = factory.CreateClient();
AuthHelper.SetBearerToken(client, token);
var workplaces = await client.GetFromJsonAsync<List<WorkplaceResponse>>(
"/api/workplaces", AuthHelper.JsonOptions);
return (client, workplaces![0].Id, DateOnly.FromDateTime(DateTime.UtcNow).AddDays(daysOffset));
}
}