Рефакторинг обработчиков. Часть 3 #21

This commit is contained in:
2026-05-13 23:02:59 +03:00
parent 61bb44ab4a
commit 40806df62a
91 changed files with 6138 additions and 7150 deletions

View File

@@ -0,0 +1,137 @@
%%%-------------------------------------------------------------------
%%% @doc Тесты клиентского API для работы с тикетами.
%%%
%%% Покрывает эндпоинты:
%%% POST /v1/tickets
%%% GET /v1/tickets
%%% GET /v1/tickets/:id
%%%
%%% Проверяет:
%%% - успешное создание тикета
%%% - получение списка своих тикетов
%%% - получение конкретного тикета по ID
%%% - ошибку 400 при отсутствии обязательных полей
%%% - ошибку 401 без токена
%%% - ошибку 403 при попытке доступа к чужому тикету
%%% @end
%%%-------------------------------------------------------------------
-module(user_tickets_tests).
-include_lib("eunit/include/eunit.hrl").
-export([test/0]).
%%%===================================================================
%%% Главная тестовая функция
%%%===================================================================
-spec test() -> ok.
test() ->
ct:pal("=== User Tickets Tests ==="),
Token = api_test_runner:get_user_token(),
StrangerEmail = api_test_runner:unique_email(<<"stranger">>),
StrangerToken = api_test_runner:register_and_login(StrangerEmail, <<"pass">>),
% Создаём тикет
#{<<"id">> := TicketId} = api_test_runner:client_post(<<"/v1/tickets">>, Token,
#{error_message => <<"Something broke">>, stacktrace => <<"line 42">>}),
test_create_ticket(Token),
test_create_ticket_missing_fields(Token),
test_create_ticket_unauthorized(),
test_list_tickets(Token, TicketId),
test_list_tickets_unauthorized(),
test_get_ticket(Token, TicketId),
test_get_ticket_forbidden(StrangerToken, TicketId),
test_get_ticket_not_found(Token),
test_get_ticket_unauthorized(TicketId),
ct:pal("=== All user tickets tests passed ==="),
ok.
%%%===================================================================
%%% Тестовые функции
%%%===================================================================
%% @doc Успешное создание тикета: 201 Created.
-spec test_create_ticket(binary()) -> ok.
test_create_ticket(Token) ->
ct:pal(" TEST: Create a ticket"),
Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token,
jsx:encode(#{error_message => <<"Test bug">>, stacktrace => <<"trace">>})),
{ok, 201, _, Body} = Resp,
#{<<"id">> := Id, <<"status">> := Status} = jsx:decode(list_to_binary(Body), [return_maps]),
?assert(is_binary(Id)),
?assertEqual(<<"open">>, Status),
ct:pal(" OK: ticket ~s created", [Id]).
%% @doc Отсутствие обязательного поля error_message: 400 Bad Request.
-spec test_create_ticket_missing_fields(binary()) -> ok.
test_create_ticket_missing_fields(Token) ->
ct:pal(" TEST: Create ticket without error_message"),
Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token,
jsx:encode(#{stacktrace => <<"trace">>})),
?assertMatch({ok, 400, _, _}, Resp),
ct:pal(" OK: got 400").
%% @doc Создание тикета без токена: 401 Unauthorized.
-spec test_create_ticket_unauthorized() -> ok.
test_create_ticket_unauthorized() ->
ct:pal(" TEST: Create ticket without token"),
Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, <<>>,
jsx:encode(#{error_message => <<"bug">>})),
?assertMatch({ok, 401, _, _}, Resp),
ct:pal(" OK: got 401").
%% @doc GET /v1/tickets получение списка своих тикетов.
-spec test_list_tickets(binary(), binary()) -> ok.
test_list_tickets(Token, ExpectedTicketId) ->
ct:pal(" TEST: List my tickets"),
Tickets = api_test_runner:client_get(<<"/v1/tickets">>, Token),
?assert(is_list(Tickets)),
?assert(length(Tickets) >= 1),
?assert(lists:any(fun(T) -> maps:get(<<"id">>, T) =:= ExpectedTicketId end, Tickets)),
ct:pal(" OK: my ticket found").
%% @doc GET /v1/tickets без токена: 401 Unauthorized.
-spec test_list_tickets_unauthorized() -> ok.
test_list_tickets_unauthorized() ->
ct:pal(" TEST: List tickets without token"),
Resp = api_test_runner:client_request(get, <<"/v1/tickets">>, <<>>),
?assertMatch({ok, 401, _, _}, Resp),
ct:pal(" OK: got 401").
%% @doc GET /v1/tickets/:id получение своего тикета.
-spec test_get_ticket(binary(), binary()) -> ok.
test_get_ticket(Token, TicketId) ->
ct:pal(" TEST: Get my ticket by ID"),
Path = <<"/v1/tickets/", TicketId/binary>>,
Ticket = api_test_runner:client_get(Path, Token),
?assertEqual(TicketId, maps:get(<<"id">>, Ticket)),
?assertEqual(<<"Something broke">>, maps:get(<<"error_message">>, Ticket)),
ct:pal(" OK: got my ticket").
%% @doc GET /v1/tickets/:id попытка доступа к чужому тикету (403).
-spec test_get_ticket_forbidden(binary(), binary()) -> ok.
test_get_ticket_forbidden(StrangerToken, TicketId) ->
ct:pal(" TEST: Get ticket that is not mine"),
Path = <<"/v1/tickets/", TicketId/binary>>,
Resp = api_test_runner:client_request(get, Path, StrangerToken),
?assertMatch({ok, 403, _, _}, Resp),
ct:pal(" OK: got 403").
%% @doc GET /v1/tickets/:id несуществующий тикет (404).
-spec test_get_ticket_not_found(binary()) -> ok.
test_get_ticket_not_found(Token) ->
ct:pal(" TEST: Get non-existent ticket"),
Resp = api_test_runner:client_request(get, <<"/v1/tickets/fakeid">>, Token),
?assertMatch({ok, 404, _, _}, Resp),
ct:pal(" OK: got 404").
%% @doc GET /v1/tickets/:id без токена (401).
-spec test_get_ticket_unauthorized(binary()) -> ok.
test_get_ticket_unauthorized(TicketId) ->
ct:pal(" TEST: Get ticket without token"),
Path = <<"/v1/tickets/", TicketId/binary>>,
Resp = api_test_runner:client_request(get, Path, <<>>),
?assertMatch({ok, 401, _, _}, Resp),
ct:pal(" OK: got 401").