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

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

## 143 statements

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"""

2 This file (test_auth_functional.py) contains the functional tests for

3 the `auth` blueprint.

4

5 These tests use GETs and POSTs to different endpoints to check

6 for the proper behavior of the `auth` module

7"""

8 import json

9 import os

10 import threading

11

12 import pytest

13 from flask import request

14 from flask import url_for

15 from flask_login import current_user

16 from modules.box__default.auth.models import User

17

18 dirpath = os.path.dirname(os.path.abspath(__file__))

19 module_path = os.path.dirname(dirpath)

20

21 module_info = None

22

23 with open(os.path.join(module_path, "info.json")) as f:

24 module_info = json.load(f)

25

26

27 class TestAuthInvalidAccess:

28 """

29 Test all auth routes for correct user authentication

30 """

31

32 routes_get = [

33 "/confirm/<token>",

34 "/resend",

35 "/unconfirmed",

36 ]

37

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 )

44

45 assert response.status_code == 200

46 assert request.path == url_for("auth.login")

47

48

49 class TestAuthEndpoints:

50 """

51 Test all auth routes' functionalities

52 """

53

54 def test_user_registration_page_renders(self, test_client):

55 response = test_client.get(f"{module_info['url_prefix']}/register")

56

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

62

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 }

70

71 response = test_client.post(

72 f"{module_info['url_prefix']}/register",

73 data=data,

74 follow_redirects=True,

75 )

76

77 assert response.status_code == 200

78 assert request.path == url_for("auth.register")

79

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 }

87

88 response = test_client.post(

89 f"{module_info['url_prefix']}/register",

90 data=data,

91 follow_redirects=True,

92 )

93

94 assert response.status_code == 200

95 assert request.path == url_for("auth.register")

96

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()

116

117 assert response.status_code == 200

118 assert request.path == url_for("dashboard.index")

119 assert user.is_email_confirmed is True

120

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()

150

151 user = User.query.filter(User.email == "test@gmail.com").scalar()

152

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

160

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 )

166

167 assert response.status_code == 200

168 assert request.path == url_for("dashboard.index")

169 assert b"Account already confirmed." in response.data

170

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 )

177

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

182

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 )

189

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

193

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)

197

198 assert response.status_code == 200

199 assert request.path == url_for("dashboard.index")

200

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)

204

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()

212

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

218

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)

222

223 assert response.status_code == 200

224 assert request.path == url_for("dashboard.index")

225

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"))

229

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

235

236 def test_login_for_dashboard_renders(self, test_client):

237 response = test_client.get(url_for("auth.login"))

238

239 assert response.status_code == 200

240 assert b"Login" in response.data

241 assert b"submit" in response.data

242

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 )

249

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

253

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 )

260

261 assert response.status_code == 200

262 assert current_user.email == non_admin_user.email

263 assert request.path == url_for("dashboard.index")

264

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 )

273

274 assert response.status_code == 200

275 assert current_user.email.lower() == data["email"].lower()

276 assert request.path == url_for("auth.unconfirmed")

277

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)

281

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