Рефакторинг обработчиков. Часть 3 #21
This commit is contained in:
115
test/api/users/user_bookings_tests.erl
Normal file
115
test/api/users/user_bookings_tests.erl
Normal file
@@ -0,0 +1,115 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @doc Тесты клиентского API для бронирований.
|
||||
%%%
|
||||
%%% Покрывает эндпоинты:
|
||||
%%% POST /v1/events/:id/bookings
|
||||
%%% PUT /v1/bookings/:id
|
||||
%%% DELETE /v1/bookings/:id
|
||||
%%%
|
||||
%%% Проверяет:
|
||||
%%% - создание бронирования участником
|
||||
%%% - подтверждение бронирования владельцем календаря
|
||||
%%% - отмену бронирования участником
|
||||
%%% - ошибку при повторном бронировании
|
||||
%%% - ошибку 401 без токена
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(user_bookings_tests).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-export([test/0]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Главная тестовая функция
|
||||
%%%===================================================================
|
||||
|
||||
-spec test() -> ok.
|
||||
test() ->
|
||||
ct:pal("=== User Bookings Tests ==="),
|
||||
OwnerToken = api_test_runner:get_user_token(),
|
||||
ParticipantEmail = api_test_runner:unique_email(<<"participant">>),
|
||||
ParticipantToken = api_test_runner:register_and_login(ParticipantEmail, <<"pass">>),
|
||||
|
||||
% Создаём календарь и событие
|
||||
CalId = api_test_runner:create_calendar(OwnerToken, #{title => <<"BookingTest">>}),
|
||||
#{<<"id">> := EventId} = api_test_runner:client_post(
|
||||
<<"/v1/calendars/", CalId/binary, "/events">>, OwnerToken,
|
||||
#{title => <<"Event to book">>,
|
||||
start_time => <<"2026-06-01T10:00:00Z">>,
|
||||
duration => 60}),
|
||||
|
||||
test_create_booking(ParticipantToken, EventId),
|
||||
test_confirm_booking(OwnerToken, EventId),
|
||||
test_cancel_booking(ParticipantToken, EventId),
|
||||
test_duplicate_booking(ParticipantToken, EventId),
|
||||
test_booking_unauthorized(EventId),
|
||||
|
||||
ct:pal("=== All user bookings tests passed ==="),
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Тестовые функции
|
||||
%%%===================================================================
|
||||
|
||||
%% @doc Успешное создание бронирования: 201 Created.
|
||||
-spec test_create_booking(binary(), binary()) -> ok.
|
||||
test_create_booking(Token, EventId) ->
|
||||
ct:pal(" TEST: Create booking"),
|
||||
Path = <<"/v1/events/", EventId/binary, "/bookings">>,
|
||||
Resp = api_test_runner:client_request(post, Path, Token, <<"{}">>),
|
||||
{ok, 201, _, Body} = Resp,
|
||||
#{<<"id">> := BookingId, <<"status">> := Status} = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
?assert(is_binary(BookingId)),
|
||||
?assertEqual(<<"pending">>, Status),
|
||||
ct:pal(" OK: booking ~s created", [BookingId]).
|
||||
|
||||
%% @doc Подтверждение бронирования владельцем: 200 OK.
|
||||
-spec test_confirm_booking(binary(), binary()) -> ok.
|
||||
test_confirm_booking(OwnerToken, EventId) ->
|
||||
ct:pal(" TEST: Confirm booking as owner"),
|
||||
% Создаём новое бронирование, которое ещё не подтверждено
|
||||
Participant2 = api_test_runner:register_and_login(
|
||||
api_test_runner:unique_email(<<"part2">>), <<"pass">>),
|
||||
Path = <<"/v1/events/", EventId/binary, "/bookings">>,
|
||||
#{<<"id">> := BookingId} = api_test_runner:client_post(Path, Participant2, #{}),
|
||||
% Подтверждаем
|
||||
ConfirmPath = <<"/v1/bookings/", BookingId/binary>>,
|
||||
Updated = api_test_runner:client_put(ConfirmPath, OwnerToken,
|
||||
#{action => <<"confirm">>}),
|
||||
?assertEqual(<<"confirmed">>, maps:get(<<"status">>, Updated)),
|
||||
ct:pal(" OK: booking ~s confirmed", [BookingId]).
|
||||
|
||||
%% @doc Отмена бронирования участником: 200 OK.
|
||||
-spec test_cancel_booking(binary(), binary()) -> ok.
|
||||
test_cancel_booking(OwnerToken, EventId) ->
|
||||
ct:pal(" TEST: Cancel booking as participant"),
|
||||
% Создаём нового участника, у которого нет бронирований
|
||||
CancelUserEmail = api_test_runner:unique_email(<<"canceluser">>),
|
||||
CancelUserToken = api_test_runner:register_and_login(CancelUserEmail, <<"pass">>),
|
||||
Path = <<"/v1/events/", EventId/binary, "/bookings">>,
|
||||
#{<<"id">> := BookingId} = api_test_runner:client_post(Path, CancelUserToken, #{}),
|
||||
CancelPath = <<"/v1/bookings/", BookingId/binary>>,
|
||||
Resp = api_test_runner:client_request(delete, CancelPath, CancelUserToken),
|
||||
?assertMatch({ok, 200, _, _}, Resp),
|
||||
ct:pal(" OK: booking ~s cancelled", [BookingId]).
|
||||
|
||||
%% @doc Повторное бронирование того же события: 409 Conflict.
|
||||
-spec test_duplicate_booking(binary(), binary()) -> ok.
|
||||
test_duplicate_booking(ParticipantToken, EventId) ->
|
||||
ct:pal(" TEST: Duplicate booking"),
|
||||
Path = <<"/v1/events/", EventId/binary, "/bookings">>,
|
||||
% Первый раз должно быть 201 (или 200, если уже есть pending)
|
||||
_ = api_test_runner:client_request(post, Path, ParticipantToken, <<"{}">>),
|
||||
% Второй раз – уже booked
|
||||
Resp2 = api_test_runner:client_request(post, Path, ParticipantToken, <<"{}">>),
|
||||
{ok, 409, _, _} = Resp2,
|
||||
ct:pal(" OK: got 409 conflict").
|
||||
|
||||
%% @doc Запрос без токена: 401 Unauthorized.
|
||||
-spec test_booking_unauthorized(binary()) -> ok.
|
||||
test_booking_unauthorized(EventId) ->
|
||||
ct:pal(" TEST: Booking without token"),
|
||||
Path = <<"/v1/events/", EventId/binary, "/bookings">>,
|
||||
Resp = api_test_runner:client_request(post, Path, <<>>, <<"{}">>),
|
||||
?assertMatch({ok, 401, _, _}, Resp),
|
||||
ct:pal(" OK: got 401").
|
||||
Reference in New Issue
Block a user