From b17b94076da711e86373541cc0b805dd1b696f84 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 2 Apr 2022 17:16:10 +0200 Subject: [PATCH] API - refacto tests move some tests in models tests (to simplify api tests) + doc fix --- .../tests/application/test_app_config_api.py | 16 +- .../application/test_app_config_model.py | 51 +++- .../tests/fixtures/fixtures_workouts.py | 81 +++--- fittrackee/tests/users/test_auth_api.py | 134 +--------- fittrackee/tests/users/test_users_api.py | 157 +----------- fittrackee/tests/users/test_users_model.py | 237 ++++++++++++++---- fittrackee/tests/utils.py | 9 +- .../tests/workouts/test_records_model.py | 43 ++-- fittrackee/tests/workouts/test_sports_api.py | 96 +++---- .../tests/workouts/test_sports_model.py | 8 +- .../tests/workouts/test_workouts_api_0_get.py | 166 ++++++------ .../tests/workouts/test_workouts_model.py | 169 ++++++++++--- fittrackee/users/auth.py | 3 +- 13 files changed, 570 insertions(+), 600 deletions(-) diff --git a/fittrackee/tests/application/test_app_config_api.py b/fittrackee/tests/application/test_app_config_api.py index ce7a613d..493312e3 100644 --- a/fittrackee/tests/application/test_app_config_api.py +++ b/fittrackee/tests/application/test_app_config_api.py @@ -4,17 +4,18 @@ from typing import Optional import pytest from flask import Flask -import fittrackee from fittrackee.application.models import AppConfig from fittrackee.users.models import User from ..mixins import ApiTestCaseMixin +from ..utils import jsonify_dict class TestGetConfig(ApiTestCaseMixin): def test_it_gets_application_config_for_unauthenticated_user( self, app: Flask ) -> None: + app_config = AppConfig.query.first() client = app.test_client() response = client.get('/api/config') @@ -22,18 +23,7 @@ class TestGetConfig(ApiTestCaseMixin): data = json.loads(response.data.decode()) assert response.status_code == 200 assert 'success' in data['status'] - assert data['data']['admin_contact'] is None - assert data['data']['gpx_limit_import'] == 10 - assert data['data']['is_registration_enabled'] is True - assert data['data']['max_single_file_size'] == 1048576 - assert data['data']['max_zip_file_size'] == 10485760 - assert data['data']['max_users'] == 100 - assert data['data']['map_attribution'] == ( - '© OpenStreetMap ' - 'contributors' - ) - assert data['data']['version'] == fittrackee.__version__ + assert data['data'] == jsonify_dict(app_config.serialize()) def test_it_gets_application_config( self, app: Flask, user_1: User diff --git a/fittrackee/tests/application/test_app_config_model.py b/fittrackee/tests/application/test_app_config_model.py index e2e824ac..bf295ace 100644 --- a/fittrackee/tests/application/test_app_config_model.py +++ b/fittrackee/tests/application/test_app_config_model.py @@ -1,22 +1,51 @@ from flask import Flask +from fittrackee import VERSION from fittrackee.application.models import AppConfig +from fittrackee.users.models import User class TestConfigModel: def test_application_config(self, app: Flask) -> None: app_config = AppConfig.query.first() - assert 1 == app_config.id + app_config.admin_contact = 'admin@example.com' + + assert app_config.is_registration_enabled is True + assert ( + app_config.map_attribution + == app.config['TILE_SERVER']['ATTRIBUTION'] + ) serialized_app_config = app_config.serialize() - assert serialized_app_config['gpx_limit_import'] == 10 - assert serialized_app_config['is_registration_enabled'] is True - assert serialized_app_config['max_single_file_size'] == 1048576 - assert serialized_app_config['max_zip_file_size'] == 10485760 - assert serialized_app_config['max_users'] == 100 - assert serialized_app_config['map_attribution'] == ( - '© OpenStreetMap ' - 'contributors' + assert ( + serialized_app_config['admin_contact'] == app_config.admin_contact ) - assert 'admin_contact' in serialized_app_config + assert ( + serialized_app_config['gpx_limit_import'] + == app_config.gpx_limit_import + ) + assert serialized_app_config['is_registration_enabled'] is True + assert ( + serialized_app_config['max_single_file_size'] + == app_config.max_single_file_size + ) + assert ( + serialized_app_config['max_zip_file_size'] + == app_config.max_zip_file_size + ) + assert serialized_app_config['max_users'] == app_config.max_users + assert ( + serialized_app_config['map_attribution'] + == app_config.map_attribution + ) + assert serialized_app_config['version'] == VERSION + + def test_it_returns_registration_disabled_when_users_count_exceeds_limit( + self, app: Flask, user_1: User, user_2: User + ) -> None: + app_config = AppConfig.query.first() + app_config.max_users = 2 + serialized_app_config = app_config.serialize() + + assert app_config.is_registration_enabled is False + assert serialized_app_config['is_registration_enabled'] is False diff --git a/fittrackee/tests/fixtures/fixtures_workouts.py b/fittrackee/tests/fixtures/fixtures_workouts.py index 4db4609a..46402c61 100644 --- a/fittrackee/tests/fixtures/fixtures_workouts.py +++ b/fittrackee/tests/fixtures/fixtures_workouts.py @@ -1,6 +1,6 @@ import datetime from io import BytesIO -from typing import Generator +from typing import Generator, List from unittest.mock import Mock, patch from uuid import uuid4 @@ -107,96 +107,105 @@ def workout_running_user_1() -> Workout: @pytest.fixture() -def seven_workouts_user_1() -> Workout: - workout = Workout( +def seven_workouts_user_1() -> List[Workout]: + workouts = [] + workout_1 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('20/03/2017', '%d/%m/%Y'), distance=5, duration=datetime.timedelta(seconds=1024), ) - update_workout(workout) - workout.ascent = 120 - workout.descent = 200 - db.session.add(workout) + update_workout(workout_1) + workout_1.ascent = 120 + workout_1.descent = 200 + db.session.add(workout_1) db.session.flush() + workouts.append(workout_1) - workout = Workout( + workout_2 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/06/2017', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=3456), ) - update_workout(workout) - workout.ascent = 100 - workout.descent = 80 - db.session.add(workout) + update_workout(workout_2) + workout_2.ascent = 100 + workout_2.descent = 80 + db.session.add(workout_2) db.session.flush() + workouts.append(workout_2) - workout = Workout( + workout_3 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=1024), ) - update_workout(workout) - workout.ascent = 80 - workout.descent = 100 - db.session.add(workout) + update_workout(workout_3) + workout_3.ascent = 80 + workout_3.descent = 100 + db.session.add(workout_3) db.session.flush() + workouts.append(workout_3) - workout = Workout( + workout_4 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), distance=1, duration=datetime.timedelta(seconds=600), ) - update_workout(workout) - workout.ascent = 120 - workout.descent = 180 - db.session.add(workout) + update_workout(workout_4) + workout_4.ascent = 120 + workout_4.descent = 180 + db.session.add(workout_4) db.session.flush() + workouts.append(workout_4) - workout = Workout( + workout_5 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('23/02/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=1000), ) - update_workout(workout) - workout.ascent = 100 - workout.descent = 200 - db.session.add(workout) + update_workout(workout_5) + workout_5.ascent = 100 + workout_5.descent = 200 + db.session.add(workout_5) db.session.flush() + workouts.append(workout_5) - workout = Workout( + workout_6 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('01/04/2018', '%d/%m/%Y'), distance=8, duration=datetime.timedelta(seconds=6000), ) - update_workout(workout) - workout.ascent = 40 - workout.descent = 20 - db.session.add(workout) + update_workout(workout_6) + workout_6.ascent = 40 + workout_6.descent = 20 + db.session.add(workout_6) db.session.flush() + workouts.append(workout_6) - workout = Workout( + workout_7 = Workout( user_id=1, sport_id=1, workout_date=datetime.datetime.strptime('09/05/2018', '%d/%m/%Y'), distance=10, duration=datetime.timedelta(seconds=3000), ) - update_workout(workout) - db.session.add(workout) + update_workout(workout_7) + db.session.add(workout_7) db.session.commit() - return workout + workouts.append(workout_7) + + return workouts @pytest.fixture() diff --git a/fittrackee/tests/users/test_auth_api.py b/fittrackee/tests/users/test_auth_api.py index 15800979..fd4842ff 100644 --- a/fittrackee/tests/users/test_auth_api.py +++ b/fittrackee/tests/users/test_auth_api.py @@ -9,9 +9,10 @@ from freezegun import freeze_time from fittrackee.users.models import User, UserSportPreference from fittrackee.users.utils.token import get_user_token -from fittrackee.workouts.models import Sport, Workout +from fittrackee.workouts.models import Sport from ..mixins import ApiTestCaseMixin +from ..utils import jsonify_dict USER_AGENT = ( 'Mozilla/5.0 (X11; Linux x86_64; rv:98.0) Gecko/20100101 Firefox/98.0' @@ -453,9 +454,7 @@ class TestUserProfile(ApiTestCaseMixin): self.assert_401(response, 'invalid token, please log in again') - def test_it_returns_user_minimal_profile( - self, app: Flask, user_1: User - ) -> None: + def test_it_returns_user(self, app: Flask, user_1: User) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email ) @@ -468,92 +467,7 @@ class TestUserProfile(ApiTestCaseMixin): assert response.status_code == 200 data = json.loads(response.data.decode()) assert data['status'] == 'success' - assert data['data'] is not None - assert data['data']['username'] == 'test' - assert data['data']['email'] == 'test@test.com' - assert data['data']['created_at'] - assert not data['data']['admin'] - assert data['data']['timezone'] is None - assert data['data']['weekm'] is False - assert data['data']['imperial_units'] is False - assert data['data']['language'] is None - assert data['data']['nb_sports'] == 0 - assert data['data']['nb_workouts'] == 0 - assert data['data']['records'] == [] - assert data['data']['sports_list'] == [] - assert data['data']['total_distance'] == 0 - assert data['data']['total_duration'] == '0:00:00' - - def test_it_returns_user_full_profile( - self, app: Flask, user_1_full: User - ) -> None: - client, auth_token = self.get_test_client_and_auth_token( - app, user_1_full.email - ) - - response = client.get( - '/api/auth/profile', - headers=dict(Authorization=f'Bearer {auth_token}'), - ) - - assert response.status_code == 200 - data = json.loads(response.data.decode()) - assert data['status'] == 'success' - assert data['data'] is not None - assert data['data']['username'] == 'test' - assert data['data']['email'] == 'test@test.com' - assert data['data']['created_at'] - assert not data['data']['admin'] - assert data['data']['first_name'] == 'John' - assert data['data']['last_name'] == 'Doe' - assert data['data']['birth_date'] - assert data['data']['bio'] == 'just a random guy' - assert data['data']['imperial_units'] is False - assert data['data']['location'] == 'somewhere' - assert data['data']['timezone'] == 'America/New_York' - assert data['data']['weekm'] is False - assert data['data']['language'] == 'en' - assert data['data']['nb_sports'] == 0 - assert data['data']['nb_workouts'] == 0 - assert data['data']['records'] == [] - assert data['data']['sports_list'] == [] - assert data['data']['total_distance'] == 0 - assert data['data']['total_duration'] == '0:00:00' - - def test_it_returns_user_profile_with_workouts( - self, - app: Flask, - user_1: User, - sport_1_cycling: Sport, - sport_2_running: Sport, - workout_cycling_user_1: Workout, - workout_running_user_1: Workout, - ) -> None: - client, auth_token = self.get_test_client_and_auth_token( - app, user_1.email - ) - - response = client.get( - '/api/auth/profile', - headers=dict(Authorization=f'Bearer {auth_token}'), - ) - - assert response.status_code == 200 - data = json.loads(response.data.decode()) - assert data['status'] == 'success' - assert data['data'] is not None - assert data['data']['username'] == 'test' - assert data['data']['email'] == 'test@test.com' - assert data['data']['created_at'] - assert not data['data']['admin'] - assert data['data']['timezone'] is None - assert data['data']['imperial_units'] is False - assert data['data']['nb_sports'] == 2 - assert data['data']['nb_workouts'] == 2 - assert len(data['data']['records']) == 8 - assert data['data']['sports_list'] == [1, 2] - assert data['data']['total_distance'] == 22 - assert data['data']['total_duration'] == '2:40:00' + assert data['data'] == jsonify_dict(user_1.serialize(user_1)) class TestUserProfileUpdate(ApiTestCaseMixin): @@ -618,25 +532,7 @@ class TestUserProfileUpdate(ApiTestCaseMixin): data = json.loads(response.data.decode()) assert data['status'] == 'success' assert data['message'] == 'user profile updated' - assert data['data']['username'] == user_1.username - assert data['data']['email'] == user_1.email - assert not data['data']['admin'] - assert data['data']['created_at'] - assert data['data']['first_name'] == first_name - assert data['data']['last_name'] == last_name - assert data['data']['birth_date'] == 'Tue, 01 Jan 1980 00:00:00 GMT' - assert data['data']['bio'] == bio - assert data['data']['imperial_units'] is False - assert data['data']['location'] == location - assert data['data']['timezone'] is None - assert data['data']['weekm'] is False - assert data['data']['language'] is None - assert data['data']['nb_sports'] == 0 - assert data['data']['nb_workouts'] == 0 - assert data['data']['records'] == [] - assert data['data']['sports_list'] == [] - assert data['data']['total_distance'] == 0 - assert data['data']['total_duration'] == '0:00:00' + assert data['data'] == jsonify_dict(user_1.serialize(user_1)) class TestUserAccountUpdate(ApiTestCaseMixin): @@ -1270,25 +1166,7 @@ class TestUserPreferencesUpdate(ApiTestCaseMixin): data = json.loads(response.data.decode()) assert data['status'] == 'success' assert data['message'] == 'user preferences updated' - assert data['data']['username'] == user_1.username - assert data['data']['email'] == user_1.email - assert not data['data']['admin'] - assert data['data']['created_at'] - assert data['data']['first_name'] is None - assert data['data']['last_name'] is None - assert data['data']['birth_date'] is None - assert data['data']['bio'] is None - assert data['data']['imperial_units'] - assert data['data']['location'] is None - assert data['data']['timezone'] == 'America/New_York' - assert data['data']['weekm'] is True - assert data['data']['language'] == 'fr' - assert data['data']['nb_sports'] == 0 - assert data['data']['nb_workouts'] == 0 - assert data['data']['records'] == [] - assert data['data']['sports_list'] == [] - assert data['data']['total_distance'] == 0 - assert data['data']['total_duration'] == '0:00:00' + assert data['data'] == jsonify_dict(user_1.serialize(user_1)) class TestUserSportPreferencesUpdate(ApiTestCaseMixin): diff --git a/fittrackee/tests/users/test_users_api.py b/fittrackee/tests/users/test_users_api.py index b9295040..e7552294 100644 --- a/fittrackee/tests/users/test_users_api.py +++ b/fittrackee/tests/users/test_users_api.py @@ -10,6 +10,7 @@ from fittrackee.utils import get_readable_duration from fittrackee.workouts.models import Sport, Workout from ..mixins import ApiTestCaseMixin +from ..utils import jsonify_dict class TestGetUser(ApiTestCaseMixin): @@ -66,22 +67,7 @@ class TestGetUser(ApiTestCaseMixin): assert data['status'] == 'success' assert len(data['data']['users']) == 1 user = data['data']['users'][0] - assert user['username'] == inactive_user.username - assert user['email'] == inactive_user.email - assert user['created_at'] - assert not user['admin'] - assert not user['is_active'] - assert user['first_name'] is None - assert user['last_name'] is None - assert user['birth_date'] is None - assert user['bio'] is None - assert user['location'] is None - assert user['nb_sports'] == 0 - assert user['nb_workouts'] == 0 - assert user['records'] == [] - assert user['sports_list'] == [] - assert user['total_distance'] == 0 - assert user['total_duration'] == '0:00:00' + assert user == jsonify_dict(inactive_user.serialize(user_1_admin)) def test_it_gets_single_user_without_workouts( self, app: Flask, user_1_admin: User, user_2: User @@ -101,22 +87,7 @@ class TestGetUser(ApiTestCaseMixin): assert data['status'] == 'success' assert len(data['data']['users']) == 1 user = data['data']['users'][0] - assert user['username'] == user_2.username - assert user['email'] == user_2.email - assert user['created_at'] - assert not user['admin'] - assert user['is_active'] - assert user['first_name'] is None - assert user['last_name'] is None - assert user['birth_date'] is None - assert user['bio'] is None - assert user['location'] is None - assert user['nb_sports'] == 0 - assert user['nb_workouts'] == 0 - assert user['records'] == [] - assert user['sports_list'] == [] - assert user['total_distance'] == 0 - assert user['total_duration'] == '0:00:00' + assert user == jsonify_dict(user_2.serialize(user_1_admin)) def test_it_gets_single_user_with_workouts( self, @@ -143,22 +114,7 @@ class TestGetUser(ApiTestCaseMixin): assert data['status'] == 'success' assert len(data['data']['users']) == 1 user = data['data']['users'][0] - assert user['username'] == user_1.username - assert user['email'] == user_1.email - assert user['created_at'] - assert not user['admin'] - assert user['is_active'] - assert user['first_name'] is None - assert user['last_name'] is None - assert user['birth_date'] is None - assert user['bio'] is None - assert user['location'] is None - assert len(user['records']) == 8 - assert user['nb_sports'] == 2 - assert user['nb_workouts'] == 2 - assert user['sports_list'] == [1, 2] - assert user['total_distance'] == 22 - assert user['total_duration'] == '2:40:00' + assert user == jsonify_dict(user_1.serialize(user_2_admin)) def test_it_returns_error_if_user_does_not_exist( self, app: Flask, user_1_admin: User @@ -207,106 +163,15 @@ class TestGetUsers(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['users']) == 3 - assert 'created_at' in data['data']['users'][0] - assert 'created_at' in data['data']['users'][1] - assert 'created_at' in data['data']['users'][2] - assert 'admin' in data['data']['users'][0]['username'] - assert 'inactive' in data['data']['users'][1]['username'] - assert 'sam' in data['data']['users'][2]['username'] - assert 'admin@example.com' in data['data']['users'][0]['email'] - assert 'inactive@example.com' in data['data']['users'][1]['email'] - assert 'sam@test.com' in data['data']['users'][2]['email'] - assert data['data']['users'][0]['is_active'] - assert not data['data']['users'][1]['is_active'] - assert data['data']['users'][2]['is_active'] - assert data['data']['users'][0]['imperial_units'] is False - assert data['data']['users'][0]['timezone'] is None - assert data['data']['users'][0]['weekm'] is False - assert data['data']['users'][0]['language'] is None - assert data['data']['users'][0]['nb_sports'] == 0 - assert data['data']['users'][0]['nb_workouts'] == 0 - assert data['data']['users'][0]['records'] == [] - assert data['data']['users'][0]['sports_list'] == [] - assert data['data']['users'][0]['total_distance'] == 0 - assert data['data']['users'][0]['total_duration'] == '0:00:00' - assert data['data']['users'][1]['nb_sports'] == 0 - assert data['data']['users'][1]['nb_workouts'] == 0 - assert data['data']['users'][1]['records'] == [] - assert data['data']['users'][1]['sports_list'] == [] - assert data['data']['users'][1]['total_distance'] == 0 - assert data['data']['users'][1]['total_duration'] == '0:00:00' - assert data['data']['users'][2]['records'] == [] - assert data['data']['users'][2]['nb_sports'] == 0 - assert data['data']['users'][2]['nb_workouts'] == 0 - assert data['data']['users'][2]['sports_list'] == [] - assert data['data']['users'][2]['total_distance'] == 0 - assert data['data']['users'][2]['total_duration'] == '0:00:00' - assert data['pagination'] == { - 'has_next': False, - 'has_prev': False, - 'page': 1, - 'pages': 1, - 'total': 3, - } - - def test_it_gets_users_list_with_workouts( - self, - app: Flask, - user_1_admin: User, - user_2: User, - user_3: User, - sport_1_cycling: Sport, - workout_cycling_user_1: Workout, - sport_2_running: Sport, - workout_running_user_1: Workout, - workout_cycling_user_2: Workout, - ) -> None: - client, auth_token = self.get_test_client_and_auth_token( - app, user_1_admin.email + assert data['data']['users'][0] == jsonify_dict( + user_1_admin.serialize(user_1_admin) ) - - response = client.get( - '/api/users', - headers=dict(Authorization=f'Bearer {auth_token}'), + assert data['data']['users'][1] == jsonify_dict( + inactive_user.serialize(user_1_admin) + ) + assert data['data']['users'][2] == jsonify_dict( + user_3.serialize(user_1_admin) ) - - data = json.loads(response.data.decode()) - assert response.status_code == 200 - assert 'success' in data['status'] - assert len(data['data']['users']) == 3 - assert 'created_at' in data['data']['users'][0] - assert 'created_at' in data['data']['users'][1] - assert 'created_at' in data['data']['users'][2] - assert 'admin' in data['data']['users'][0]['username'] - assert 'toto' in data['data']['users'][1]['username'] - assert 'sam' in data['data']['users'][2]['username'] - assert 'admin@example.com' in data['data']['users'][0]['email'] - assert 'toto@toto.com' in data['data']['users'][1]['email'] - assert 'sam@test.com' in data['data']['users'][2]['email'] - assert data['data']['users'][0]['is_active'] - assert data['data']['users'][1]['is_active'] - assert data['data']['users'][2]['is_active'] - assert data['data']['users'][0]['imperial_units'] is False - assert data['data']['users'][0]['timezone'] is None - assert data['data']['users'][0]['weekm'] is False - assert data['data']['users'][0]['nb_sports'] == 2 - assert data['data']['users'][0]['nb_workouts'] == 2 - assert len(data['data']['users'][0]['records']) == 8 - assert data['data']['users'][0]['sports_list'] == [1, 2] - assert data['data']['users'][0]['total_distance'] == 22.0 - assert data['data']['users'][0]['total_duration'] == '2:40:00' - assert data['data']['users'][1]['nb_sports'] == 1 - assert data['data']['users'][1]['nb_workouts'] == 1 - assert len(data['data']['users'][1]['records']) == 4 - assert data['data']['users'][1]['sports_list'] == [1] - assert data['data']['users'][1]['total_distance'] == 15 - assert data['data']['users'][1]['total_duration'] == '1:00:00' - assert data['data']['users'][2]['nb_sports'] == 0 - assert data['data']['users'][2]['nb_workouts'] == 0 - assert len(data['data']['users'][2]['records']) == 0 - assert data['data']['users'][2]['sports_list'] == [] - assert data['data']['users'][2]['total_distance'] == 0 - assert data['data']['users'][2]['total_duration'] == '0:00:00' assert data['pagination'] == { 'has_next': False, 'has_prev': False, diff --git a/fittrackee/tests/users/test_users_model.py b/fittrackee/tests/users/test_users_model.py index 8778dc39..93a5e0c1 100644 --- a/fittrackee/tests/users/test_users_model.py +++ b/fittrackee/tests/users/test_users_model.py @@ -9,77 +9,145 @@ from fittrackee.workouts.models import Sport, Workout class TestUserModel: - @staticmethod - def assert_serialized_used(serialized_user: Dict) -> None: - assert 'created_at' in serialized_user - assert serialized_user['admin'] is False - assert serialized_user['first_name'] is None - assert serialized_user['is_active'] - assert serialized_user['last_name'] is None - assert serialized_user['bio'] is None - assert serialized_user['location'] is None - assert serialized_user['birth_date'] is None - assert serialized_user['picture'] is False - assert serialized_user['nb_workouts'] == 0 - - def test_user_model_as_auth_user(self, app: Flask, user_1: User) -> None: + def test_it_returns_username_in_string_value( + self, app: Flask, user_1: User + ) -> None: assert '' == str(user_1) + +class UserModelAssertMixin: + @staticmethod + def assert_user_account(serialized_user: Dict, user: User) -> None: + assert serialized_user['admin'] == user.admin + assert serialized_user['email_to_confirm'] == user.email_to_confirm + assert serialized_user['is_active'] == user.is_active + assert serialized_user['username'] == user.username + + @staticmethod + def assert_user_profile(serialized_user: Dict, user: User) -> None: + assert serialized_user['bio'] == user.bio + assert serialized_user['birth_date'] == user.birth_date + assert serialized_user['first_name'] == user.first_name + assert serialized_user['last_name'] == user.last_name + assert serialized_user['location'] == user.location + assert serialized_user['picture'] is False + + @staticmethod + def assert_workouts_keys_are_present(serialized_user: Dict) -> None: + assert 'nb_sports' in serialized_user + assert 'nb_workouts' in serialized_user + assert 'records' in serialized_user + assert 'sports_list' in serialized_user + assert 'total_distance' in serialized_user + assert 'total_duration' in serialized_user + + +class TestUserSerializeAsAuthUser(UserModelAssertMixin): + def test_it_returns_user_account_infos( + self, app: Flask, user_1: User + ) -> None: serialized_user = user_1.serialize(user_1) - self.assert_serialized_used(serialized_user) - assert 'test' == serialized_user['username'] - assert 'test@test.com' == serialized_user['email'] - assert serialized_user['nb_sports'] == 0 - assert serialized_user['records'] == [] - assert serialized_user['sports_list'] == [] - assert serialized_user['total_distance'] == 0 - assert serialized_user['total_duration'] == '0:00:00' - assert serialized_user['imperial_units'] is False - assert serialized_user['language'] is None - assert serialized_user['timezone'] is None - assert serialized_user['weekm'] is False - assert serialized_user['email_to_confirm'] is None - assert 'confirmation_token' not in serialized_user + self.assert_user_account(serialized_user, user_1) - def test_user_model_as_admin( + def test_it_returns_user_profile_infos( + self, app: Flask, user_1: User + ) -> None: + serialized_user = user_1.serialize(user_1) + + self.assert_user_profile(serialized_user, user_1) + + def test_it_returns_user_preferences( + self, app: Flask, user_1: User + ) -> None: + serialized_user = user_1.serialize(user_1) + + assert serialized_user['imperial_units'] == user_1.imperial_units + assert serialized_user['language'] == user_1.language + assert serialized_user['timezone'] == user_1.timezone + assert serialized_user['weekm'] == user_1.weekm + + def test_it_returns_workouts_infos(self, app: Flask, user_1: User) -> None: + serialized_user = user_1.serialize(user_1) + + self.assert_workouts_keys_are_present(serialized_user) + + def test_it_does_not_return_confirmation_token( + self, app: Flask, user_1_admin: User, user_2: User + ) -> None: + serialized_user = user_2.serialize(user_1_admin) + + assert 'confirmation_token' not in serialized_user + + +class TestUserSerializeAsAdmin(UserModelAssertMixin): + def test_it_returns_user_account_infos( + self, app: Flask, user_1_admin: User, user_2: User + ) -> None: + serialized_user = user_2.serialize(user_1_admin) + + self.assert_user_account(serialized_user, user_2) + + def test_it_returns_user_profile_infos( + self, app: Flask, user_1_admin: User, user_2: User + ) -> None: + serialized_user = user_2.serialize(user_1_admin) + + self.assert_user_profile(serialized_user, user_1_admin) + + def test_it_does_return_user_preferences( self, app: Flask, user_1_admin: User, user_2: User ) -> None: serialized_user = user_2.serialize(user_1_admin) - self.assert_serialized_used(serialized_user) - assert 'toto' == serialized_user['username'] - assert 'toto@toto.com' == serialized_user['email'] - assert serialized_user['nb_sports'] == 0 - assert serialized_user['records'] == [] - assert serialized_user['sports_list'] == [] - assert serialized_user['total_distance'] == 0 - assert serialized_user['total_duration'] == '0:00:00' - assert serialized_user['email_to_confirm'] is None assert 'imperial_units' not in serialized_user assert 'language' not in serialized_user assert 'timezone' not in serialized_user assert 'weekm' not in serialized_user + + def test_it_returns_workouts_infos( + self, app: Flask, user_1_admin: User, user_2: User + ) -> None: + serialized_user = user_2.serialize(user_1_admin) + + self.assert_workouts_keys_are_present(serialized_user) + + def test_it_does_not_return_confirmation_token( + self, app: Flask, user_1_admin: User, user_2: User + ) -> None: + serialized_user = user_2.serialize(user_1_admin) + assert 'confirmation_token' not in serialized_user + +class TestInactiveUserSerialize(UserModelAssertMixin): + def test_it_returns_is_active_to_false_for_inactive_user( + self, + app: Flask, + inactive_user: User, + ) -> None: + serialized_user = inactive_user.serialize(inactive_user) + + assert serialized_user['is_active'] is False + + +class TestUserSerializeAsRegularUser(UserModelAssertMixin): def test_user_model_as_regular_user( self, app: Flask, user_1: User, user_2: User ) -> None: with pytest.raises(UserNotFoundException): user_2.serialize(user_1) - def test_encode_auth_token(self, app: Flask, user_1: User) -> None: - auth_token = user_1.encode_auth_token(user_1.id) - assert isinstance(auth_token, str) - def test_encode_password_token(self, app: Flask, user_1: User) -> None: - password_token = user_1.encode_password_reset_token(user_1.id) - assert isinstance(password_token, str) +class TestUserRecords(UserModelAssertMixin): + def test_it_returns_empty_list_when_no_workouts( + self, + app: Flask, + user_1: User, + ) -> None: + serialized_user = user_1.serialize(user_1) - def test_decode_auth_token(self, app: Flask, user_1: User) -> None: - auth_token = user_1.encode_auth_token(user_1.id) - assert isinstance(auth_token, str) - assert User.decode_auth_token(auth_token) == user_1.id + assert serialized_user['records'] == [] def test_it_returns_user_records( self, @@ -100,14 +168,79 @@ class TestUserModel: ) assert serialized_user['records'][0]['workout_date'] - def test_it_returns_is_active_to_false_fot_inactive_user( + +class TestUserWorkouts(UserModelAssertMixin): + def test_it_returns_infos_when_no_workouts( self, app: Flask, - inactive_user: User, + user_1: User, ) -> None: - serialized_user = inactive_user.serialize(inactive_user) + serialized_user = user_1.serialize(user_1) - assert serialized_user['is_active'] is False + assert serialized_user['nb_sports'] == 0 + assert serialized_user['nb_workouts'] == 0 + assert serialized_user['sports_list'] == [] + assert serialized_user['total_distance'] == 0 + assert serialized_user['total_duration'] == '0:00:00' + + def test_it_returns_infos_when_only_one_workout_exists( + self, + app: Flask, + user_1: User, + sport_1_cycling: Sport, + workout_cycling_user_1: Workout, + ) -> None: + serialized_user = user_1.serialize(user_1) + + assert serialized_user['nb_sports'] == 1 + assert serialized_user['nb_workouts'] == 1 + assert serialized_user['sports_list'] == [sport_1_cycling.id] + assert ( + serialized_user['total_distance'] + == workout_cycling_user_1.distance + ) + assert serialized_user['total_duration'] == str( + workout_cycling_user_1.duration + ) + + def test_it_returns_infos_when_several_sports( + self, + app: Flask, + user_1: User, + sport_1_cycling: Sport, + sport_2_running: Sport, + workout_cycling_user_1: Workout, + workout_running_user_1: Workout, + ) -> None: + serialized_user = user_1.serialize(user_1) + + assert serialized_user['nb_sports'] == 2 + assert serialized_user['nb_workouts'] == 2 + assert serialized_user['sports_list'] == [ + sport_1_cycling.id, + sport_2_running.id, + ] + assert serialized_user['total_distance'] == ( + workout_cycling_user_1.distance + workout_running_user_1.distance + ) + assert serialized_user['total_duration'] == str( + workout_cycling_user_1.duration + workout_running_user_1.duration + ) + + +class TestUserModelToken: + def test_encode_auth_token(self, app: Flask, user_1: User) -> None: + auth_token = user_1.encode_auth_token(user_1.id) + assert isinstance(auth_token, str) + + def test_encode_password_token(self, app: Flask, user_1: User) -> None: + password_token = user_1.encode_password_reset_token(user_1.id) + assert isinstance(password_token, str) + + def test_decode_auth_token(self, app: Flask, user_1: User) -> None: + auth_token = user_1.encode_auth_token(user_1.id) + assert isinstance(auth_token, str) + assert User.decode_auth_token(auth_token) == user_1.id class TestUserSportModel: diff --git a/fittrackee/tests/utils.py b/fittrackee/tests/utils.py index 9f513a3b..a93db3cf 100644 --- a/fittrackee/tests/utils.py +++ b/fittrackee/tests/utils.py @@ -1,6 +1,9 @@ import random import string -from typing import Optional +from json import loads +from typing import Dict, Optional + +from flask import json as flask_json def random_string( @@ -23,3 +26,7 @@ def random_string( def random_email() -> str: return random_string(suffix='@example.com') + + +def jsonify_dict(data: Dict) -> Dict: + return loads(flask_json.dumps(data)) diff --git a/fittrackee/tests/workouts/test_records_model.py b/fittrackee/tests/workouts/test_records_model.py index afaec5e6..e80c4e4a 100644 --- a/fittrackee/tests/workouts/test_records_model.py +++ b/fittrackee/tests/workouts/test_records_model.py @@ -14,26 +14,34 @@ class TestRecordModel: sport_1_cycling: Sport, workout_cycling_user_1: Workout, ) -> None: + record_type = 'LD' + record_ld = Record.query.filter_by( user_id=workout_cycling_user_1.user_id, sport_id=workout_cycling_user_1.sport_id, - record_type='LD', + record_type=record_type, ).first() - assert 'test' == record_ld.user.username - assert 1 == record_ld.sport_id - assert 1 == record_ld.workout_id - assert 'LD' == record_ld.record_type - assert '2018-01-01 00:00:00' == str(record_ld.workout_date) + + assert record_ld.user.username == user_1.username + assert record_ld.sport_id == sport_1_cycling.id + assert record_ld.workout_id == workout_cycling_user_1.sport_id + assert record_ld.record_type == record_type + assert str(record_ld.workout_date) == str( + workout_cycling_user_1.workout_date + ) + assert record_ld.value == workout_cycling_user_1.duration + assert '' == str(record_ld) record_serialize = record_ld.serialize() - assert 'id' in record_serialize - assert 'user' in record_serialize - assert 'sport_id' in record_serialize - assert 'workout_id' in record_serialize - assert 'record_type' in record_serialize - assert 'workout_date' in record_serialize - assert 'value' in record_serialize + + record_serialize['id'] = record_ld.id + record_serialize['record_type'] = record_ld.record_type + record_serialize['sport_id'] = record_ld.sport_id + record_serialize['user'] = record_ld.user.username + record_serialize['value'] = record_ld.value + record_serialize['workout_id'] = record_ld.workout_id + record_serialize['workout_date'] = record_ld.workout_date def test_record_model_with_none_value( self, @@ -48,12 +56,7 @@ class TestRecordModel: record_type='LD', ).first() record_ld.value = None - assert 'test' == record_ld.user.username - assert 1 == record_ld.sport_id - assert 1 == record_ld.workout_id - assert 'LD' == record_ld.record_type - assert '2018-01-01 00:00:00' == str(record_ld.workout_date) - assert '' == str(record_ld) + assert record_ld.value is None record_serialize = record_ld.serialize() @@ -80,7 +83,7 @@ class TestRecordModel: assert record_serialize.get('value') == 10.0 assert isinstance(record_serialize.get('value'), float) - def test_add_farest_distance_records( + def test_add_farthest_distance_records( self, app: Flask, user_1: User, diff --git a/fittrackee/tests/workouts/test_sports_api.py b/fittrackee/tests/workouts/test_sports_api.py index 2fdceb31..cf6e8a3a 100644 --- a/fittrackee/tests/workouts/test_sports_api.py +++ b/fittrackee/tests/workouts/test_sports_api.py @@ -7,41 +7,7 @@ from fittrackee.users.models import User, UserSportPreference from fittrackee.workouts.models import Sport, Workout from ..mixins import ApiTestCaseMixin - -expected_sport_1_cycling_result = { - 'id': 1, - 'label': 'Cycling', - 'is_active': True, - 'is_active_for_user': True, - 'color': None, - 'stopped_speed_threshold': 1, -} -expected_sport_1_cycling_admin_result = expected_sport_1_cycling_result.copy() -expected_sport_1_cycling_admin_result['has_workouts'] = False - -expected_sport_2_running_result = { - 'id': 2, - 'label': 'Running', - 'is_active': True, - 'is_active_for_user': True, - 'color': None, - 'stopped_speed_threshold': 0.1, -} -expected_sport_2_running_admin_result = expected_sport_2_running_result.copy() -expected_sport_2_running_admin_result['has_workouts'] = False - -expected_sport_1_cycling_inactive_result = { - 'id': 1, - 'label': 'Cycling', - 'is_active': False, - 'is_active_for_user': False, - 'color': None, - 'stopped_speed_threshold': 1, -} -expected_sport_1_cycling_inactive_admin_result = ( - expected_sport_1_cycling_inactive_result.copy() -) -expected_sport_1_cycling_inactive_admin_result['has_workouts'] = False +from ..utils import jsonify_dict class TestGetSports(ApiTestCaseMixin): @@ -75,8 +41,12 @@ class TestGetSports(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 2 - assert data['data']['sports'][0] == expected_sport_1_cycling_result - assert data['data']['sports'][1] == expected_sport_2_running_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling.serialize() + ) + assert data['data']['sports'][1] == jsonify_dict( + sport_2_running.serialize() + ) def test_it_gets_all_sports_with_inactive_one( self, @@ -98,11 +68,12 @@ class TestGetSports(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 2 - assert ( - data['data']['sports'][0] - == expected_sport_1_cycling_inactive_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling_inactive.serialize() + ) + assert data['data']['sports'][1] == jsonify_dict( + sport_2_running.serialize() ) - assert data['data']['sports'][1] == expected_sport_2_running_result def test_it_gets_all_sports_with_admin_rights( self, @@ -124,12 +95,11 @@ class TestGetSports(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 2 - assert ( - data['data']['sports'][0] - == expected_sport_1_cycling_inactive_admin_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling_inactive.serialize(is_admin=True) ) - assert ( - data['data']['sports'][1] == expected_sport_2_running_admin_result + assert data['data']['sports'][1] == jsonify_dict( + sport_2_running.serialize(is_admin=True) ) def test_it_gets_sports_with_auth_user_preferences( @@ -158,11 +128,14 @@ class TestGetSports(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 2 - assert data['data']['sports'][0]['color'] == '#000000' - assert data['data']['sports'][0]['stopped_speed_threshold'] == 0.5 - assert data['data']['sports'][0]['is_active_for_user'] is False - assert ( - data['data']['sports'][1] == expected_sport_2_running_admin_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling.serialize( + is_admin=True, + sport_preferences=user_admin_sport_1_preference.serialize(), + ) + ) + assert data['data']['sports'][1] == jsonify_dict( + sport_2_running.serialize(is_admin=True) ) @@ -183,7 +156,9 @@ class TestGetSport(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 1 - assert data['data']['sports'][0] == expected_sport_1_cycling_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling.serialize() + ) def test_it_gets_a_sport_with_preferences( self, @@ -205,7 +180,11 @@ class TestGetSport(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 1 - assert data['data']['sports'][0] == expected_sport_1_cycling_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling.serialize( + sport_preferences=user_sport_1_preference.serialize() + ) + ) def test_it_returns_404_if_sport_does_not_exist( self, app: Flask, user_1: User @@ -238,9 +217,8 @@ class TestGetSport(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 1 - assert ( - data['data']['sports'][0] - == expected_sport_1_cycling_inactive_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling_inactive.serialize() ) def test_it_get_an_inactive_sport_with_admin_rights( @@ -259,9 +237,8 @@ class TestGetSport(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['sports']) == 1 - assert ( - data['data']['sports'][0] - == expected_sport_1_cycling_inactive_admin_result + assert data['data']['sports'][0] == jsonify_dict( + sport_1_cycling_inactive.serialize(is_admin=True) ) @@ -388,7 +365,6 @@ class TestUpdateSport(ApiTestCaseMixin): assert len(data['data']['sports']) == 1 assert data['data']['sports'][0]['is_active'] is False assert data['data']['sports'][0]['is_active_for_user'] is False - assert data['data']['sports'][0]['is_active_for_user'] is False assert data['data']['sports'][0]['has_workouts'] is False def test_it_enables_a_sport_with_preferences( diff --git a/fittrackee/tests/workouts/test_sports_model.py b/fittrackee/tests/workouts/test_sports_model.py index 417f2959..67bf1a05 100644 --- a/fittrackee/tests/workouts/test_sports_model.py +++ b/fittrackee/tests/workouts/test_sports_model.py @@ -17,15 +17,17 @@ class TestSportModel: assert '' == str(sport) serialized_sport = sport.serialize(is_admin=is_admin) - assert 1 == serialized_sport['id'] - assert 'Cycling' == serialized_sport['label'] + assert serialized_sport['label'] == sport.label + assert serialized_sport['id'] == sport.id assert serialized_sport['is_active'] is True assert serialized_sport['is_active_for_user'] is True assert serialized_sport['color'] is None assert serialized_sport['stopped_speed_threshold'] == 1 return serialized_sport - def test_sport_model(self, app: Flask, sport_1_cycling: Sport) -> None: + def test_sport_model_without_workout( + self, app: Flask, sport_1_cycling: Sport + ) -> None: serialized_sport = self.assert_sport_model(sport_1_cycling) assert 'has_workouts' not in serialized_sport diff --git a/fittrackee/tests/workouts/test_workouts_api_0_get.py b/fittrackee/tests/workouts/test_workouts_api_0_get.py index 726e7784..beba7c44 100644 --- a/fittrackee/tests/workouts/test_workouts_api_0_get.py +++ b/fittrackee/tests/workouts/test_workouts_api_0_get.py @@ -1,4 +1,5 @@ import json +from typing import List from unittest.mock import patch from uuid import uuid4 @@ -8,6 +9,7 @@ from fittrackee.users.models import User from fittrackee.workouts.models import Sport, Workout from ..mixins import ApiTestCaseMixin +from ..utils import jsonify_dict from .utils import get_random_short_id @@ -45,25 +47,12 @@ class TestGetWorkouts(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 2 - assert 'creation_date' in data['data']['workouts'][0] - assert ( - 'Sun, 01 Apr 2018 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + workout_running_user_1.serialize() ) - assert 'test' == data['data']['workouts'][0]['user'] - assert 2 == data['data']['workouts'][0]['sport_id'] - assert 12.0 == data['data']['workouts'][0]['distance'] - assert '1:40:00' == data['data']['workouts'][0]['duration'] - - assert 'creation_date' in data['data']['workouts'][1] - assert ( - 'Mon, 01 Jan 2018 00:00:00 GMT' - == data['data']['workouts'][1]['workout_date'] + assert data['data']['workouts'][1] == jsonify_dict( + workout_cycling_user_1.serialize() ) - assert 'test' == data['data']['workouts'][1]['user'] - assert 1 == data['data']['workouts'][1]['sport_id'] - assert 10.0 == data['data']['workouts'][1]['distance'] - assert '1:00:00' == data['data']['workouts'][1]['duration'] assert data['pagination'] == { 'has_next': False, 'has_prev': False, @@ -119,7 +108,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -134,18 +123,22 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 5 - assert 'creation_date' in data['data']['workouts'][0] - assert ( - 'Wed, 09 May 2018 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + seven_workouts_user_1[6].serialize() ) - assert '0:50:00' == data['data']['workouts'][0]['duration'] - assert 'creation_date' in data['data']['workouts'][4] - assert ( - 'Mon, 01 Jan 2018 00:00:00 GMT' - == data['data']['workouts'][4]['workout_date'] + assert data['data']['workouts'][1] == jsonify_dict( + seven_workouts_user_1[5].serialize() ) - assert '0:17:04' == data['data']['workouts'][4]['duration'] + assert data['data']['workouts'][2] == jsonify_dict( + seven_workouts_user_1[3].serialize() + ) + assert data['data']['workouts'][3] == jsonify_dict( + seven_workouts_user_1[4].serialize() + ) + assert data['data']['workouts'][4] == jsonify_dict( + seven_workouts_user_1[2].serialize() + ) + assert data['pagination'] == { 'has_next': True, 'has_prev': False, @@ -159,7 +152,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -174,18 +167,21 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 5 - assert 'creation_date' in data['data']['workouts'][0] - assert ( - 'Wed, 09 May 2018 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + seven_workouts_user_1[6].serialize() ) - assert '0:50:00' == data['data']['workouts'][0]['duration'] - assert 'creation_date' in data['data']['workouts'][4] - assert ( - 'Mon, 01 Jan 2018 00:00:00 GMT' - == data['data']['workouts'][4]['workout_date'] + assert data['data']['workouts'][1] == jsonify_dict( + seven_workouts_user_1[5].serialize() + ) + assert data['data']['workouts'][2] == jsonify_dict( + seven_workouts_user_1[3].serialize() + ) + assert data['data']['workouts'][3] == jsonify_dict( + seven_workouts_user_1[4].serialize() + ) + assert data['data']['workouts'][4] == jsonify_dict( + seven_workouts_user_1[2].serialize() ) - assert '0:17:04' == data['data']['workouts'][4]['duration'] assert data['pagination'] == { 'has_next': True, 'has_prev': False, @@ -199,7 +195,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -214,18 +210,12 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 2 - assert 'creation_date' in data['data']['workouts'][0] - assert ( - 'Thu, 01 Jun 2017 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + seven_workouts_user_1[1].serialize() ) - assert '0:57:36' == data['data']['workouts'][0]['duration'] - assert 'creation_date' in data['data']['workouts'][1] - assert ( - 'Mon, 20 Mar 2017 00:00:00 GMT' - == data['data']['workouts'][1]['workout_date'] + assert data['data']['workouts'][1] == jsonify_dict( + seven_workouts_user_1[0].serialize() ) - assert '0:17:04' == data['data']['workouts'][1]['duration'] assert data['pagination'] == { 'has_next': False, 'has_prev': True, @@ -239,7 +229,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -267,7 +257,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -286,7 +276,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -301,13 +291,11 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 6 - assert ( - 'Wed, 09 May 2018 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + seven_workouts_user_1[6].serialize() ) - assert ( - 'Thu, 01 Jun 2017 00:00:00 GMT' - == data['data']['workouts'][5]['workout_date'] + assert data['data']['workouts'][5] == jsonify_dict( + seven_workouts_user_1[1].serialize() ) assert data['pagination'] == { 'has_next': True, @@ -323,7 +311,7 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -338,13 +326,14 @@ class TestGetWorkoutsWithPagination(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 3 - assert ( - 'Wed, 09 May 2018 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + seven_workouts_user_1[6].serialize() ) - assert ( - 'Fri, 23 Feb 2018 00:00:00 GMT' - == data['data']['workouts'][2]['workout_date'] + assert data['data']['workouts'][1] == jsonify_dict( + seven_workouts_user_1[5].serialize() + ) + assert data['data']['workouts'][2] == jsonify_dict( + seven_workouts_user_1[4].serialize() ) assert data['pagination'] == { 'has_next': True, @@ -361,7 +350,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -397,7 +386,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -433,7 +422,7 @@ class TestGetWorkoutsWithOrder(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -471,7 +460,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -507,7 +496,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -537,7 +526,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -567,7 +556,7 @@ class TestGetWorkoutsWithOrderBy(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -599,7 +588,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -625,7 +614,6 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): 'Fri, 23 Feb 2018 00:00:00 GMT' == data['data']['workouts'][1]['workout_date'] ) - assert '0:10:00' == data['data']['workouts'][1]['duration'] assert data['pagination'] == { 'has_next': False, 'has_prev': False, @@ -639,7 +627,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -667,7 +655,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -704,7 +692,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -740,7 +728,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -776,7 +764,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -808,7 +796,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -876,7 +864,7 @@ class TestGetWorkoutsWithFilters(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], sport_2_running: Sport, workout_running_user_1: Workout, ) -> None: @@ -912,7 +900,7 @@ class TestGetWorkoutsWithFiltersAndPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -948,7 +936,7 @@ class TestGetWorkoutsWithFiltersAndPagination(ApiTestCaseMixin): app: Flask, user_1: User, sport_1_cycling: Sport, - seven_workouts_user_1: Workout, + seven_workouts_user_1: List[Workout], ) -> None: client, auth_token = self.get_test_client_and_auth_token( app, user_1.email @@ -1001,15 +989,9 @@ class TestGetWorkout(ApiTestCaseMixin): assert response.status_code == 200 assert 'success' in data['status'] assert len(data['data']['workouts']) == 1 - assert 'creation_date' in data['data']['workouts'][0] - assert ( - 'Mon, 01 Jan 2018 00:00:00 GMT' - == data['data']['workouts'][0]['workout_date'] + assert data['data']['workouts'][0] == jsonify_dict( + workout_cycling_user_1.serialize() ) - assert 'test' == data['data']['workouts'][0]['user'] - assert 1 == data['data']['workouts'][0]['sport_id'] - assert 10.0 == data['data']['workouts'][0]['distance'] - assert '1:00:00' == data['data']['workouts'][0]['duration'] def test_it_returns_403_if_workout_belongs_to_a_different_user( self, diff --git a/fittrackee/tests/workouts/test_workouts_model.py b/fittrackee/tests/workouts/test_workouts_model.py index 6c7167af..13bc1132 100644 --- a/fittrackee/tests/workouts/test_workouts_model.py +++ b/fittrackee/tests/workouts/test_workouts_model.py @@ -1,15 +1,17 @@ -from uuid import UUID +from datetime import timedelta from flask import Flask from fittrackee import db from fittrackee.users.models import User from fittrackee.workouts.models import Sport, Workout -from fittrackee.workouts.utils.short_id import decode_short_id +from fittrackee.workouts.utils.short_id import encode_uuid + +from ..utils import random_string class TestWorkoutModel: - def test_workout_model( + def test_sport_label_and_date_are_in_string_value( self, app: Flask, sport_1_cycling: Sport, @@ -18,48 +20,109 @@ class TestWorkoutModel: ) -> None: workout_cycling_user_1.title = 'Test' db.session.commit() - - assert 1 == workout_cycling_user_1.id - assert workout_cycling_user_1.uuid is not None - assert 1 == workout_cycling_user_1.user_id - assert 1 == workout_cycling_user_1.sport_id - assert '2018-01-01 00:00:00' == str( - workout_cycling_user_1.workout_date - ) - assert 10.0 == float(workout_cycling_user_1.distance) - assert '1:00:00' == str(workout_cycling_user_1.duration) - assert 'Test' == workout_cycling_user_1.title assert '' == str( workout_cycling_user_1 ) - serialized_workout = workout_cycling_user_1.serialize() - assert isinstance(decode_short_id(serialized_workout['id']), UUID) - assert 'test' == serialized_workout['user'] - assert 1 == serialized_workout['sport_id'] - assert serialized_workout['title'] == 'Test' - assert 'creation_date' in serialized_workout - assert serialized_workout['modification_date'] is not None - assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00' - assert serialized_workout['duration'] == '1:00:00' - assert serialized_workout['pauses'] is None - assert serialized_workout['moving'] == '1:00:00' - assert serialized_workout['distance'] == 10.0 - assert serialized_workout['max_alt'] is None - assert serialized_workout['descent'] is None + def test_short_id_returns_encoded_workout_uuid( + self, + app: Flask, + sport_1_cycling: Sport, + user_1: User, + workout_cycling_user_1: Workout, + ) -> None: + assert workout_cycling_user_1.short_id == encode_uuid( + workout_cycling_user_1.uuid + ) + + def test_serialize_for_workout_without_gpx( + self, + app: Flask, + sport_1_cycling: Sport, + user_1: User, + workout_cycling_user_1: Workout, + ) -> None: + workout = workout_cycling_user_1 + + serialized_workout = workout.serialize() assert serialized_workout['ascent'] is None - assert serialized_workout['max_speed'] == 10.0 - assert serialized_workout['ave_speed'] == 10.0 - assert serialized_workout['with_gpx'] is False + assert serialized_workout['ave_speed'] == float(workout.ave_speed) assert serialized_workout['bounds'] == [] - assert serialized_workout['previous_workout'] is None - assert serialized_workout['next_workout'] is None - assert serialized_workout['segments'] == [] - assert serialized_workout['records'] != [] + assert 'creation_date' in serialized_workout + assert serialized_workout['descent'] is None + assert serialized_workout['distance'] == float(workout.distance) + assert serialized_workout['duration'] == str(workout.duration) + assert serialized_workout['id'] == workout.short_id assert serialized_workout['map'] is None - assert serialized_workout['weather_start'] is None - assert serialized_workout['weather_end'] is None + assert serialized_workout['max_alt'] is None + assert serialized_workout['max_speed'] == float(workout.max_speed) + assert serialized_workout['min_alt'] is None + assert serialized_workout['modification_date'] is None + assert serialized_workout['moving'] == str(workout.moving) + assert serialized_workout['next_workout'] is None assert serialized_workout['notes'] is None + assert serialized_workout['pauses'] is None + assert serialized_workout['previous_workout'] is None + assert serialized_workout['records'] == [ + record.serialize() for record in workout.records + ] + assert serialized_workout['segments'] == [] + assert serialized_workout['sport_id'] == workout.sport_id + assert serialized_workout['title'] == workout.title + assert serialized_workout['user'] == workout.user.username + assert serialized_workout['weather_end'] is None + assert serialized_workout['weather_start'] is None + assert serialized_workout['with_gpx'] is False + assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00' + + def test_serialize_for_workout_with_gpx( + self, + app: Flask, + sport_1_cycling: Sport, + user_1: User, + workout_cycling_user_1: Workout, + workout_cycling_user_1_segment: Workout, + ) -> None: + workout = workout_cycling_user_1 + workout.bounds = [1, 2, 3, 4] + workout.gpx = random_string() + workout.map = random_string() + workout.pauses = timedelta(minutes=15) + + serialized_workout = workout.serialize() + assert serialized_workout['ascent'] is None + assert serialized_workout['ave_speed'] == float(workout.ave_speed) + assert serialized_workout['bounds'] == [ + float(bound) for bound in workout.bounds + ] + assert 'creation_date' in serialized_workout + assert serialized_workout['descent'] is None + assert serialized_workout['distance'] == float(workout.distance) + assert serialized_workout['duration'] == str(workout.duration) + assert serialized_workout['id'] == workout.short_id + assert serialized_workout['map'] is None + assert serialized_workout['max_alt'] is None + assert serialized_workout['max_speed'] == float(workout.max_speed) + assert serialized_workout['min_alt'] is None + assert serialized_workout['modification_date'] is not None + assert serialized_workout['moving'] == str(workout.moving) + assert serialized_workout['next_workout'] is None + assert serialized_workout['notes'] is None + assert serialized_workout['pauses'] == str(workout.pauses) + assert serialized_workout['previous_workout'] is None + assert serialized_workout['records'] == [ + record.serialize() for record in workout.records + ] + assert serialized_workout['segments'] == [ + segment.serialize() for segment in workout.segments + ] + assert serialized_workout['sport_id'] == workout.sport_id + assert serialized_workout['title'] == workout.title + assert serialized_workout['user'] == workout.user.username + assert serialized_workout['weather_end'] is None + assert serialized_workout['weather_start'] is None + assert serialized_workout['with_gpx'] is True + assert str(serialized_workout['workout_date']) == '2018-01-01 00:00:00' def test_workout_segment_model( self, @@ -74,3 +137,35 @@ class TestWorkoutModel: f'for workout \'{workout_cycling_user_1.short_id}\'>' == str(workout_cycling_user_1_segment) ) + + def test_it_returns_previous_workout( + self, + app: Flask, + sport_1_cycling: Sport, + sport_2_running: Sport, + user_1: User, + workout_cycling_user_1: Workout, + workout_running_user_1: Workout, + ) -> None: + serialized_workout = workout_running_user_1.serialize() + + assert ( + serialized_workout['previous_workout'] + == workout_cycling_user_1.short_id + ) + + def test_it_returns_next_workout( + self, + app: Flask, + sport_1_cycling: Sport, + sport_2_running: Sport, + user_1: User, + workout_cycling_user_1: Workout, + workout_running_user_1: Workout, + ) -> None: + serialized_workout = workout_cycling_user_1.serialize() + + assert ( + serialized_workout['next_workout'] + == workout_running_user_1.short_id + ) diff --git a/fittrackee/users/auth.py b/fittrackee/users/auth.py index 1c315e40..df8bb69d 100644 --- a/fittrackee/users/auth.py +++ b/fittrackee/users/auth.py @@ -791,8 +791,9 @@ def edit_user_preferences(auth_user: User) -> Union[Dict, HttpResponse]: } :