Раздел api Календари #22
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @doc API-тесты для административного управления календарями.
|
||||
%%% Покрывает эндпоинты:
|
||||
%%% GET /v1/admin/calendars
|
||||
%%% GET /v1/admin/calendars/:id
|
||||
%%% PUT /v1/admin/calendars/:id
|
||||
%%% DELETE /v1/admin/calendars/:id
|
||||
%%% Проверяет пагинацию, фильтрацию по статусу/типу, поиск и сортировку.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(admin_calendars_tests).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-export([test/0]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Главная тестовая функция
|
||||
%%%===================================================================
|
||||
-spec test() -> ok.
|
||||
test() ->
|
||||
ct:pal("=== Admin Calendars Tests ==="),
|
||||
{AdminToken, UserToken, CalIds} = setup(),
|
||||
[CalId1, CalId2, _CalId3] = CalIds,
|
||||
try
|
||||
%% Основные CRUD
|
||||
test_get_calendar(AdminToken, CalId1),
|
||||
test_get_calendar_not_found(AdminToken),
|
||||
test_update_calendar(AdminToken, CalId1, UserToken),
|
||||
test_update_calendar_not_found(AdminToken),
|
||||
test_update_calendar_invalid_body(AdminToken, CalId1),
|
||||
test_delete_calendar(AdminToken, CalId2),
|
||||
test_delete_calendar_not_found(AdminToken),
|
||||
|
||||
%% Пагинация
|
||||
test_pagination(AdminToken),
|
||||
%% Фильтрация
|
||||
test_filter_by_status(AdminToken),
|
||||
test_filter_by_type(AdminToken),
|
||||
test_search(AdminToken),
|
||||
%% Сортировка
|
||||
test_sort_by_title(AdminToken),
|
||||
test_sort_by_created_at(AdminToken)
|
||||
after
|
||||
cleanup(AdminToken, CalIds)
|
||||
end,
|
||||
ct:pal("=== All admin calendars tests passed ==="),
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Подготовка и очистка
|
||||
%%%===================================================================
|
||||
-spec setup() -> {binary(), binary(), [binary()]}.
|
||||
setup() ->
|
||||
ct:pal(" Setup: register user and create calendars"),
|
||||
AdminToken = api_test_runner:get_admin_token(),
|
||||
|
||||
Email = api_test_runner:unique_email(<<"caladmin">>),
|
||||
Password = <<"testpass">>,
|
||||
UserToken = api_test_runner:register_and_login(Email, Password),
|
||||
|
||||
CalId1 = create_calendar(UserToken, <<"Personal Active">>, <<"Desc1">>),
|
||||
CalId2 = create_calendar(UserToken, <<"Commercial">>, <<"Desc2">>),
|
||||
CalId3 = create_calendar(UserToken, <<"Frozen">>, <<"Desc3">>),
|
||||
|
||||
update_calendar_admin(AdminToken, CalId2, #{<<"type">> => <<"commercial">>}),
|
||||
update_calendar_admin(AdminToken, CalId3, #{<<"status">> => <<"frozen">>}),
|
||||
|
||||
ct:pal(" Created calendars: ~p", [[CalId1, CalId2, CalId3]]),
|
||||
{AdminToken, UserToken, [CalId1, CalId2, CalId3]}.
|
||||
|
||||
-spec create_calendar(binary(), binary(), binary()) -> binary().
|
||||
create_calendar(UserToken, Title, Description) ->
|
||||
Body = jsx:encode(#{title => Title, description => Description}),
|
||||
{ok, 201, _, Resp} = api_test_runner:client_request(post, <<"/v1/calendars">>, UserToken, Body),
|
||||
#{<<"id">> := Id} = jsx:decode(list_to_binary(Resp), [return_maps]),
|
||||
Id.
|
||||
|
||||
-spec update_calendar_admin(binary(), binary(), map()) -> ok.
|
||||
update_calendar_admin(AdminToken, CalId, Updates) ->
|
||||
% Получаем текущий календарь
|
||||
{ok, 200, _, RespBody} = api_test_runner:admin_request(get, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, <<"">>),
|
||||
Cal = jsx:decode(list_to_binary(RespBody), [return_maps]),
|
||||
% Сливаем изменения
|
||||
UpdatedCal = maps:merge(Cal, Updates),
|
||||
Body = jsx:encode(UpdatedCal),
|
||||
{ok, 200, _, _} = api_test_runner:admin_request(put, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, Body),
|
||||
ok.
|
||||
|
||||
-spec cleanup(binary(), [binary()]) -> ok.
|
||||
cleanup(_AdminToken, []) -> ok;
|
||||
cleanup(AdminToken, [Id | Rest]) ->
|
||||
catch api_test_runner:admin_request(delete, <<"/v1/admin/calendars/", Id/binary>>, AdminToken, <<"">>),
|
||||
cleanup(AdminToken, Rest).
|
||||
|
||||
%%%===================================================================
|
||||
%%% CRUD тесты
|
||||
%%%===================================================================
|
||||
test_get_calendar(AdminToken, CalId) ->
|
||||
ct:pal(" TEST: Get calendar by ID (admin)"),
|
||||
{ok, 200, _, RespBody} = api_test_runner:admin_request(get, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, <<"">>),
|
||||
Cal = jsx:decode(list_to_binary(RespBody), [return_maps]),
|
||||
?assertEqual(CalId, maps:get(<<"id">>, Cal)),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_get_calendar_not_found(AdminToken) ->
|
||||
ct:pal(" TEST: Get non-existent calendar"),
|
||||
{ok, 404, _, _} = api_test_runner:admin_request(get, <<"/v1/admin/calendars/nonexistent">>, AdminToken, <<"">>),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_update_calendar(AdminToken, CalId, UserToken) ->
|
||||
ct:pal(" TEST: Update calendar (admin)"),
|
||||
NewTitle = <<"Updated by admin">>,
|
||||
update_calendar_admin(AdminToken, CalId, #{<<"title">> => NewTitle}),
|
||||
% Проверяем через пользовательский API
|
||||
{ok, 200, _, UserResp} = api_test_runner:client_request(get, <<"/v1/calendars/", CalId/binary>>, UserToken, <<"">>),
|
||||
UserCal = jsx:decode(list_to_binary(UserResp), [return_maps]),
|
||||
?assertEqual(NewTitle, maps:get(<<"title">>, UserCal)),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_update_calendar_not_found(AdminToken) ->
|
||||
ct:pal(" TEST: Update non-existent calendar"),
|
||||
{ok, 404, _, _} = api_test_runner:admin_request(put, <<"/v1/admin/calendars/nonexistent">>, AdminToken, jsx:encode(#{title => <<"x">>})),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_update_calendar_invalid_body(AdminToken, CalId) ->
|
||||
ct:pal(" TEST: Update calendar with invalid JSON"),
|
||||
{ok, 400, _, _} = api_test_runner:admin_request(put, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, <<"not json">>),
|
||||
ct:pal(" OK").
|
||||
|
||||
test_delete_calendar(AdminToken, CalId) ->
|
||||
ct:pal(" TEST: Delete calendar (admin)"),
|
||||
{ok, 200, _, _} = api_test_runner:admin_request(delete, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, <<"">>),
|
||||
% Проверяем, что календарь не удалён физически, а помечен как deleted (soft delete)
|
||||
{ok, 200, _, RespBody} = api_test_runner:admin_request(get, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, <<"">>),
|
||||
Cal = jsx:decode(list_to_binary(RespBody), [return_maps]),
|
||||
?assertEqual(<<"deleted">>, maps:get(<<"status">>, Cal)),
|
||||
ct:pal(" OK: calendar soft deleted").
|
||||
|
||||
test_delete_calendar_not_found(AdminToken) ->
|
||||
ct:pal(" TEST: Delete non-existent calendar"),
|
||||
{ok, 404, _, _} = api_test_runner:admin_request(delete, <<"/v1/admin/calendars/nonexistent">>, AdminToken, <<"">>),
|
||||
ct:pal(" OK").
|
||||
|
||||
%%%===================================================================
|
||||
%%% Пагинация
|
||||
%%%===================================================================
|
||||
test_pagination(AdminToken) ->
|
||||
ct:pal(" TEST: Pagination"),
|
||||
{ok, 200, Headers1, Body1} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?limit=2&offset=0">>, AdminToken, <<"">>),
|
||||
List1 = jsx:decode(list_to_binary(Body1), [return_maps]),
|
||||
?assertEqual(2, length(List1)),
|
||||
TotalCount = list_to_integer(
|
||||
proplists:get_value("x-total-count", Headers1, "0")
|
||||
),
|
||||
?assert(TotalCount >= 3),
|
||||
|
||||
{ok, 200, _, Body2} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?limit=2&offset=2">>, AdminToken, <<"">>),
|
||||
List2 = jsx:decode(list_to_binary(Body2), [return_maps]),
|
||||
?assert(length(List2) >= 1),
|
||||
ct:pal(" OK: got pages").
|
||||
|
||||
%%%===================================================================
|
||||
%%% Фильтрация
|
||||
%%%===================================================================
|
||||
test_filter_by_status(AdminToken) ->
|
||||
ct:pal(" TEST: Filter by status"),
|
||||
{ok, 200, _, BodyActive} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?status=active">>, AdminToken, <<"">>),
|
||||
ActiveList = jsx:decode(list_to_binary(BodyActive), [return_maps]),
|
||||
[?assertEqual(<<"active">>, maps:get(<<"status">>, C)) || C <- ActiveList],
|
||||
|
||||
{ok, 200, _, BodyFrozen} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?status=frozen">>, AdminToken, <<"">>),
|
||||
FrozenList = jsx:decode(list_to_binary(BodyFrozen), [return_maps]),
|
||||
[?assertEqual(<<"frozen">>, maps:get(<<"status">>, C)) || C <- FrozenList],
|
||||
?assert(length(FrozenList) >= 1),
|
||||
ct:pal(" OK: status filter works").
|
||||
|
||||
test_filter_by_type(AdminToken) ->
|
||||
ct:pal(" TEST: Filter by type"),
|
||||
{ok, 200, _, Body} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?type=commercial">>, AdminToken, <<"">>),
|
||||
CommercialList = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
[?assertEqual(<<"commercial">>, maps:get(<<"type">>, C)) || C <- CommercialList],
|
||||
?assert(length(CommercialList) >= 1),
|
||||
ct:pal(" OK: type filter works").
|
||||
|
||||
test_search(AdminToken) ->
|
||||
ct:pal(" TEST: Search (q parameter)"),
|
||||
{ok, 200, _, Body} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?q=commercial">>, AdminToken, <<"">>),
|
||||
Results = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
?assert(length(Results) >= 1),
|
||||
HasMatch = lists:any(fun(C) ->
|
||||
Title = string:lowercase(binary_to_list(maps:get(<<"title">>, C, <<>>))),
|
||||
Desc = string:lowercase(binary_to_list(maps:get(<<"description">>, C, <<>>))),
|
||||
string:str(Title, "commercial") > 0 orelse
|
||||
string:str(Desc, "commercial") > 0
|
||||
end, Results),
|
||||
?assert(HasMatch),
|
||||
ct:pal(" OK: search works").
|
||||
|
||||
%%%===================================================================
|
||||
%%% Сортировка
|
||||
%%%===================================================================
|
||||
test_sort_by_title(AdminToken) ->
|
||||
ct:pal(" TEST: Sort by title asc"),
|
||||
{ok, 200, _, Body} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?sort_by=title&sort_order=asc">>, AdminToken, <<"">>),
|
||||
List = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
Titles = [maps:get(<<"title">>, C) || C <- List],
|
||||
?assertEqual(lists:sort(Titles), Titles),
|
||||
ct:pal(" OK: sorted by title").
|
||||
|
||||
test_sort_by_created_at(AdminToken) ->
|
||||
ct:pal(" TEST: Sort by created_at desc"),
|
||||
{ok, 200, _, Body} = api_test_runner:admin_request(get, <<"/v1/admin/calendars?sort_by=created_at&sort_order=desc">>, AdminToken, <<"">>),
|
||||
List = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
Dates = [maps:get(<<"created_at">>, C) || C <- List],
|
||||
Sorted = lists:reverse(lists:sort(Dates)),
|
||||
?assertEqual(Sorted, Dates),
|
||||
ct:pal(" OK: sorted by created_at desc").
|
||||
@@ -25,6 +25,7 @@
|
||||
%% @doc Возвращает список тестовых кейсов.
|
||||
all() ->
|
||||
[
|
||||
admin_test_calendars,
|
||||
admin_test_events,
|
||||
admin_test_reviews,
|
||||
admin_test_users,
|
||||
@@ -85,7 +86,10 @@ end_per_suite(Config) ->
|
||||
%%% Тестовые кейсы
|
||||
%%%===================================================================
|
||||
|
||||
%% @doc Тесты для событий.
|
||||
%% @doc Тесты.
|
||||
admin_test_calendars(_Config) ->
|
||||
admin_calendars_tests:test().
|
||||
|
||||
admin_test_events(_Config) ->
|
||||
admin_events_tests:test().
|
||||
|
||||
|
||||
Reference in New Issue
Block a user