Skip to content

Commit ef70f0b

Browse files
committed
test(api,web): добавлены новые тесты для повышения покрытия
1 parent 4601639 commit ef70f0b

File tree

5 files changed

+975
-0
lines changed

5 files changed

+975
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Net;
2+
using FluentAssertions;
3+
using Xunit;
4+
5+
namespace HQStudio.API.Tests;
6+
7+
/// <summary>
8+
/// Тесты для health check и базовой доступности API
9+
/// </summary>
10+
public class HealthCheckTests : IntegrationTestBase
11+
{
12+
[Fact]
13+
public async Task HealthCheck_ReturnsHealthy()
14+
{
15+
// Act
16+
var response = await Client.GetAsync("/api/health");
17+
18+
// Assert
19+
response.StatusCode.Should().Be(HttpStatusCode.OK);
20+
var content = await response.Content.ReadAsStringAsync();
21+
content.Should().Contain("Healthy");
22+
}
23+
24+
[Fact]
25+
public async Task Swagger_IsAccessible()
26+
{
27+
// Act
28+
var response = await Client.GetAsync("/swagger/index.html");
29+
30+
// Assert
31+
response.StatusCode.Should().Be(HttpStatusCode.OK);
32+
}
33+
34+
[Fact]
35+
public async Task SwaggerJson_IsAccessible()
36+
{
37+
// Act
38+
var response = await Client.GetAsync("/swagger/v1/swagger.json");
39+
40+
// Assert
41+
response.StatusCode.Should().Be(HttpStatusCode.OK);
42+
var content = await response.Content.ReadAsStringAsync();
43+
content.Should().Contain("openapi");
44+
}
45+
46+
[Fact]
47+
public async Task NonExistentEndpoint_ReturnsNotFound()
48+
{
49+
// Act
50+
var response = await Client.GetAsync("/api/nonexistent");
51+
52+
// Assert
53+
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
54+
}
55+
56+
[Fact]
57+
public async Task PublicEndpoints_AreAccessibleWithoutAuth()
58+
{
59+
// Services - публичный endpoint
60+
var servicesResponse = await Client.GetAsync("/api/services");
61+
servicesResponse.StatusCode.Should().Be(HttpStatusCode.OK);
62+
}
63+
64+
[Fact]
65+
public async Task ProtectedEndpoints_RequireAuth()
66+
{
67+
// Clients - защищённый endpoint
68+
var clientsResponse = await Client.GetAsync("/api/clients");
69+
clientsResponse.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
70+
71+
// Orders - защищённый endpoint
72+
var ordersResponse = await Client.GetAsync("/api/orders");
73+
ordersResponse.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
74+
75+
// Users - защищённый endpoint
76+
var usersResponse = await Client.GetAsync("/api/users");
77+
usersResponse.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
78+
79+
// Dashboard - защищённый endpoint
80+
var dashboardResponse = await Client.GetAsync("/api/dashboard");
81+
dashboardResponse.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
82+
}
83+
84+
[Fact]
85+
public async Task CorsHeaders_ArePresent()
86+
{
87+
// Act
88+
var request = new HttpRequestMessage(HttpMethod.Options, "/api/services");
89+
request.Headers.Add("Origin", "http://localhost:3000");
90+
request.Headers.Add("Access-Control-Request-Method", "GET");
91+
92+
var response = await Client.SendAsync(request);
93+
94+
// Assert - CORS должен быть настроен
95+
// В тестовом окружении может быть отключен, поэтому проверяем что запрос не падает
96+
response.StatusCode.Should().NotBe(HttpStatusCode.InternalServerError);
97+
}
98+
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
using System.Net;
2+
using System.Net.Http.Json;
3+
using FluentAssertions;
4+
using HQStudio.API.Models;
5+
using Xunit;
6+
7+
namespace HQStudio.API.Tests;
8+
9+
/// <summary>
10+
/// Тесты полного workflow заказа: создание → обработка → завершение
11+
/// </summary>
12+
public class OrderWorkflowTests : IntegrationTestBase
13+
{
14+
[Fact]
15+
public async Task OrderWorkflow_CreateToComplete_WorksCorrectly()
16+
{
17+
// Arrange
18+
await AuthenticateAsync();
19+
20+
// 1. Создаём клиента
21+
var clientResponse = await Client.PostAsJsonAsync("/api/clients", new
22+
{
23+
name = "Workflow Test Client",
24+
phone = "+7-999-111-00-00",
25+
carModel = "BMW X5",
26+
licensePlate = "А111АА777"
27+
});
28+
clientResponse.StatusCode.Should().Be(HttpStatusCode.Created);
29+
var client = await clientResponse.Content.ReadFromJsonAsync<WorkflowClientDto>();
30+
31+
// 2. Получаем услуги
32+
var servicesResponse = await Client.GetAsync("/api/services");
33+
var services = await servicesResponse.Content.ReadFromJsonAsync<List<WorkflowServiceDto>>();
34+
var serviceIds = services!.Take(2).Select(s => s.Id).ToList();
35+
36+
// 3. Создаём заказ
37+
var orderResponse = await Client.PostAsJsonAsync("/api/orders", new
38+
{
39+
clientId = client!.Id,
40+
serviceIds = serviceIds,
41+
totalPrice = 25000m,
42+
notes = "Тестовый заказ для workflow"
43+
});
44+
orderResponse.StatusCode.Should().Be(HttpStatusCode.Created);
45+
var orderId = orderResponse.Headers.Location?.ToString()?.Split('/').Last();
46+
47+
// 4. Проверяем статус - должен быть New (0)
48+
var getOrderResponse = await Client.GetAsync($"/api/orders/{orderId}");
49+
var order = await getOrderResponse.Content.ReadFromJsonAsync<WorkflowOrderDto>();
50+
order!.Status.Should().Be(0); // New
51+
52+
// 5. Переводим в работу (InProgress = 1)
53+
var inProgressResponse = await Client.PutAsJsonAsync($"/api/orders/{orderId}/status", 1);
54+
inProgressResponse.StatusCode.Should().Be(HttpStatusCode.NoContent);
55+
56+
// 6. Проверяем статус
57+
var checkResponse1 = await Client.GetAsync($"/api/orders/{orderId}");
58+
var orderInProgress = await checkResponse1.Content.ReadFromJsonAsync<WorkflowOrderDto>();
59+
orderInProgress!.Status.Should().Be(1); // InProgress
60+
61+
// 7. Завершаем заказ (Completed = 2)
62+
var completeResponse = await Client.PutAsJsonAsync($"/api/orders/{orderId}/status", 2);
63+
completeResponse.StatusCode.Should().Be(HttpStatusCode.NoContent);
64+
65+
// 8. Проверяем финальный статус
66+
var finalResponse = await Client.GetAsync($"/api/orders/{orderId}");
67+
var completedOrder = await finalResponse.Content.ReadFromJsonAsync<WorkflowOrderDto>();
68+
completedOrder!.Status.Should().Be(2); // Completed
69+
}
70+
71+
[Fact]
72+
public async Task OrderWorkflow_CancelOrder_WorksCorrectly()
73+
{
74+
// Arrange
75+
await AuthenticateAsync();
76+
77+
// Создаём клиента
78+
var clientResponse = await Client.PostAsJsonAsync("/api/clients", new
79+
{
80+
name = "Cancel Test Client",
81+
phone = "+7-999-222-00-00"
82+
});
83+
var client = await clientResponse.Content.ReadFromJsonAsync<WorkflowClientDto>();
84+
85+
// Создаём заказ
86+
var orderResponse = await Client.PostAsJsonAsync("/api/orders", new
87+
{
88+
clientId = client!.Id,
89+
serviceIds = new List<int>(),
90+
totalPrice = 10000m
91+
});
92+
var orderId = orderResponse.Headers.Location?.ToString()?.Split('/').Last();
93+
94+
// Act - отменяем заказ (Cancelled = 3)
95+
var cancelResponse = await Client.PutAsJsonAsync($"/api/orders/{orderId}/status", 3);
96+
97+
// Assert
98+
cancelResponse.StatusCode.Should().Be(HttpStatusCode.NoContent);
99+
100+
var checkResponse = await Client.GetAsync($"/api/orders/{orderId}");
101+
var cancelledOrder = await checkResponse.Content.ReadFromJsonAsync<WorkflowOrderDto>();
102+
cancelledOrder!.Status.Should().Be(3); // Cancelled
103+
}
104+
105+
[Fact]
106+
public async Task OrderWorkflow_UpdateOrderDetails_WorksCorrectly()
107+
{
108+
// Arrange
109+
await AuthenticateAsync();
110+
111+
var clientResponse = await Client.PostAsJsonAsync("/api/clients", new
112+
{
113+
name = "Update Order Client",
114+
phone = "+7-999-333-00-00"
115+
});
116+
var client = await clientResponse.Content.ReadFromJsonAsync<WorkflowClientDto>();
117+
118+
var orderResponse = await Client.PostAsJsonAsync("/api/orders", new
119+
{
120+
clientId = client!.Id,
121+
serviceIds = new List<int>(),
122+
totalPrice = 5000m,
123+
notes = "Original notes"
124+
});
125+
var orderId = orderResponse.Headers.Location?.ToString()?.Split('/').Last();
126+
127+
// Act - обновляем заказ
128+
var updateResponse = await Client.PutAsJsonAsync($"/api/orders/{orderId}", new
129+
{
130+
id = int.Parse(orderId!),
131+
clientId = client.Id,
132+
serviceIds = new List<int>(),
133+
totalPrice = 7500m,
134+
notes = "Updated notes",
135+
status = 0
136+
});
137+
138+
// Assert
139+
updateResponse.StatusCode.Should().Be(HttpStatusCode.NoContent);
140+
141+
var checkResponse = await Client.GetAsync($"/api/orders/{orderId}");
142+
var updatedOrder = await checkResponse.Content.ReadFromJsonAsync<WorkflowOrderDto>();
143+
updatedOrder!.TotalPrice.Should().Be(7500m);
144+
}
145+
146+
[Fact]
147+
public async Task OrderWorkflow_FilterByStatus_ReturnsCorrectOrders()
148+
{
149+
// Arrange
150+
await AuthenticateAsync();
151+
152+
// Act - получаем заказы со статусом New
153+
var response = await Client.GetAsync("/api/orders?status=0");
154+
155+
// Assert
156+
response.StatusCode.Should().Be(HttpStatusCode.OK);
157+
var orders = await response.Content.ReadFromJsonAsync<List<WorkflowOrderDto>>();
158+
orders.Should().NotBeNull();
159+
orders!.Should().OnlyContain(o => o.Status == 0);
160+
}
161+
162+
[Fact]
163+
public async Task OrderWorkflow_FilterByClient_ReturnsCorrectOrders()
164+
{
165+
// Arrange
166+
await AuthenticateAsync();
167+
168+
var clientResponse = await Client.PostAsJsonAsync("/api/clients", new
169+
{
170+
name = "Filter Test Client",
171+
phone = "+7-999-444-00-00"
172+
});
173+
var client = await clientResponse.Content.ReadFromJsonAsync<WorkflowClientDto>();
174+
175+
// Создаём заказ для этого клиента
176+
await Client.PostAsJsonAsync("/api/orders", new
177+
{
178+
clientId = client!.Id,
179+
serviceIds = new List<int>(),
180+
totalPrice = 1000m
181+
});
182+
183+
// Act
184+
var response = await Client.GetAsync($"/api/orders?clientId={client.Id}");
185+
186+
// Assert
187+
response.StatusCode.Should().Be(HttpStatusCode.OK);
188+
var orders = await response.Content.ReadFromJsonAsync<List<WorkflowOrderDto>>();
189+
orders.Should().NotBeNull();
190+
orders!.Should().OnlyContain(o => o.ClientId == client.Id);
191+
}
192+
193+
private class WorkflowClientDto
194+
{
195+
public int Id { get; set; }
196+
public string Name { get; set; } = "";
197+
}
198+
199+
private class WorkflowServiceDto
200+
{
201+
public int Id { get; set; }
202+
public string Title { get; set; } = "";
203+
}
204+
205+
private class WorkflowOrderDto
206+
{
207+
public int Id { get; set; }
208+
public int ClientId { get; set; }
209+
public int Status { get; set; }
210+
public decimal TotalPrice { get; set; }
211+
public string? Notes { get; set; }
212+
}
213+
}

0 commit comments

Comments
 (0)