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

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

(#7) Allow users profiles to be accessed using a more friendly url:

https://openworkouts.org/profile/NICKNAME

IMPORTANT: This change adds a new index to the catalog, so ensure you
update any existing databases after pulling.

Enter pshell and run this code:

root._update_indexes()
for user in root.users:

root.reindex(user)

  • Property mode set to 100644
File size: 28.9 KB
RevLine 
[5ec3a0b]1import os
[421f05f]2import json
[55470f9]3from decimal import Decimal
[5ec3a0b]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
[1d92bf2]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):
[5ec3a0b]36        root = OpenWorkouts()
[1d92bf2]37        root.add_user(john)
[5ec3a0b]38        workout = Workout(
39            start=datetime(2015, 6, 28, 12, 55, tzinfo=timezone.utc),
40            duration=timedelta(minutes=60),
41            distance=30
42        )
[1d92bf2]43        john.add_workout(workout)
[5ec3a0b]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
[1d92bf2]53    def profile_post_request(self, root, john):
[5ec3a0b]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        """
[1d92bf2]58        user = john
[5ec3a0b]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,
[1d92bf2]103            'nickname': 'JackBlack',
[5ec3a0b]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
[fe6089a]126    def test_dashboard_redirect_authenticated(self, root, john):
[5ec3a0b]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        """
[fe6089a]135        alt_request = DummyRequest()
[5ec3a0b]136        request = Mock()
137        request.root = root
[fe6089a]138        request.authenticated_userid = str(john.uid)
139        request.resource_url = alt_request.resource_url
[5ec3a0b]140        response = user_views.dashboard_redirect(root, request)
141        assert isinstance(response, HTTPFound)
[fe6089a]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')
[5ec3a0b]149
[1d92bf2]150    def test_dashboard(self, dummy_request, john):
[5ec3a0b]151        """
152        Renders the user dashboard
153        """
154        request = dummy_request
[1d92bf2]155        response = user_views.dashboard(john, request)
[5bdfbfb]156        assert len(response) == 6
[2d91474]157        assert 'month_name' in response.keys()
[5bdfbfb]158        assert response['current_year'] == datetime.now().year
159        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]173        assert len(response) == 6
[2d91474]174        assert 'month_name' in response.keys()
[5bdfbfb]175        assert response['current_year'] == datetime.now().year
176        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]184        assert len(response) == 6
[2d91474]185        assert 'month_name' in response.keys()
[5bdfbfb]186        assert response['current_year'] == datetime.now().year
187        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]204        assert len(response) == 6
[2d91474]205        assert 'month_name' in response.keys()
[5bdfbfb]206        assert response['current_year'] == datetime.now().year
207        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]215        assert len(response) == 6
[2d91474]216        assert 'month_name' in response.keys()
[5bdfbfb]217        assert response['current_year'] == datetime.now().year
218        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]227        assert len(response) == 6
[2d91474]228        assert 'month_name' in response.keys()
[5bdfbfb]229        assert response['current_year'] == datetime.now().year
230        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]245        assert len(response) == 6
[2d91474]246        assert 'month_name' in response.keys()
[5bdfbfb]247        assert response['current_year'] == datetime.now().year
248        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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)
[5bdfbfb]256        assert len(response) == 6
[2d91474]257        assert 'month_name' in response.keys()
[5bdfbfb]258        assert response['current_year'] == datetime.now().year
259        assert response['current_day_name'] == datetime.now().strftime('%a')
[2d91474]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()]
[5ec3a0b]264
[1d92bf2]265    def test_profile(self, dummy_request, john):
[5ec3a0b]266        """
267        Renders the user profile page
268        """
269        request = dummy_request
[dbfab70]270        # profile page for the current day (no workouts avalable)
[1d92bf2]271        response = user_views.profile(john, request)
[bddf042]272        assert len(response.keys()) == 5
[bed4f06]273        current_month = datetime.now(timezone.utc).strftime('%Y-%m')
[bddf042]274        assert response['user'] == john
[bed4f06]275        assert response['current_month'] == current_month
[5cf5787]276        assert response['current_week'] is None
[dbfab70]277        assert response['workouts'] == []
[55470f9]278        assert response['totals'] == {
279            'distance': Decimal(0),
280            'time': timedelta(0),
281            'elevation': Decimal(0)
282        }
[dbfab70]283        # profile page for a previous date, that has workouts
284        request.GET['year'] = 2015
[55470f9]285        request.GET['month'] = 6
[dbfab70]286        response = user_views.profile(john, request)
[bddf042]287        assert len(response.keys()) == 5
288        assert response['user'] == john
[55470f9]289        assert response['current_month'] == '2015-06'
[5cf5787]290        assert response['current_week'] is None
[55470f9]291        workouts = john.workouts(2015, 6)
292        assert response['workouts'] == workouts
293        assert response['totals'] == {
294            'distance': workouts[0].distance,
295            'time': workouts[0].duration,
296            'elevation': Decimal(0)
297        }
[5cf5787]298        # same, passing a week, first on a week without workouts
299        request.GET['year'] = 2015
[55470f9]300        request.GET['month'] = 6
[5cf5787]301        request.GET['week'] = 25
302        response = user_views.profile(john, request)
[bddf042]303        assert len(response.keys()) == 5
304        assert response['user'] == john
[55470f9]305        assert response['current_month'] == '2015-06'
306        assert response['current_week'] == 25
[5cf5787]307        assert response['workouts'] == []
[55470f9]308        assert response['totals'] == {
309            'distance': Decimal(0),
310            'time': timedelta(0),
311            'elevation': Decimal(0)
312        }
313        # now in a week with workouts
[5cf5787]314        request.GET['year'] = 2015
[55470f9]315        request.GET['month'] = 6
[5cf5787]316        request.GET['week'] = 26
317        response = user_views.profile(john, request)
[bddf042]318        assert len(response.keys()) == 5
319        assert response['user'] == john
[55470f9]320        assert response['current_month'] == '2015-06'
321        assert response['current_week'] == 26
322        workouts = john.workouts(2015, 6)
323        assert response['workouts'] == workouts
324        assert response['totals'] == {
325            'distance': workouts[0].distance,
326            'time': workouts[0].duration,
327            'elevation': Decimal(0)
328        }
[5ec3a0b]329
330    def test_login_get(self, dummy_request):
331        """
332        GET request to access the login page
333        """
334        request = dummy_request
335        response = user_views.login(request.root, request)
336        assert response['message'] == ''
[1d92bf2]337        assert response['email'] == ''
[5ec3a0b]338        assert response['password'] == ''
339        assert response['redirect_url'] == request.resource_url(request.root)
340
[1d92bf2]341    def test_login_get_return_to(self, dummy_request, john):
[5ec3a0b]342        """
343        GET request to access the login page, if there is a page set to where
344        the user should be sent to, the response "redirect_url" key will have
345        such url
346        """
347        request = dummy_request
[1d92bf2]348        workout = john.workouts()[0]
[5ec3a0b]349        workout_url = request.resource_url(workout)
350        request.params['return_to'] = workout_url
351        response = user_views.login(request.root, request)
352        assert response['redirect_url'] == workout_url
353
[1d92bf2]354    def test_login_post_wrong_email(self, dummy_request):
[5ec3a0b]355        request = dummy_request
356        request.method = 'POST'
357        request.POST['submit'] = True
[1d92bf2]358        request.POST['email'] = 'jack@example.net'
[5ec3a0b]359        response = user_views.login(request.root, request)
[1d92bf2]360        assert response['message'] == u'Wrong email address'
[5ec3a0b]361
[1d92bf2]362    def test_login_post_wrong_password(self, dummy_request):
[5ec3a0b]363        request = dummy_request
364        request.method = 'POST'
365        request.POST['submit'] = True
[1d92bf2]366        request.POST['email'] = 'john.doe@example.net'
[5ec3a0b]367        request.POST['password'] = 'badpassword'
368        response = user_views.login(request.root, request)
[1d92bf2]369        assert response['message'] == u'Wrong password'
[5ec3a0b]370
371    @patch('ow.views.user.remember')
[f24ad73]372    def test_login_post_ok(self, rem, dummy_request, john):
[5ec3a0b]373        request = dummy_request
374        request.method = 'POST'
375        request.POST['submit'] = True
[1d92bf2]376        request.POST['email'] = 'john.doe@example.net'
[5ec3a0b]377        request.POST['password'] = 's3cr3t'
378        response = user_views.login(request.root, request)
379        assert isinstance(response, HTTPFound)
380        assert rem.called
[f24ad73]381        assert response.location == request.resource_url(john)
[5ec3a0b]382
383    @patch('ow.views.user.forget')
384    def test_logout(self, forg, dummy_request):
385        request = dummy_request
386        response = user_views.logout(request.root, request)
387        assert isinstance(response, HTTPFound)
388        assert forg.called
389        assert response.location == request.resource_url(request.root)
390
391    extensions = ('png', 'jpg', 'jpeg', 'gif')
392
393    @pytest.mark.parametrize('extension', extensions)
[1d92bf2]394    def test_profile_picture(self, extension, dummy_request, john):
[5ec3a0b]395        """
396        GET request to get the profile picture of an user.
397        """
398        request = dummy_request
399        # Get the user
[1d92bf2]400        user = john
[5ec3a0b]401        # Get the path to the image, then open it and copy it to a new Blob
402        # object
403        path = 'fixtures/image.' + extension
404        image_path = os.path.join(
405            os.path.dirname(os.path.dirname(__file__)), path)
406        blob = Blob()
407        with open(image_path, 'rb') as infile, blob.open('w') as out:
408            infile.seek(0)
409            copyfileobj(infile, out)
410
411        # Set the blob with the picture
412        user.picture = blob
413
414        # Call the profile_picture view
415        response = user_views.profile_picture(user, request)
416        assert isinstance(response, Response)
417        assert response.status_int == 200
418        assert response.content_type == 'image'
419
[1d92bf2]420    def test_edit_profile_get(self, dummy_request, john):
[5ec3a0b]421        """
422        GET request to the edit profile page, returns the form ready to
423        be rendered
424        """
425        request = dummy_request
[1d92bf2]426        user = john
[5ec3a0b]427        response = user_views.edit_profile(user, request)
428        assert isinstance(response['form'], OWFormRenderer)
429        # no errors in the form (first load)
430        assert response['form'].errorlist() == ''
431        # the form carries along the proper data keys, taken from the
432        # loaded user profile
[722ae18]433        data = ['firstname', 'lastname', 'email', 'nickname', 'bio',
[31adfa5]434                'birth_date', 'height', 'weight', 'gender', 'timezone']
[5ec3a0b]435        assert list(response['form'].data.keys()) == data
436        # and check the email to see data is properly loaded
437        assert response['form'].data['email'] == 'john.doe@example.net'
438
[1d92bf2]439    def test_edit_profile_post_ok(self, profile_post_request, john):
[5ec3a0b]440        request = profile_post_request
[1d92bf2]441        user = john
[5ec3a0b]442        # Update the bio field
443        bio = 'Some text about this user'
444        request.POST['bio'] = bio
445        response = user_views.edit_profile(user, request)
446        assert isinstance(response, HTTPFound)
447        assert response.location == request.resource_url(user, 'profile')
448        assert user.bio == bio
449
[1d92bf2]450    def test_edit_profile_post_missing_required(
451            self, profile_post_request, john):
[5ec3a0b]452        request = profile_post_request
453        request.POST['email'] = ''
[1d92bf2]454        user = john
[5ec3a0b]455        response = user_views.edit_profile(user, request)
456        assert isinstance(response['form'], OWFormRenderer)
457        # error on the missing email field
458        error = u'Please enter an email address'
459        html_error = u'<ul class="error"><li>' + error + '</li></ul>'
460        assert response['form'].errorlist() == html_error
461        assert response['form'].errors_for('email') == [error]
462
[fe6089a]463    def test_edit_profile_post_ok_picture_empty_bytes(
464            self, profile_post_request, john):
465        """
466        POST request with an empty picture, the content of
467        request['POST'].picture is a empty bytes string (b'') which triggers
468        a bug in formencode, we put a fix in place, test that
469        (more in ow.user.views.edit_profile)
470        """
471        # for the purposes of this test, we can mock the picture
472        picture = Mock()
473        john.picture = picture
474        request = profile_post_request
475        user = john
476        # Mimic what happens when a picture is not provided by the user
477        request.POST['picture'] = b''
478        response = user_views.edit_profile(user, request)
479        assert isinstance(response, HTTPFound)
480        assert response.location == request.resource_url(user, 'profile')
481        assert user.picture == picture
482
483    def test_edit_profile_post_ok_missing_picture(
484            self, profile_post_request, john):
485        """
486        POST request without picture
487        """
488        # for the purposes of this test, we can mock the picture
489        picture = Mock()
490        john.picture = picture
491        request = profile_post_request
492        user = john
493        # No pic is provided in the request POST values
494        del request.POST['picture']
495        response = user_views.edit_profile(user, request)
496        assert isinstance(response, HTTPFound)
497        assert response.location == request.resource_url(user, 'profile')
498        assert user.picture == picture
499
500    def test_edit_profile_post_ok_nickname(self, profile_post_request, john):
501        """
502        User with a nickname set saves profile without changing the profile,
503        we have to be sure there are no "nickname already in use" errors
504        """
505        request = profile_post_request
506        user = john
507        user.nickname = 'mr_jones'
508        # add the nickname, the default post request has not a nickname set
509        request.POST['nickname'] = 'mr_jones'
510        response = user_views.edit_profile(user, request)
511        assert isinstance(response, HTTPFound)
512        assert response.location == request.resource_url(user, 'profile')
513
[1d92bf2]514    def test_change_password_get(self, dummy_request, john):
[5ec3a0b]515        request = dummy_request
[1d92bf2]516        user = john
[5ec3a0b]517        response = user_views.change_password(user, request)
518        assert isinstance(response['form'], OWFormRenderer)
519        # no errors in the form (first load)
520        assert response['form'].errorlist() == ''
521
[1d92bf2]522    def test_change_password_post_ok(self, passwd_post_request, john):
[5ec3a0b]523        request = passwd_post_request
[1d92bf2]524        user = john
[5ec3a0b]525        request.POST['old_password'] = 's3cr3t'
526        request.POST['password'] = 'h1dd3n s3cr3t'
527        request.POST['password_confirm'] = 'h1dd3n s3cr3t'
528        response = user_views.change_password(user, request)
529        assert isinstance(response, HTTPFound)
530        assert response.location == request.resource_url(user, 'profile')
531        # password was changed
532        assert not user.check_password('s3cr3t')
533        assert user.check_password('h1dd3n s3cr3t')
534
[1d92bf2]535    def test_change_password_post_no_values(self, passwd_post_request, john):
[5ec3a0b]536        request = passwd_post_request
[1d92bf2]537        user = john
[5ec3a0b]538        response = user_views.change_password(user, request)
539        assert isinstance(response['form'], OWFormRenderer)
540        error = u'Please enter a value'
541        html_error = u'<ul class="error">'
542        html_error += ('<li>' + error + '</li>') * 3  # 3 fields
543        html_error += '</ul>'
544        errorlist = response['form'].errorlist().replace('\n', '')
545        assert errorlist == html_error
546        assert response['form'].errors_for('old_password') == [error]
547        assert response['form'].errors_for('password') == [error]
548        assert response['form'].errors_for('password_confirm') == [error]
549        # password was not changed
550        assert user.check_password('s3cr3t')
551
[1d92bf2]552    def test_change_password_post_bad_old_password(
553            self, passwd_post_request, john):
[5ec3a0b]554        request = passwd_post_request
[1d92bf2]555        user = john
[5ec3a0b]556        request.POST['old_password'] = 'FAIL PASSWORD'
557        request.POST['password'] = 'h1dd3n s3cr3t'
558        request.POST['password_confirm'] = 'h1dd3n s3cr3t'
559        response = user_views.change_password(user, request)
560        assert isinstance(response['form'], OWFormRenderer)
561        error = u'The given password does not match the existing one '
562        html_error = u'<ul class="error"><li>' + error + '</li></ul>'
563        assert response['form'].errorlist() == html_error
564        assert response['form'].errors_for('old_password') == [error]
565        # password was not changed
566        assert user.check_password('s3cr3t')
567        assert not user.check_password('h1dd3n s3cr3t')
568
[1d92bf2]569    def test_change_password_post_password_mismatch(
570            self, passwd_post_request, john):
[5ec3a0b]571        request = passwd_post_request
[1d92bf2]572        user = john
[5ec3a0b]573        request.POST['old_password'] = 's3cr3t'
574        request.POST['password'] = 'h1dd3n s3cr3ts'
575        request.POST['password_confirm'] = 'h1dd3n s3cr3t'
576        response = user_views.change_password(user, request)
577        assert isinstance(response['form'], OWFormRenderer)
578        error = u'Fields do not match'
579        html_error = u'<ul class="error"><li>' + error + '</li></ul>'
580        assert response['form'].errorlist() == html_error
581        assert response['form'].errors_for('password_confirm') == [error]
582        # password was not changed
583        assert user.check_password('s3cr3t')
584        assert not user.check_password('h1dd3n s3cr3t')
585
586    def test_signup_get(self, dummy_request):
587        request = dummy_request
588        response = user_views.signup(request.root, request)
589        assert isinstance(response['form'], OWFormRenderer)
590        # no errors in the form (first load)
591        assert response['form'].errorlist() == ''
592
593    def test_signup_post_ok(self, signup_post_request):
594        request = signup_post_request
[1d92bf2]595        assert 'jack.black@example.net' not in request.root.emails
596        assert 'JackBlack' not in request.root.all_nicknames
[5ec3a0b]597        response = user_views.signup(request.root, request)
598        assert isinstance(response, HTTPFound)
599        assert response.location == request.resource_url(request.root)
[1d92bf2]600        assert 'jack.black@example.net' in request.root.emails
601        assert 'JackBlack' in request.root.all_nicknames
[5ec3a0b]602
603    def test_signup_missing_required(self, signup_post_request):
604        request = signup_post_request
605        request.POST['email'] = ''
[1d92bf2]606        assert 'jack.black@example.net' not in request.root.emails
607        assert 'JackBlack' not in request.root.all_nicknames
[5ec3a0b]608        response = user_views.signup(request.root, request)
609        assert isinstance(response['form'], OWFormRenderer)
610        error = u'Please enter an email address'
611        html_error = '<ul class="error">'
612        html_error += '<li>' + error + '</li>'
613        html_error += '</ul>'
614        errorlist = response['form'].errorlist().replace('\n', '')
615        assert errorlist == html_error
616        assert response['form'].errors_for('email') == [error]
[1d92bf2]617        assert 'jack.black@example.net' not in request.root.emails
618        assert 'JackBlack' not in request.root.all_nicknames
[5ec3a0b]619
[1d92bf2]620    def test_signup_existing_nickname(self, signup_post_request, john):
[5ec3a0b]621        request = signup_post_request
[1d92bf2]622        # assign john a nickname first
623        john.nickname = 'john'
624        # now set it for the POST request
625        request.POST['nickname'] = 'john'
626        # check jack is not there yet
627        assert 'jack.black@example.net' not in request.root.emails
628        assert 'JackBlack' not in request.root.all_nicknames
629        # now signup as jack, but trying to set the nickname 'john'
[5ec3a0b]630        response = user_views.signup(request.root, request)
631        assert isinstance(response['form'], OWFormRenderer)
[1d92bf2]632        error = u'Another user is already using the nickname john'
[5ec3a0b]633        html_error = '<ul class="error">'
634        html_error += '<li>' + error + '</li>'
635        html_error += '</ul>'
636        errorlist = response['form'].errorlist().replace('\n', '')
637        assert errorlist == html_error
[1d92bf2]638        assert response['form'].errors_for('nickname') == [error]
639        # all the errors, and jack is not there
640        assert 'jack.black@example.net' not in request.root.emails
641        assert 'JackBlack' not in request.root.all_nicknames
[5ec3a0b]642
643    def test_signup_existing_email(self, signup_post_request):
644        request = signup_post_request
645        request.POST['email'] = 'john.doe@example.net'
[1d92bf2]646        assert 'jack.black@example.net' not in request.root.emails
647        assert 'JackBlack' not in request.root.all_nicknames
[5ec3a0b]648        response = user_views.signup(request.root, request)
649        assert isinstance(response['form'], OWFormRenderer)
650        error = u'Another user is already registered with the email '
651        error += u'john.doe@example.net'
652        html_error = '<ul class="error">'
653        html_error += '<li>' + error + '</li>'
654        html_error += '</ul>'
655        errorlist = response['form'].errorlist().replace('\n', '')
656        assert errorlist == html_error
657        assert response['form'].errors_for('email') == [error]
[1d92bf2]658        assert 'jack.black@example.net' not in request.root.emails
659        assert 'JackBlack' not in request.root.all_nicknames
[421f05f]660
661    def test_week_stats_no_stats(self, dummy_request, john):
662        response = user_views.week_stats(john, dummy_request)
663        assert isinstance(response, Response)
664        assert response.content_type == 'application/json'
665        # the body is a valid json-encoded stream
666        obj = json.loads(response.body)
667        assert obj == [
668            {'distance': 0, 'elevation': 0, 'name': 'Mon',
669             'time': '00', 'workouts': 0},
670            {'distance': 0, 'elevation': 0, 'name': 'Tue',
671             'time': '00', 'workouts': 0},
672            {'distance': 0, 'elevation': 0, 'name': 'Wed',
673             'time': '00', 'workouts': 0},
674            {'distance': 0, 'elevation': 0, 'name': 'Thu',
675             'time': '00', 'workouts': 0},
676            {'distance': 0, 'elevation': 0, 'name': 'Fri',
677             'time': '00', 'workouts': 0},
678            {'distance': 0, 'elevation': 0, 'name': 'Sat',
679             'time': '00', 'workouts': 0},
680            {'distance': 0, 'elevation': 0, 'name': 'Sun',
681             'time': '00', 'workouts': 0}
682        ]
683
684    def test_week_stats(self, dummy_request, john):
685        workout = Workout(
686            start=datetime.now(timezone.utc),
687            duration=timedelta(minutes=60),
688            distance=30,
689            elevation=540
690        )
691        john.add_workout(workout)
692        response = user_views.week_stats(john, dummy_request)
693        assert isinstance(response, Response)
694        assert response.content_type == 'application/json'
695        # the body is a valid json-encoded stream
696        obj = json.loads(response.body)
697        assert len(obj) == 7
698        for day in obj:
699            if datetime.now(timezone.utc).strftime('%a') == day['name']:
700                day['distance'] == 30
701                day['elevation'] == 540
702                day['time'] == '01'
703                day['workouts'] == 1
704            else:
705                day['distance'] == 0
706                day['elevation'] == 0
707                day['time'] == '00'
708                day['workouts'] == 0
Note: See TracBrowser for help on using the repository browser.