API - add typing

This commit is contained in:
Sam
2021-01-02 19:28:03 +01:00
parent 4705393a08
commit 634d06b05a
53 changed files with 1884 additions and 1075 deletions

View File

@@ -1,14 +1,17 @@
import json
from datetime import datetime, timedelta
from io import BytesIO
from unittest.mock import patch
from unittest.mock import Mock, patch
from fittrackee.activities.models import Activity, Sport
from fittrackee.users.models import User
from fittrackee.users.utils_token import get_user_token
from flask import Flask
from freezegun import freeze_time
class TestUserRegistration:
def test_user_can_register(self, app):
def test_user_can_register(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -31,7 +34,9 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 201
def test_it_returns_error_if_user_already_exists(self, app, user_1):
def test_it_returns_error_if_user_already_exists(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
response = client.post(
'/api/auth/register',
@@ -51,7 +56,9 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 400
def test_it_returns_error_if_username_is_too_short(self, app):
def test_it_returns_error_if_username_is_too_short(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
@@ -73,7 +80,9 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 400
def test_it_returns_error_if_username_is_too_long(self, app):
def test_it_returns_error_if_username_is_too_long(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
'/api/auth/register',
@@ -93,7 +102,7 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 400
def test_it_returns_error_if_email_is_invalid(self, app):
def test_it_returns_error_if_email_is_invalid(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -115,7 +124,9 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 400
def test_it_returns_error_if_password_is_too_short(self, app):
def test_it_returns_error_if_password_is_too_short(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
@@ -137,7 +148,7 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 400
def test_it_returns_error_if_passwords_mismatch(self, app):
def test_it_returns_error_if_passwords_mismatch(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -162,7 +173,7 @@ class TestUserRegistration:
assert response.content_type == 'application/json'
assert response.status_code == 400
def test_it_returns_error_if_payload_is_invalid(self, app):
def test_it_returns_error_if_payload_is_invalid(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
'/api/auth/register',
@@ -174,7 +185,7 @@ class TestUserRegistration:
assert 'Invalid payload.', data['message']
assert 'error', data['status']
def test_it_returns_error_if_username_is_missing(self, app):
def test_it_returns_error_if_username_is_missing(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -194,7 +205,7 @@ class TestUserRegistration:
assert 'Invalid payload.' in data['message']
assert 'error' in data['status']
def test_it_returns_error_if_email_is_missing(self, app):
def test_it_returns_error_if_email_is_missing(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -214,7 +225,7 @@ class TestUserRegistration:
assert 'Invalid payload.' in data['message']
assert 'error' in data['status']
def test_it_returns_error_if_password_is_missing(self, app):
def test_it_returns_error_if_password_is_missing(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -234,7 +245,9 @@ class TestUserRegistration:
assert 'Invalid payload.', data['message']
assert 'error', data['status']
def test_it_returns_error_if_password_confirmation_is_missing(self, app):
def test_it_returns_error_if_password_confirmation_is_missing(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
'/api/auth/register',
@@ -250,7 +263,7 @@ class TestUserRegistration:
assert 'Invalid payload.' in data['message']
assert 'error' in data['status']
def test_it_returns_error_if_username_is_invalid(self, app):
def test_it_returns_error_if_username_is_invalid(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -276,7 +289,7 @@ class TestUserRegistration:
class TestUserLogin:
def test_user_can_register(self, app, user_1):
def test_user_can_register(self, app: Flask, user_1: User) -> None:
client = app.test_client()
response = client.post(
@@ -292,7 +305,9 @@ class TestUserLogin:
assert data['message'] == 'Successfully logged in.'
assert data['auth_token']
def test_it_returns_error_if_user_does_not_exists(self, app):
def test_it_returns_error_if_user_does_not_exists(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
@@ -307,7 +322,7 @@ class TestUserLogin:
assert data['status'] == 'error'
assert data['message'] == 'Invalid credentials.'
def test_it_returns_error_on_invalid_payload(self, app):
def test_it_returns_error_on_invalid_payload(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -322,7 +337,9 @@ class TestUserLogin:
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_it_returns_error_if_password_is_invalid(self, app, user_1):
def test_it_returns_error_if_password_is_invalid(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
response = client.post(
@@ -339,7 +356,7 @@ class TestUserLogin:
class TestUserLogout:
def test_user_can_logout(self, app, user_1):
def test_user_can_logout(self, app: Flask, user_1: User) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -360,7 +377,9 @@ class TestUserLogout:
assert data['message'] == 'Successfully logged out.'
assert response.status_code == 200
def test_it_returns_error_with_expired_token(self, app, user_1):
def test_it_returns_error_with_expired_token(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
now = datetime.utcnow()
resp_login = client.post(
@@ -381,7 +400,7 @@ class TestUserLogout:
assert data['message'] == 'Signature expired. Please log in again.'
assert response.status_code == 401
def test_it_returns_error_with_invalid_token(self, app):
def test_it_returns_error_with_invalid_token(self, app: Flask) -> None:
client = app.test_client()
response = client.get(
'/api/auth/logout', headers=dict(Authorization='Bearer invalid')
@@ -391,7 +410,7 @@ class TestUserLogout:
assert data['message'] == 'Invalid token. Please log in again.'
assert response.status_code == 401
def test_it_returns_error_with_invalid_headers(self, app):
def test_it_returns_error_with_invalid_headers(self, app: Flask) -> None:
client = app.test_client()
response = client.get('/api/auth/logout', headers=dict())
data = json.loads(response.data.decode())
@@ -401,7 +420,9 @@ class TestUserLogout:
class TestUserProfile:
def test_it_returns_user_minimal_profile(self, app, user_1):
def test_it_returns_user_minimal_profile(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -432,7 +453,9 @@ class TestUserProfile:
assert data['data']['total_duration'] == '0:00:00'
assert response.status_code == 200
def test_it_returns_user_full_profile(self, app, user_1_full):
def test_it_returns_user_full_profile(
self, app: Flask, user_1_full: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -470,13 +493,13 @@ class TestUserProfile:
def test_it_returns_user_profile_with_activities(
self,
app,
user_1,
sport_1_cycling,
sport_2_running,
activity_cycling_user_1,
activity_running_user_1,
):
app: Flask,
user_1: User,
sport_1_cycling: Sport,
sport_2_running: Sport,
activity_cycling_user_1: Activity,
activity_running_user_1: Activity,
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -505,7 +528,7 @@ class TestUserProfile:
assert data['data']['total_duration'] == '2:40:00'
assert response.status_code == 200
def test_it_returns_error_if_headers_are_invalid(self, app):
def test_it_returns_error_if_headers_are_invalid(self, app: Flask) -> None:
client = app.test_client()
response = client.get(
'/api/auth/profile', headers=dict(Authorization='Bearer invalid')
@@ -517,7 +540,7 @@ class TestUserProfile:
class TestUserProfileUpdate:
def test_it_updates_user_profile(self, app, user_1):
def test_it_updates_user_profile(self, app: Flask, user_1: User) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -568,7 +591,9 @@ class TestUserProfileUpdate:
assert data['data']['total_distance'] == 0
assert data['data']['total_duration'] == '0:00:00'
def test_it_updates_user_profile_without_password(self, app, user_1):
def test_it_updates_user_profile_without_password(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -617,7 +642,9 @@ class TestUserProfileUpdate:
assert data['data']['total_distance'] == 0
assert data['data']['total_duration'] == '0:00:00'
def test_it_returns_error_if_fields_are_missing(self, app, user_1):
def test_it_returns_error_if_fields_are_missing(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -638,7 +665,9 @@ class TestUserProfileUpdate:
assert data['message'] == 'Invalid payload.'
assert response.status_code == 400
def test_it_returns_error_if_payload_is_empty(self, app, user_1):
def test_it_returns_error_if_payload_is_empty(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -659,7 +688,9 @@ class TestUserProfileUpdate:
assert 'Invalid payload.' in data['message']
assert 'error' in data['status']
def test_it_returns_error_if_passwords_mismatch(self, app, user_1):
def test_it_returns_error_if_passwords_mismatch(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -697,8 +728,8 @@ class TestUserProfileUpdate:
assert response.status_code == 400
def test_it_returns_error_if_password_confirmation_is_missing(
self, app, user_1
):
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -736,7 +767,7 @@ class TestUserProfileUpdate:
class TestUserPicture:
def test_it_updates_user_picture(self, app, user_1):
def test_it_updates_user_picture(self, app: Flask, user_1: User) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -774,7 +805,9 @@ class TestUserPicture:
assert 'avatar.png' not in user_1.picture
assert 'avatar2.png' in user_1.picture
def test_it_returns_error_if_file_is_missing(self, app, user_1):
def test_it_returns_error_if_file_is_missing(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -794,7 +827,9 @@ class TestUserPicture:
assert data['message'] == 'No file part.'
assert response.status_code == 400
def test_it_returns_error_if_file_is_invalid(self, app, user_1):
def test_it_returns_error_if_file_is_invalid(
self, app: Flask, user_1: User
) -> None:
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
@@ -818,8 +853,8 @@ class TestUserPicture:
class TestRegistrationConfiguration:
def test_it_returns_error_if_it_exceeds_max_users(
self, app, user_1_admin, user_2, user_3
):
self, app: Flask, user_1_admin: User, user_2: User, user_3: User
) -> None:
client = app.test_client()
resp_login = client.post(
@@ -859,8 +894,12 @@ class TestRegistrationConfiguration:
assert data['message'] == 'Error. Registration is disabled.'
def test_it_disables_registration_on_user_registration(
self, app_no_config, app_config, user_1_admin, user_2
):
self,
app_no_config: Flask,
app_config: Flask,
user_1_admin: User,
user_2: User,
) -> None:
app_config.max_users = 3
client = app_no_config.test_client()
client.post(
@@ -894,11 +933,11 @@ class TestRegistrationConfiguration:
def test_it_does_not_disable_registration_on_user_registration(
self,
app_no_config,
app_config,
user_1_admin,
user_2,
):
app_no_config: Flask,
app_config: Flask,
user_1_admin: User,
user_2: User,
) -> None:
app_config.max_users = 4
client = app_no_config.test_client()
client.post(
@@ -932,8 +971,8 @@ class TestPasswordResetRequest:
@patch('smtplib.SMTP_SSL')
@patch('smtplib.SMTP')
def test_it_requests_password_reset_when_user_exists(
self, mock_smtp, mock_smtp_ssl, app, user_1
):
self, mock_smtp: Mock, mock_smtp_ssl: Mock, app: Flask, user_1: User
) -> None:
client = app.test_client()
response = client.post(
'/api/auth/password/reset-request',
@@ -946,7 +985,9 @@ class TestPasswordResetRequest:
assert data['status'] == 'success'
assert data['message'] == 'Password reset request processed.'
def test_it_does_not_return_error_when_user_does_not_exist(self, app):
def test_it_does_not_return_error_when_user_does_not_exist(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
@@ -960,7 +1001,7 @@ class TestPasswordResetRequest:
assert data['status'] == 'success'
assert data['message'] == 'Password reset request processed.'
def test_it_returns_error_on_invalid_payload(self, app):
def test_it_returns_error_on_invalid_payload(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -974,7 +1015,7 @@ class TestPasswordResetRequest:
assert data['message'] == 'Invalid payload.'
assert data['status'] == 'error'
def test_it_returns_error_on_empty_payload(self, app):
def test_it_returns_error_on_empty_payload(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -990,7 +1031,7 @@ class TestPasswordResetRequest:
class TestPasswordUpdate:
def test_it_returns_error_if_payload_is_empty(self, app):
def test_it_returns_error_if_payload_is_empty(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -1009,7 +1050,7 @@ class TestPasswordUpdate:
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_it_returns_error_if_token_is_missing(self, app):
def test_it_returns_error_if_token_is_missing(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -1028,7 +1069,7 @@ class TestPasswordUpdate:
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_it_returns_error_if_password_is_missing(self, app):
def test_it_returns_error_if_password_is_missing(self, app: Flask) -> None:
client = app.test_client()
response = client.post(
@@ -1047,7 +1088,9 @@ class TestPasswordUpdate:
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_it_returns_error_if_password_confirmation_is_missing(self, app):
def test_it_returns_error_if_password_confirmation_is_missing(
self, app: Flask
) -> None:
client = app.test_client()
response = client.post(
@@ -1066,7 +1109,7 @@ class TestPasswordUpdate:
assert data['status'] == 'error'
assert data['message'] == 'Invalid payload.'
def test_it_returns_error_if_token_is_invalid(self, app):
def test_it_returns_error_if_token_is_invalid(self, app: Flask) -> None:
token = get_user_token(1)
client = app.test_client()
@@ -1087,7 +1130,9 @@ class TestPasswordUpdate:
assert data['status'] == 'error'
assert data['message'] == 'Invalid token. Please request a new token.'
def test_it_returns_error_if_token_is_expired(self, app, user_1):
def test_it_returns_error_if_token_is_expired(
self, app: Flask, user_1: User
) -> None:
now = datetime.utcnow()
token = get_user_token(user_1.id, password_reset=True)
client = app.test_client()
@@ -1112,7 +1157,9 @@ class TestPasswordUpdate:
data['message'] == 'Invalid token. Please request a new token.'
)
def test_it_returns_error_if_password_is_invalid(self, app, user_1):
def test_it_returns_error_if_password_is_invalid(
self, app: Flask, user_1: User
) -> None:
token = get_user_token(user_1.id, password_reset=True)
client = app.test_client()
@@ -1133,7 +1180,7 @@ class TestPasswordUpdate:
assert data['status'] == 'error'
assert data['message'] == 'Password: 8 characters required.\n'
def test_it_update_password(self, app, user_1):
def test_it_update_password(self, app: Flask, user_1: User) -> None:
token = get_user_token(user_1.id, password_reset=True)
client = app.test_client()