%%%------------------------------------------------------------------- %%% @doc Тесты клиентского API для входа пользователей. %%% %%% Покрывает эндпоинты: %%% POST /v1/login %%% %%% Проверяет: %%% - успешный вход с правильными email и паролем %%% - ошибку при неверном пароле %%% - ошибку при несуществующем email %%% - ошибку при отсутствии обязательных полей %%% @end %%%------------------------------------------------------------------- -module(user_login_tests). -include_lib("eunit/include/eunit.hrl"). -export([test/0]). %%%=================================================================== %%% Главная тестовая функция %%%=================================================================== -spec test() -> ok. test() -> ct:pal("=== Client Login Tests ==="), Email = api_test_runner:unique_email(<<"login">>), Password = <<"StrongPass1!">>, % Создаём пользователя для тестов входа api_test_runner:register_and_login(Email, Password), test_successful_login(Email, Password), test_wrong_password(Email), test_nonexistent_email(), test_missing_fields(), ct:pal("=== All client login tests passed ==="), ok. %%%=================================================================== %%% Тестовые функции %%%=================================================================== %% @doc Успешный вход: 200 OK, возвращает токен и данные пользователя. -spec test_successful_login(binary(), binary()) -> ok. test_successful_login(Email, Password) -> ct:pal(" TEST: Successful login"), Resp = api_test_runner:client_request(post, <<"/v1/login">>, <<>>, jsx:encode(#{email => Email, password => Password})), {ok, 200, _, Body} = Resp, #{<<"token">> := Token, <<"user">> := User} = jsx:decode(list_to_binary(Body), [return_maps]), ?assert(is_binary(Token)), ?assertEqual(Email, maps:get(<<"email">>, User)), ct:pal(" OK: user ~s logged in", [maps:get(<<"id">>, User)]). %% @doc Неверный пароль: 401 Unauthorized. -spec test_wrong_password(binary()) -> ok. test_wrong_password(Email) -> ct:pal(" TEST: Wrong password"), Resp = api_test_runner:client_request(post, <<"/v1/login">>, <<>>, jsx:encode(#{email => Email, password => <<"WrongPass1">>})), {ok, 401, _, Body} = Resp, #{<<"error">> := Msg} = jsx:decode(list_to_binary(Body), [return_maps]), ?assertEqual(<<"Invalid credentials">>, Msg), ct:pal(" OK: got 401 unauthorized"). %% @doc Несуществующий email: 401 Unauthorized. -spec test_nonexistent_email() -> ok. test_nonexistent_email() -> ct:pal(" TEST: Nonexistent email"), Resp = api_test_runner:client_request(post, <<"/v1/login">>, <<>>, jsx:encode(#{email => <<"no@such.user">>, password => <<"Anything1">>})), {ok, 401, _, Body} = Resp, #{<<"error">> := Msg} = jsx:decode(list_to_binary(Body), [return_maps]), ?assertEqual(<<"Invalid credentials">>, Msg), ct:pal(" OK: got 401 unauthorized"). %% @doc Отсутствие обязательных полей: 400 Bad Request. -spec test_missing_fields() -> ok. test_missing_fields() -> ct:pal(" TEST: Missing required fields"), Resp1 = api_test_runner:client_request(post, <<"/v1/login">>, <<>>, jsx:encode(#{email => <<"a@b.com">>})), ?assertMatch({ok, 400, _, _}, Resp1), Resp2 = api_test_runner:client_request(post, <<"/v1/login">>, <<>>, jsx:encode(#{password => <<"NoEmail1">>})), ?assertMatch({ok, 400, _, _}, Resp2), ct:pal(" OK: 400 on missing fields").