55MoinMoin - Tests for frontend
66"""
77
8+ from __future__ import annotations
9+
10+ from typing import Any , TYPE_CHECKING , Iterable
811from io import BytesIO
912
13+ import pytest
14+
1015from flask import url_for
1116from flask import g as flaskg
1217from werkzeug .datastructures import FileStorage
1318
14- from moin .apps .frontend import views
1519from moin import user
20+ from moin .apps .frontend import views
21+ from moin .constants .keys import ITEMID
22+
23+ if TYPE_CHECKING :
24+ from flask .testing import FlaskClient
25+ from werkzeug .test import TestResponse
26+
27+
28+ def create_user (name : str , password : str , pwencoded : bool = False , email : str | None = None ) -> None :
29+ """helper to create test user"""
30+ if email is None :
31+ 32+ user .create_user (name , password , email , is_encrypted = pwencoded )
1633
17- import pytest
34+
35+ def set_user_in_client_session (client : FlaskClient , user : user .User ) -> None :
36+ # the test configuration has MoinAuth enabled
37+ with client .session_transaction () as session :
38+ session ["user.itemid" ] = user .profile [ITEMID ]
39+ session ["user.trusted" ] = False
40+ session ["user.auth_method" ] = "moin"
41+ session ["user.auth_attribs" ] = tuple ()
42+ session ["user.session_token" ] = user .get_session_token ()
43+
44+
45+ def client_request (
46+ client : FlaskClient , method : str , url : str , * , user : user .User | None = None , ** kwargs : Any
47+ ) -> TestResponse :
48+ if user is not None :
49+ set_user_in_client_session (client , user )
50+ print (f"client request: { method } { url } " )
51+ response = client .open (url , method = method , ** kwargs )
52+ return response
1853
1954
2055class TestFrontend :
@@ -26,51 +61,68 @@ def custom_setup(self, app):
2661 def _test_view (
2762 self ,
2863 viewname ,
29- status = "200 OK" ,
30- data = ("<html>" , "</html>" ),
31- content_types = ("text/html; charset=utf-8" ,),
32- viewopts = None ,
33- params = None ,
34- ):
64+ * ,
65+ status : str = "200 OK" ,
66+ data : Iterable [str ] = ("<html>" , "</html>" ),
67+ content_types : Iterable [str ] = ("text/html; charset=utf-8" ,),
68+ viewopts : dict [str , Any ] | None = None ,
69+ params : dict [str , Any ] | None = None ,
70+ user : user .User | None = None ,
71+ ) -> TestResponse :
72+
3573 if viewopts is None :
3674 viewopts = {}
3775 if params is None :
3876 params = {}
3977
40- with self .app .test_client () as c :
41- for method in ["HEAD" , "GET" ]:
42- print ("%s %s" % (method , url_for (viewname , ** viewopts )))
43- rv = c .open (url_for (viewname , ** viewopts ), method = method , data = params )
44- rv_data = rv .data .decode ()
45- assert rv .status == status
46- assert rv .headers ["Content-Type" ] in content_types
47- if method == "GET" :
48- for item in data :
49- assert item in rv_data
50- return rv
78+ with self .app .test_client () as client :
79+
80+ request_url = url_for (viewname , ** viewopts )
81+
82+ response = client_request (client , "HEAD" , request_url , user = user , data = params )
83+ assert response .status == status
84+ assert response .headers ["Content-Type" ] in content_types
85+
86+ response = client_request (client , "GET" , request_url , user = user , data = params )
87+ assert response .status == status
88+ assert response .headers ["Content-Type" ] in content_types
89+ rv_data = response .data .decode ()
90+ for item in data :
91+ assert item in rv_data
92+
93+ return response
5194
5295 def _test_view_post (
5396 self ,
54- viewname ,
55- status = "302 FOUND" ,
56- content_types = ("text/html; charset=utf-8" ,),
57- data = ("<html>" , "</html>" ),
58- form = None ,
59- viewopts = None ,
60- ):
97+ viewname : str ,
98+ * ,
99+ status : str = "302 FOUND" ,
100+ content_types : Iterable [str ] = ("text/html; charset=utf-8" ,),
101+ data : Iterable [str ] = ("<html>" , "</html>" ),
102+ form : dict [str , Any ] | None = None ,
103+ viewopts : dict [str , Any ] | None = None ,
104+ params : dict [str , Any ] | None = None ,
105+ user : user .User | None = None ,
106+ ) -> TestResponse :
107+
108+ if params is None :
109+ params = {}
61110 if viewopts is None :
62111 viewopts = {}
63112 if form is None :
64113 form = {}
65- print ("POST %s" % url_for (viewname , ** viewopts ))
66- with self .app .test_client () as c :
67- rv = c .post (url_for (viewname , ** viewopts ), data = form )
68- rv_data = rv .data .decode ()
69- assert rv .status == status
70- assert rv .headers ["Content-Type" ] in content_types
114+
115+ request_url = url_for (viewname , ** viewopts )
116+ print ("POST %s" % request_url )
117+
118+ with self .app .test_client () as client :
119+ response = client_request (client , "POST" , request_url , user = user , query_string = params , data = form )
120+ assert response .status == status
121+ assert response .headers ["Content-Type" ] in content_types
122+ rv_data = response .get_data (as_text = True )
71123 for item in data :
72124 assert item in rv_data
73- return rv
125+ return response
74126
75127 def test_ajaxdelete_item_name_route (self ):
76128 self ._test_view_post (
@@ -170,6 +222,31 @@ def test_convert_item(self):
170222 def test_modify_item (self ):
171223 self ._test_view ("frontend.modify_item" , status = "200 OK" , viewopts = dict (item_name = "DoesntExist" ))
172224
225+ def test_modify_item_show_preview (self ):
226+
227+ create_user ("björn" , "Xiwejr622" )
228+ test_user = flaskg .user = user .User (name = "björn" , password = "Xiwejr622" )
229+
230+ content = "New item content."
231+
232+ self ._test_view_post (
233+ "frontend.modify_item" ,
234+ status = "200 OK" ,
235+ viewopts = dict (item_name = "quokka" ),
236+ params = {"itemtype" : "default" , "contenttype" : "text/x.moin.wiki;charset=utf-8" , "template" : "" },
237+ form = {
238+ "comment" : "" ,
239+ "content_form_data_text" : content ,
240+ "content_form_data_file" : content .encode (encoding = "utf-8" ),
241+ "preview" : "Preview" ,
242+ "meta_form_acl" : "None" ,
243+ "meta_form_name" : "quokka" ,
244+ "meta_form_summary" : "" ,
245+ "meta_form_tags" : "" ,
246+ },
247+ user = test_user ,
248+ )
249+
173250 def test_rename_item (self ):
174251 self ._test_view ("frontend.rename_item" , status = "404 NOT FOUND" , viewopts = dict (item_name = "DoesntExist" ))
175252
@@ -253,6 +330,22 @@ def test_recoverpass(self):
253330 def test_login (self ):
254331 self ._test_view ("frontend.login" )
255332
333+ def test_login_post (self ):
334+ username = "moin"
335+ password = "Xiwejr622"
336+ create_user (username , password )
337+ response = self ._test_view_post (
338+ "frontend.login" ,
339+ form = {
340+ "login_username" : username ,
341+ "login_password" : password ,
342+ "login_nexturl" : "http://localhost/Home" ,
343+ "login_submit" : "1" ,
344+ },
345+ data = ("Redirecting..." ,),
346+ )
347+ assert response .location == "http://localhost/Home"
348+
256349 def test_logout (self ):
257350 self ._test_view ("frontend.logout" , status = "302 FOUND" , data = ["<!doctype html" ])
258351
@@ -284,7 +377,7 @@ def custom_setup(self, app):
284377 flaskg .user = saved_user
285378
286379 def test_user_password_change (self ):
287- self . createUser ("moin" , "Xiwejr622" )
380+ create_user ("moin" , "Xiwejr622" )
288381 flaskg .user = user .User (name = "moin" , password = "Xiwejr622" )
289382 form = self .fillPasswordChangeForm ("Xiwejr622" , "Woodoo645" , "Woodoo645" )
290383 valid = form .validate ()
@@ -294,7 +387,7 @@ def test_user_unicode_password_change(self):
294387 name = "moin"
295388 password = "__שם משתמש לא קיים__" # Hebrew
296389
297- self . createUser (name , password )
390+ create_user (name , password )
298391 flaskg .user = user .User (name = name , password = password )
299392 form = self .fillPasswordChangeForm (password , "Woodoo645" , "Woodoo645" )
300393 valid = form .validate ()
@@ -305,22 +398,22 @@ def test_user_password_change_to_unicode_pw(self):
305398 password = "Xiwejr622"
306399 new_password = "__שם משתמש לא קיים__" # Hebrew
307400
308- self . createUser (name , password )
401+ create_user (name , password )
309402 flaskg .user = user .User (name = name , password = password )
310403 form = self .fillPasswordChangeForm (password , new_password , new_password )
311404 valid = form .validate ()
312405 assert valid # form data is valid
313406
314407 def test_fail_user_password_change_pw_mismatch (self ):
315- self . createUser ("moin" , "Xiwejr622" )
408+ create_user ("moin" , "Xiwejr622" )
316409 flaskg .user = user .User (name = "moin" , password = "Xiwejr622" )
317410 form = self .fillPasswordChangeForm ("Xiwejr622" , "Piped33" , "Woodoo645" )
318411 valid = form .validate ()
319412 # form data is invalid because password1 != password2
320413 assert not valid
321414
322415 def test_fail_password_change (self ):
323- self . createUser ("moin" , "Xiwejr622" )
416+ create_user ("moin" , "Xiwejr622" )
324417 flaskg .user = user .User (name = "moin" , password = "Xiwejr622" )
325418 form = self .fillPasswordChangeForm ("Xinetd33" , "Woodoo645" , "Woodoo645" )
326419 valid = form .validate ()
@@ -340,9 +433,3 @@ def fillPasswordChangeForm(self, current_password, password1, password2):
340433 )
341434 form = FormClass .from_flat (request_form )
342435 return form
343-
344- def createUser (self , name , password , pwencoded = False , email = None ):
345- """helper to create test user"""
346- if email is None :
347- 348- user .create_user (name , password , email , is_encrypted = pwencoded )
0 commit comments