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

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

(#58) Set a title automatically when adding manually a workout without
providing one.

The title is generated based on the only required data we have (starting
date and time) + sport (if provided).

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