Coverage for modules/box__default/auth/tests/test_auth_functional.py : 99%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2This file (test_auth_functional.py) contains the functional tests for
3the `auth` blueprint.
5These tests use GETs and POSTs to different endpoints to check
6for the proper behavior of the `auth` module
7"""
8import json
9import os
10import threading
12import pytest
13from flask import request
14from flask import url_for
15from flask_login import current_user
16from modules.box__default.auth.models import User
18dirpath = os.path.dirname(os.path.abspath(__file__))
19module_path = os.path.dirname(dirpath)
21module_info = None
23with open(os.path.join(module_path, "info.json")) as f:
24 module_info = json.load(f)
27class TestAuthInvalidAccess:
28 """
29 Test all auth routes for correct user authentication
30 """
32 routes_get = [
33 "/confirm/<token>",
34 "/resend",
35 "/unconfirmed",
36 ]
38 @pytest.mark.parametrize("route", routes_get)
39 def test_redirect_if_not_logged_in_get(self, test_client, route, auth):
40 auth.logout()
41 response = test_client.get(
42 f"{module_info['url_prefix']}{route}", follow_redirects=True
43 )
45 assert response.status_code == 200
46 assert request.path == url_for("auth.login")
49class TestAuthEndpoints:
50 """
51 Test all auth routes' functionalities
52 """
54 def test_user_registration_page_renders(self, test_client):
55 response = test_client.get(f"{module_info['url_prefix']}/register")
57 assert response.status_code == 200
58 assert b"Email" in response.data
59 assert b"Password" in response.data
60 assert b"Confirm Password" in response.data
61 assert b"Register" in response.data
63 def test_user_not_registered_on_invalid_form_submit(self, test_client):
64 User.create(email="test@gmail.com", password="pass")
65 data = {
66 "email": "test@gmail.com",
67 "password": "password",
68 "confirm": "password",
69 }
71 response = test_client.post(
72 f"{module_info['url_prefix']}/register",
73 data=data,
74 follow_redirects=True,
75 )
77 assert response.status_code == 200
78 assert request.path == url_for("auth.register")
80 def test_user_registration_is_case_insensitive(self, test_client):
81 User.create(email="foo@bar.com", password="pass")
82 data = {
83 "email": "Foo@Bar.com",
84 "password": "password",
85 "confirm": "password",
86 }
88 response = test_client.post(
89 f"{module_info['url_prefix']}/register",
90 data=data,
91 follow_redirects=True,
92 )
94 assert response.status_code == 200
95 assert request.path == url_for("auth.register")
97 @pytest.mark.parametrize(
98 "email_config",
99 [
100 ("EMAIL_CONFIRMATION_DISABLED", True),
101 ],
102 indirect=True,
103 )
104 def test_user_confirmed_if_email_disabled(self, test_client, email_config):
105 data = {
106 "email": "test@gmail.com",
107 "password": "password",
108 "confirm": "password",
109 }
110 response = test_client.post(
111 f"{module_info['url_prefix']}/register",
112 data=data,
113 follow_redirects=True,
114 )
115 user = User.query.filter(User.email == "test@gmail.com").scalar()
117 assert response.status_code == 200
118 assert request.path == url_for("dashboard.index")
119 assert user.is_email_confirmed is True
121 @pytest.mark.parametrize(
122 "email_config",
123 [
124 ("EMAIL_CONFIRMATION_DISABLED", "remove"),
125 ("EMAIL_CONFIRMATION_DISABLED", False),
126 ("EMAIL_CONFIRMATION_DISABLED", None),
127 ],
128 indirect=True,
129 )
130 def test_user_is_registered_on_valid_form_submit(
131 self, test_client, capfd, email_config
132 ):
133 data = {
134 "email": "test@gmail.com",
135 "password": "password",
136 "confirm": "password",
137 }
138 response = test_client.post(
139 f"{module_info['url_prefix']}/register",
140 data=data,
141 follow_redirects=True,
142 )
143 # Not very happy with this solution. Need a better
144 # way to wait for the email thread to join with main
145 # thread before reading the email written to stdout @rehmanis
146 while threading.activeCount() > 1:
147 pass
148 else:
149 captured = capfd.readouterr()
151 user = User.query.filter(User.email == "test@gmail.com").scalar()
153 assert response.status_code == 200
154 assert request.path == url_for("auth.unconfirmed")
155 assert b"A confirmation email has been sent via email" in response.data
156 assert "test@gmail.com" in captured.out
157 assert "Welcome to Shopyo" in captured.out
158 assert user is not None
159 assert user.is_email_confirmed is False
161 @pytest.mark.usefixtures("login_non_admin_user")
162 def test_user_not_confirmed_for_already_confirmed_user(self, test_client):
163 response = test_client.get(
164 url_for("auth.confirm", token="sometoken"), follow_redirects=True
165 )
167 assert response.status_code == 200
168 assert request.path == url_for("dashboard.index")
169 assert b"Account already confirmed." in response.data
171 @pytest.mark.usefixtures("login_unconfirmed_user")
172 def test_user_confirmed_on_valid_token(self, test_client):
173 token = current_user.generate_confirmation_token()
174 response = test_client.get(
175 url_for("auth.confirm", token=token), follow_redirects=True
176 )
178 assert response.status_code == 200
179 assert request.path == url_for("dashboard.index")
180 assert b"You have confirmed your account. Thanks!" in response.data
181 assert current_user.is_email_confirmed is True
183 @pytest.mark.usefixtures("login_unconfirmed_user")
184 def test_no_confirm_sent_for_invalid_token(self, test_client):
185 token = current_user.generate_confirmation_token() + "extra"
186 response = test_client.get(
187 url_for("auth.confirm", token=token), follow_redirects=True
188 )
190 assert response.status_code == 200
191 assert request.path == url_for("auth.unconfirmed")
192 assert b"The confirmation link is invalid/expired." in response.data
194 @pytest.mark.usefixtures("login_non_admin_user")
195 def test_do_not_allow_email_resend_for_confirmed(self, test_client):
196 response = test_client.get(url_for("auth.resend"), follow_redirects=True)
198 assert response.status_code == 200
199 assert request.path == url_for("dashboard.index")
201 @pytest.mark.usefixtures("login_unconfirmed_user")
202 def test_valid_resend_email_confirmation(self, test_client, capfd):
203 response = test_client.get(url_for("auth.resend"), follow_redirects=True)
205 # Not very happy with this solution. Need a better
206 # way to wait for the email thread to join with main
207 # thread before reading the email written to stdout @rehmanis
208 while threading.activeCount() > 1: 208 ↛ 209line 208 didn't jump to line 209, because the condition on line 208 was never true
209 pass
210 else:
211 captured = capfd.readouterr()
213 assert response.status_code == 200
214 assert current_user.email in captured.out
215 assert "Welcome to Shopyo" in captured.out
216 assert request.path == url_for("auth.unconfirmed")
217 assert b"A new confirmation email has been sent" in response.data
219 @pytest.mark.usefixtures("login_non_admin_user")
220 def test_confirmed_user_is_redirected_to_dashboard(self, test_client):
221 response = test_client.get(url_for("auth.unconfirmed"), follow_redirects=True)
223 assert response.status_code == 200
224 assert request.path == url_for("dashboard.index")
226 @pytest.mark.usefixtures("login_unconfirmed_user")
227 def test_unconfirmed_page_renders_correctly(self, test_client):
228 response = test_client.get(url_for("auth.unconfirmed"))
230 assert response.status_code == 200
231 assert request.path == url_for("auth.unconfirmed")
232 assert b"You have not confirmed your account" in response.data
233 assert b"Email confirmation link was sent to" in response.data
234 assert current_user.email.encode() in response.data
236 def test_login_for_dashboard_renders(self, test_client):
237 response = test_client.get(url_for("auth.login"))
239 assert response.status_code == 200
240 assert b"Login" in response.data
241 assert b"submit" in response.data
243 def test_invalid_dashboard_login(self, test_client):
244 response = test_client.post(
245 url_for("auth.login"),
246 data=dict(email="admin1@domain.com", password="wrongpass"),
247 follow_redirects=True,
248 )
250 assert response.status_code == 200
251 assert request.path == url_for("auth.login")
252 assert b"please check your user id and password" in response.data
254 def test_valid_dashboard_login(self, test_client, non_admin_user):
255 response = test_client.post(
256 url_for("auth.login"),
257 data=dict(email=non_admin_user.email, password="pass"),
258 follow_redirects=True,
259 )
261 assert response.status_code == 200
262 assert current_user.email == non_admin_user.email
263 assert request.path == url_for("dashboard.index")
265 def test_valid_dashboard_login_is_case_insensitive(self, test_client):
266 User.create(email="foo@bar.com", password="pass")
267 data = {"email": "Foo@Bar.com", "password": "pass"}
268 response = test_client.post(
269 url_for("auth.login"),
270 data=data,
271 follow_redirects=True,
272 )
274 assert response.status_code == 200
275 assert current_user.email.lower() == data["email"].lower()
276 assert request.path == url_for("auth.unconfirmed")
278 @pytest.mark.usefixtures("login_non_admin_user")
279 def test_current_user_logout(self, test_client):
280 response = test_client.get(url_for("auth.logout"), follow_redirects=True)
282 assert response.status_code == 200
283 assert request.path == url_for("auth.login")
284 assert b"Successfully logged out" in response.data
285 assert current_user.is_authenticated is False