source: OpenWorkouts-current/ow/tests/views/test_user.py @ 55470f9

currentfeature/docs
Last change on this file since 55470f9 was 55470f9, checked in by Borja Lopez <borja@…>, 5 years ago

Fixed some tests broken during the last code changes.
Fixed a bug in the calculations of the totals for the profile page
(we weren't taking in account possible None values for distance,
duration and specially elevation/uphill)

  • Property mode set to 100644
File size: 28.8 KB
Line 
1import os
2import json
3from decimal import Decimal
4from datetime import datetime, timedelta, timezone
5from shutil import copyfileobj
6from unittest.mock import Mock, patch
7
8import pytest
9
10from ZODB.blob import Blob
11
12from pyramid.testing import DummyRequest
13from pyramid.httpexceptions import HTTPFound
14from pyramid.response import Response
15
16from webob.multidict import MultiDict
17
18from ow.models.root import OpenWorkouts
19from ow.models.user import User
20from ow.models.workout import Workout
21from ow.views.renderers import OWFormRenderer
22import ow.views.user as user_views
23
24
25class TestUserViews(object):
26
27    @pytest.fixture
28    def john(self):
29        user = User(firstname='John', lastname='Doe',
30                    email='john.doe@example.net')
31        user.password = 's3cr3t'
32        return user
33
34    @pytest.fixture
35    def root(self, john):
36        root = OpenWorkouts()
37        root.add_user(john)
38        workout = Workout(
39            start=datetime(2015, 6, 28, 12, 55, tzinfo=timezone.utc),
40            duration=timedelta(minutes=60),
41            distance=30
42        )
43        john.add_workout(workout)
44        return root
45
46    @pytest.fixture
47    def dummy_request(self, root):
48        request = DummyRequest()
49        request.root = root
50        return request
51
52    @pytest.fixture
53    def profile_post_request(self, root, john):
54        """
55        This is a valid POST request to update an user profile.
56        Form will validate, but nothing will be really updated/changed.
57        """
58        user = john
59        request = DummyRequest()
60        request.root = root
61        request.method = 'POST'
62        request.POST = MultiDict({
63            'submit': True,
64            'firstname': user.firstname,
65            'lastname': user.lastname,
66            'email': user.email,
67            'bio': user.bio,
68            'weight': user.weight,
69            'height': user.height,
70            'gender': user.gender,
71            'birth_date': user.birth_date,
72            'picture': user.picture,
73            })
74        return request
75
76    @pytest.fixture
77    def passwd_post_request(self, root):
78        """
79        This is a valid POST request to change the user password, but
80        the form will not validate (empty fields)
81        """
82        request = DummyRequest()
83        request.root = root
84        request.method = 'POST'
85        request.POST = MultiDict({
86            'submit': True,
87            'old_password': '',
88            'password': '',
89            'password_confirm': ''
90            })
91        return request
92
93    @pytest.fixture
94    def signup_post_request(self, root):
95        """
96        This is a valid POST request to signup a new user.
97        """
98        request = DummyRequest()
99        request.root = root
100        request.method = 'POST'
101        request.POST = MultiDict({
102            'submit': True,
103            'nickname': 'JackBlack',
104            'email': 'jack.black@example.net',
105            'firstname': 'Jack',
106            'lastname': 'Black',
107            'password': 'j4ck s3cr3t',
108            'password_confirm': 'j4ck s3cr3t'
109            })
110        return request
111
112    def test_dashboard_redirect_unauthenticated(self, root):
113        """
114        Anoymous access to the root object, send the user to the login page.
115
116        Instead of reusing the DummyRequest from the request fixture, we do
117        Mock fully the request here, because we need to use
118        authenticated_userid, which cannot be easily set in the DummyRequest
119        """
120        request = DummyRequest()
121        request.root = root
122        response = user_views.dashboard_redirect(root, request)
123        assert isinstance(response, HTTPFound)
124        assert response.location == request.resource_url(root, 'login')
125
126    def test_dashboard_redirect_authenticated(self, root, john):
127        """
128        Authenticated user accesing the root object, send the user to her
129        dashboard
130
131        Instead of reusing the DummyRequest from the request fixture, we do
132        Mock fully the request here, because we need to use
133        authenticated_userid, which cannot be easily set in the DummyRequest
134        """
135        alt_request = DummyRequest()
136        request = Mock()
137        request.root = root
138        request.authenticated_userid = str(john.uid)
139        request.resource_url = alt_request.resource_url
140        response = user_views.dashboard_redirect(root, request)
141        assert isinstance(response, HTTPFound)
142        assert response.location == request.resource_url(john)
143        # if authenticated_userid is the id of an user that does not exist
144        # anymore, we send the user to the logout page
145        request.authenticated_userid = 'faked-uid'
146        response = user_views.dashboard_redirect(root, request)
147        assert isinstance(response, HTTPFound)
148        assert response.location == request.resource_url(root, 'logout')
149
150    def test_dashboard(self, dummy_request, john):
151        """
152        Renders the user dashboard
153        """
154        request = dummy_request
155        response = user_views.dashboard(john, request)
156        assert len(response) == 6
157        assert 'month_name' in response.keys()
158        assert response['current_year'] == datetime.now().year
159        assert response['current_day_name'] == datetime.now().strftime('%a')
160        # this user has a single workout, in 2015
161        assert response['viewing_year'] == 2015
162        assert response['viewing_month'] == 6
163        assert response['workouts'] == [w for w in john.workouts()]
164
165    def test_dashboard_year(self, dummy_request, john):
166        """
167        Renders the user dashboard for a chosen year.
168        """
169        request = dummy_request
170        # first test the year for which we know there is a workout
171        request.GET['year'] = 2015
172        response = user_views.dashboard(john, request)
173        assert len(response) == 6
174        assert 'month_name' in response.keys()
175        assert response['current_year'] == datetime.now().year
176        assert response['current_day_name'] == datetime.now().strftime('%a')
177        # this user has a single workout, in 2015
178        assert response['viewing_year'] == 2015
179        assert response['viewing_month'] == 6
180        assert response['workouts'] == [w for w in john.workouts()]
181        # now, a year we know there is no workout info
182        request.GET['year'] = 2000
183        response = user_views.dashboard(john, request)
184        assert len(response) == 6
185        assert 'month_name' in response.keys()
186        assert response['current_year'] == datetime.now().year
187        assert response['current_day_name'] == datetime.now().strftime('%a')
188        # this user has a single workout, in 2015
189        assert response['viewing_year'] == 2000
190        # we have no data for that year and we didn't ask for a certain month,
191        # so the passing value for that is None
192        assert response['viewing_month'] is None
193        assert response['workouts'] == []
194
195    def test_dashboard_year_month(self, dummy_request, john):
196        """
197        Renders the user dashboard for a chosen year and month.
198        """
199        request = dummy_request
200        # first test the year/month for which we know there is a workout
201        request.GET['year'] = 2015
202        request.GET['month'] = 6
203        response = user_views.dashboard(john, request)
204        assert len(response) == 6
205        assert 'month_name' in response.keys()
206        assert response['current_year'] == datetime.now().year
207        assert response['current_day_name'] == datetime.now().strftime('%a')
208        # this user has a single workout, in 2015
209        assert response['viewing_year'] == 2015
210        assert response['viewing_month'] == 6
211        assert response['workouts'] == [w for w in john.workouts()]
212        # now, change month to one without values
213        request.GET['month'] = 2
214        response = user_views.dashboard(john, request)
215        assert len(response) == 6
216        assert 'month_name' in response.keys()
217        assert response['current_year'] == datetime.now().year
218        assert response['current_day_name'] == datetime.now().strftime('%a')
219        # this user has a single workout, in 2015
220        assert response['viewing_year'] == 2015
221        assert response['viewing_month'] == 2
222        assert response['workouts'] == []
223        # now the month with data, but in a different year
224        request.GET['year'] = 2010
225        request.GET['month'] = 6
226        response = user_views.dashboard(john, request)
227        assert len(response) == 6
228        assert 'month_name' in response.keys()
229        assert response['current_year'] == datetime.now().year
230        assert response['current_day_name'] == datetime.now().strftime('%a')
231        # this user has a single workout, in 2015
232        assert response['viewing_year'] == 2010
233        assert response['viewing_month'] == 6
234        assert response['workouts'] == []
235
236    def test_dashboard_month(self, dummy_request, john):
237        """
238        Passing a month without a year when rendering the dashboard. The last
239        year for which workout data is available is assumed
240        """
241        request = dummy_request
242        # Set a month without workout data
243        request.GET['month'] = 5
244        response = user_views.dashboard(john, request)
245        assert len(response) == 6
246        assert 'month_name' in response.keys()
247        assert response['current_year'] == datetime.now().year
248        assert response['current_day_name'] == datetime.now().strftime('%a')
249        # this user has a single workout, in 2015
250        assert response['viewing_year'] == 2015
251        assert response['viewing_month'] == 5
252        assert response['workouts'] == []
253        # now a month with data
254        request.GET['month'] = 6
255        response = user_views.dashboard(john, request)
256        assert len(response) == 6
257        assert 'month_name' in response.keys()
258        assert response['current_year'] == datetime.now().year
259        assert response['current_day_name'] == datetime.now().strftime('%a')
260        # this user has a single workout, in 2015
261        assert response['viewing_year'] == 2015
262        assert response['viewing_month'] == 6
263        assert response['workouts'] == [w for w in john.workouts()]
264
265    def test_profile(self, dummy_request, john):
266        """
267        Renders the user profile page
268        """
269        request = dummy_request
270        # profile page for the current day (no workouts avalable)
271        response = user_views.profile(john, request)
272        assert len(response.keys()) == 4
273        current_month = datetime.now(timezone.utc).strftime('%Y-%m')
274        assert response['current_month'] == current_month
275        assert response['current_week'] is None
276        assert response['workouts'] == []
277        assert response['totals'] == {
278            'distance': Decimal(0),
279            'time': timedelta(0),
280            'elevation': Decimal(0)
281        }
282        # profile page for a previous date, that has workouts
283        request.GET['year'] = 2015
284        request.GET['month'] = 6
285        response = user_views.profile(john, request)
286        assert len(response.keys()) == 4
287        assert response['current_month'] == '2015-06'
288        assert response['current_week'] is None
289        workouts = john.workouts(2015, 6)
290        assert response['workouts'] == workouts
291        assert response['totals'] == {
292            'distance': workouts[0].distance,
293            'time': workouts[0].duration,
294            'elevation': Decimal(0)
295        }
296        # same, passing a week, first on a week without workouts
297        request.GET['year'] = 2015
298        request.GET['month'] = 6
299        request.GET['week'] = 25
300        response = user_views.profile(john, request)
301        assert len(response.keys()) == 4
302        assert response['current_month'] == '2015-06'
303        assert response['current_week'] == 25
304        assert response['workouts'] == []
305        assert response['totals'] == {
306            'distance': Decimal(0),
307            'time': timedelta(0),
308            'elevation': Decimal(0)
309        }
310        # now in a week with workouts
311        request.GET['year'] = 2015
312        request.GET['month'] = 6
313        request.GET['week'] = 26
314        response = user_views.profile(john, request)
315        assert len(response.keys()) == 4
316        assert response['current_month'] == '2015-06'
317        assert response['current_week'] == 26
318        workouts = john.workouts(2015, 6)
319        assert response['workouts'] == workouts
320        assert response['totals'] == {
321            'distance': workouts[0].distance,
322            'time': workouts[0].duration,
323            'elevation': Decimal(0)
324        }
325
326    def test_login_get(self, dummy_request):
327        """
328        GET request to access the login page
329        """
330        request = dummy_request
331        response = user_views.login(request.root, request)
332        assert response['message'] == ''
333        assert response['email'] == ''
334        assert response['password'] == ''
335        assert response['redirect_url'] == request.resource_url(request.root)
336
337    def test_login_get_return_to(self, dummy_request, john):
338        """
339        GET request to access the login page, if there is a page set to where
340        the user should be sent to, the response "redirect_url" key will have
341        such url
342        """
343        request = dummy_request
344        workout = john.workouts()[0]
345        workout_url = request.resource_url(workout)
346        request.params['return_to'] = workout_url
347        response = user_views.login(request.root, request)
348        assert response['redirect_url'] == workout_url
349
350    def test_login_post_wrong_email(self, dummy_request):
351        request = dummy_request
352        request.method = 'POST'
353        request.POST['submit'] = True
354        request.POST['email'] = 'jack@example.net'
355        response = user_views.login(request.root, request)
356        assert response['message'] == u'Wrong email address'
357
358    def test_login_post_wrong_password(self, dummy_request):
359        request = dummy_request
360        request.method = 'POST'
361        request.POST['submit'] = True
362        request.POST['email'] = 'john.doe@example.net'
363        request.POST['password'] = 'badpassword'
364        response = user_views.login(request.root, request)
365        assert response['message'] == u'Wrong password'
366
367    @patch('ow.views.user.remember')
368    def test_login_post_ok(self, rem, dummy_request, john):
369        request = dummy_request
370        request.method = 'POST'
371        request.POST['submit'] = True
372        request.POST['email'] = 'john.doe@example.net'
373        request.POST['password'] = 's3cr3t'
374        response = user_views.login(request.root, request)
375        assert isinstance(response, HTTPFound)
376        assert rem.called
377        assert response.location == request.resource_url(john)
378
379    @patch('ow.views.user.forget')
380    def test_logout(self, forg, dummy_request):
381        request = dummy_request
382        response = user_views.logout(request.root, request)
383        assert isinstance(response, HTTPFound)
384        assert forg.called
385        assert response.location == request.resource_url(request.root)
386
387    extensions = ('png', 'jpg', 'jpeg', 'gif')
388
389    @pytest.mark.parametrize('extension', extensions)
390    def test_profile_picture(self, extension, dummy_request, john):
391        """
392        GET request to get the profile picture of an user.
393        """
394        request = dummy_request
395        # Get the user
396        user = john
397        # Get the path to the image, then open it and copy it to a new Blob
398        # object
399        path = 'fixtures/image.' + extension
400        image_path = os.path.join(
401            os.path.dirname(os.path.dirname(__file__)), path)
402        blob = Blob()
403        with open(image_path, 'rb') as infile, blob.open('w') as out:
404            infile.seek(0)
405            copyfileobj(infile, out)
406
407        # Set the blob with the picture
408        user.picture = blob
409
410        # Call the profile_picture view
411        response = user_views.profile_picture(user, request)
412        assert isinstance(response, Response)
413        assert response.status_int == 200
414        assert response.content_type == 'image'
415
416    def test_edit_profile_get(self, dummy_request, john):
417        """
418        GET request to the edit profile page, returns the form ready to
419        be rendered
420        """
421        request = dummy_request
422        user = john
423        response = user_views.edit_profile(user, request)
424        assert isinstance(response['form'], OWFormRenderer)
425        # no errors in the form (first load)
426        assert response['form'].errorlist() == ''
427        # the form carries along the proper data keys, taken from the
428        # loaded user profile
429        data = ['firstname', 'lastname', 'email', 'nickname', 'bio',
430                'birth_date', 'height', 'weight', 'gender', 'timezone']
431        assert list(response['form'].data.keys()) == data
432        # and check the email to see data is properly loaded
433        assert response['form'].data['email'] == 'john.doe@example.net'
434
435    def test_edit_profile_post_ok(self, profile_post_request, john):
436        request = profile_post_request
437        user = john
438        # Update the bio field
439        bio = 'Some text about this user'
440        request.POST['bio'] = bio
441        response = user_views.edit_profile(user, request)
442        assert isinstance(response, HTTPFound)
443        assert response.location == request.resource_url(user, 'profile')
444        assert user.bio == bio
445
446    def test_edit_profile_post_missing_required(
447            self, profile_post_request, john):
448        request = profile_post_request
449        request.POST['email'] = ''
450        user = john
451        response = user_views.edit_profile(user, request)
452        assert isinstance(response['form'], OWFormRenderer)
453        # error on the missing email field
454        error = u'Please enter an email address'
455        html_error = u'<ul class="error"><li>' + error + '</li></ul>'
456        assert response['form'].errorlist() == html_error
457        assert response['form'].errors_for('email') == [error]
458
459    def test_edit_profile_post_ok_picture_empty_bytes(
460            self, profile_post_request, john):
461        """
462        POST request with an empty picture, the content of
463        request['POST'].picture is a empty bytes string (b'') which triggers
464        a bug in formencode, we put a fix in place, test that
465        (more in ow.user.views.edit_profile)
466        """
467        # for the purposes of this test, we can mock the picture
468        picture = Mock()
469        john.picture = picture
470        request = profile_post_request
471        user = john
472        # Mimic what happens when a picture is not provided by the user
473        request.POST['picture'] = b''
474        response = user_views.edit_profile(user, request)
475        assert isinstance(response, HTTPFound)
476        assert response.location == request.resource_url(user, 'profile')
477        assert user.picture == picture
478
479    def test_edit_profile_post_ok_missing_picture(
480            self, profile_post_request, john):
481        """
482        POST request without picture
483        """
484        # for the purposes of this test, we can mock the picture
485        picture = Mock()
486        john.picture = picture
487        request = profile_post_request
488        user = john
489        # No pic is provided in the request POST values
490        del request.POST['picture']
491        response = user_views.edit_profile(user, request)
492        assert isinstance(response, HTTPFound)
493        assert response.location == request.resource_url(user, 'profile')
494        assert user.picture == picture
495
496    def test_edit_profile_post_ok_nickname(self, profile_post_request, john):
497        """
498        User with a nickname set saves profile without changing the profile,
499        we have to be sure there are no "nickname already in use" errors
500        """
501        request = profile_post_request
502        user = john
503        user.nickname = 'mr_jones'
504        # add the nickname, the default post request has not a nickname set
505        request.POST['nickname'] = 'mr_jones'
506        response = user_views.edit_profile(user, request)
507        assert isinstance(response, HTTPFound)
508        assert response.location == request.resource_url(user, 'profile')
509
510    def test_change_password_get(self, dummy_request, john):
511        request = dummy_request
512        user = john
513        response = user_views.change_password(user, request)
514        assert isinstance(response['form'], OWFormRenderer)
515        # no errors in the form (first load)
516        assert response['form'].errorlist() == ''
517
518    def test_change_password_post_ok(self, passwd_post_request, john):
519        request = passwd_post_request
520        user = john
521        request.POST['old_password'] = 's3cr3t'
522        request.POST['password'] = 'h1dd3n s3cr3t'
523        request.POST['password_confirm'] = 'h1dd3n s3cr3t'
524        response = user_views.change_password(user, request)
525        assert isinstance(response, HTTPFound)
526        assert response.location == request.resource_url(user, 'profile')
527        # password was changed
528        assert not user.check_password('s3cr3t')
529        assert user.check_password('h1dd3n s3cr3t')
530
531    def test_change_password_post_no_values(self, passwd_post_request, john):
532        request = passwd_post_request
533        user = john
534        response = user_views.change_password(user, request)
535        assert isinstance(response['form'], OWFormRenderer)
536        error = u'Please enter a value'
537        html_error = u'<ul class="error">'
538        html_error += ('<li>' + error + '</li>') * 3  # 3 fields
539        html_error += '</ul>'
540        errorlist = response['form'].errorlist().replace('\n', '')
541        assert errorlist == html_error
542        assert response['form'].errors_for('old_password') == [error]
543        assert response['form'].errors_for('password') == [error]
544        assert response['form'].errors_for('password_confirm') == [error]
545        # password was not changed
546        assert user.check_password('s3cr3t')
547
548    def test_change_password_post_bad_old_password(
549            self, passwd_post_request, john):
550        request = passwd_post_request
551        user = john
552        request.POST['old_password'] = 'FAIL PASSWORD'
553        request.POST['password'] = 'h1dd3n s3cr3t'
554        request.POST['password_confirm'] = 'h1dd3n s3cr3t'
555        response = user_views.change_password(user, request)
556        assert isinstance(response['form'], OWFormRenderer)
557        error = u'The given password does not match the existing one '
558        html_error = u'<ul class="error"><li>' + error + '</li></ul>'
559        assert response['form'].errorlist() == html_error
560        assert response['form'].errors_for('old_password') == [error]
561        # password was not changed
562        assert user.check_password('s3cr3t')
563        assert not user.check_password('h1dd3n s3cr3t')
564
565    def test_change_password_post_password_mismatch(
566            self, passwd_post_request, john):
567        request = passwd_post_request
568        user = john
569        request.POST['old_password'] = 's3cr3t'
570        request.POST['password'] = 'h1dd3n s3cr3ts'
571        request.POST['password_confirm'] = 'h1dd3n s3cr3t'
572        response = user_views.change_password(user, request)
573        assert isinstance(response['form'], OWFormRenderer)
574        error = u'Fields do not match'
575        html_error = u'<ul class="error"><li>' + error + '</li></ul>'
576        assert response['form'].errorlist() == html_error
577        assert response['form'].errors_for('password_confirm') == [error]
578        # password was not changed
579        assert user.check_password('s3cr3t')
580        assert not user.check_password('h1dd3n s3cr3t')
581
582    def test_signup_get(self, dummy_request):
583        request = dummy_request
584        response = user_views.signup(request.root, request)
585        assert isinstance(response['form'], OWFormRenderer)
586        # no errors in the form (first load)
587        assert response['form'].errorlist() == ''
588
589    def test_signup_post_ok(self, signup_post_request):
590        request = signup_post_request
591        assert 'jack.black@example.net' not in request.root.emails
592        assert 'JackBlack' not in request.root.all_nicknames
593        response = user_views.signup(request.root, request)
594        assert isinstance(response, HTTPFound)
595        assert response.location == request.resource_url(request.root)
596        assert 'jack.black@example.net' in request.root.emails
597        assert 'JackBlack' in request.root.all_nicknames
598
599    def test_signup_missing_required(self, signup_post_request):
600        request = signup_post_request
601        request.POST['email'] = ''
602        assert 'jack.black@example.net' not in request.root.emails
603        assert 'JackBlack' not in request.root.all_nicknames
604        response = user_views.signup(request.root, request)
605        assert isinstance(response['form'], OWFormRenderer)
606        error = u'Please enter an email address'
607        html_error = '<ul class="error">'
608        html_error += '<li>' + error + '</li>'
609        html_error += '</ul>'
610        errorlist = response['form'].errorlist().replace('\n', '')
611        assert errorlist == html_error
612        assert response['form'].errors_for('email') == [error]
613        assert 'jack.black@example.net' not in request.root.emails
614        assert 'JackBlack' not in request.root.all_nicknames
615
616    def test_signup_existing_nickname(self, signup_post_request, john):
617        request = signup_post_request
618        # assign john a nickname first
619        john.nickname = 'john'
620        # now set it for the POST request
621        request.POST['nickname'] = 'john'
622        # check jack is not there yet
623        assert 'jack.black@example.net' not in request.root.emails
624        assert 'JackBlack' not in request.root.all_nicknames
625        # now signup as jack, but trying to set the nickname 'john'
626        response = user_views.signup(request.root, request)
627        assert isinstance(response['form'], OWFormRenderer)
628        error = u'Another user is already using the nickname john'
629        html_error = '<ul class="error">'
630        html_error += '<li>' + error + '</li>'
631        html_error += '</ul>'
632        errorlist = response['form'].errorlist().replace('\n', '')
633        assert errorlist == html_error
634        assert response['form'].errors_for('nickname') == [error]
635        # all the errors, and jack is not there
636        assert 'jack.black@example.net' not in request.root.emails
637        assert 'JackBlack' not in request.root.all_nicknames
638
639    def test_signup_existing_email(self, signup_post_request):
640        request = signup_post_request
641        request.POST['email'] = 'john.doe@example.net'
642        assert 'jack.black@example.net' not in request.root.emails
643        assert 'JackBlack' not in request.root.all_nicknames
644        response = user_views.signup(request.root, request)
645        assert isinstance(response['form'], OWFormRenderer)
646        error = u'Another user is already registered with the email '
647        error += u'john.doe@example.net'
648        html_error = '<ul class="error">'
649        html_error += '<li>' + error + '</li>'
650        html_error += '</ul>'
651        errorlist = response['form'].errorlist().replace('\n', '')
652        assert errorlist == html_error
653        assert response['form'].errors_for('email') == [error]
654        assert 'jack.black@example.net' not in request.root.emails
655        assert 'JackBlack' not in request.root.all_nicknames
656
657    def test_week_stats_no_stats(self, dummy_request, john):
658        response = user_views.week_stats(john, dummy_request)
659        assert isinstance(response, Response)
660        assert response.content_type == 'application/json'
661        # the body is a valid json-encoded stream
662        obj = json.loads(response.body)
663        assert obj == [
664            {'distance': 0, 'elevation': 0, 'name': 'Mon',
665             'time': '00', 'workouts': 0},
666            {'distance': 0, 'elevation': 0, 'name': 'Tue',
667             'time': '00', 'workouts': 0},
668            {'distance': 0, 'elevation': 0, 'name': 'Wed',
669             'time': '00', 'workouts': 0},
670            {'distance': 0, 'elevation': 0, 'name': 'Thu',
671             'time': '00', 'workouts': 0},
672            {'distance': 0, 'elevation': 0, 'name': 'Fri',
673             'time': '00', 'workouts': 0},
674            {'distance': 0, 'elevation': 0, 'name': 'Sat',
675             'time': '00', 'workouts': 0},
676            {'distance': 0, 'elevation': 0, 'name': 'Sun',
677             'time': '00', 'workouts': 0}
678        ]
679
680    def test_week_stats(self, dummy_request, john):
681        workout = Workout(
682            start=datetime.now(timezone.utc),
683            duration=timedelta(minutes=60),
684            distance=30,
685            elevation=540
686        )
687        john.add_workout(workout)
688        response = user_views.week_stats(john, dummy_request)
689        assert isinstance(response, Response)
690        assert response.content_type == 'application/json'
691        # the body is a valid json-encoded stream
692        obj = json.loads(response.body)
693        assert len(obj) == 7
694        for day in obj:
695            if datetime.now(timezone.utc).strftime('%a') == day['name']:
696                day['distance'] == 30
697                day['elevation'] == 540
698                day['time'] == '01'
699                day['workouts'] == 1
700            else:
701                day['distance'] == 0
702                day['elevation'] == 0
703                day['time'] == '00'
704                day['workouts'] == 0
Note: See TracBrowser for help on using the repository browser.