1import logging 2 3import pytest 4import werkzeug.serving 5from jinja2 import TemplateNotFound 6 7import flask 8 9 10def test_context_processing(app, client): 11 @app.context_processor 12 def context_processor(): 13 return {"injected_value": 42} 14 15 @app.route("/") 16 def index(): 17 return flask.render_template("context_template.html", value=23) 18 19 rv = client.get("/") 20 assert rv.data == b"<p>23|42" 21 22 23def test_original_win(app, client): 24 @app.route("/") 25 def index(): 26 return flask.render_template_string("{{ config }}", config=42) 27 28 rv = client.get("/") 29 assert rv.data == b"42" 30 31 32def test_request_less_rendering(app, app_ctx): 33 app.config["WORLD_NAME"] = "Special World" 34 35 @app.context_processor 36 def context_processor(): 37 return dict(foo=42) 38 39 rv = flask.render_template_string("Hello {{ config.WORLD_NAME }} {{ foo }}") 40 assert rv == "Hello Special World 42" 41 42 43def test_standard_context(app, client): 44 @app.route("/") 45 def index(): 46 flask.g.foo = 23 47 flask.session["test"] = "aha" 48 return flask.render_template_string( 49 """ 50 {{ request.args.foo }} 51 {{ g.foo }} 52 {{ config.DEBUG }} 53 {{ session.test }} 54 """ 55 ) 56 57 rv = client.get("/?foo=42") 58 assert rv.data.split() == [b"42", b"23", b"False", b"aha"] 59 60 61def test_escaping(app, client): 62 text = "<p>Hello World!" 63 64 @app.route("/") 65 def index(): 66 return flask.render_template( 67 "escaping_template.html", text=text, html=flask.Markup(text) 68 ) 69 70 lines = client.get("/").data.splitlines() 71 assert lines == [ 72 b"<p>Hello World!", 73 b"<p>Hello World!", 74 b"<p>Hello World!", 75 b"<p>Hello World!", 76 b"<p>Hello World!", 77 b"<p>Hello World!", 78 ] 79 80 81def test_no_escaping(app, client): 82 text = "<p>Hello World!" 83 84 @app.route("/") 85 def index(): 86 return flask.render_template( 87 "non_escaping_template.txt", text=text, html=flask.Markup(text) 88 ) 89 90 lines = client.get("/").data.splitlines() 91 assert lines == [ 92 b"<p>Hello World!", 93 b"<p>Hello World!", 94 b"<p>Hello World!", 95 b"<p>Hello World!", 96 b"<p>Hello World!", 97 b"<p>Hello World!", 98 b"<p>Hello World!", 99 b"<p>Hello World!", 100 ] 101 102 103def test_escaping_without_template_filename(app, client, req_ctx): 104 assert flask.render_template_string("{{ foo }}", foo="<test>") == "<test>" 105 assert flask.render_template("mail.txt", foo="<test>") == "<test> Mail" 106 107 108def test_macros(app, req_ctx): 109 macro = flask.get_template_attribute("_macro.html", "hello") 110 assert macro("World") == "Hello World!" 111 112 113def test_template_filter(app): 114 @app.template_filter() 115 def my_reverse(s): 116 return s[::-1] 117 118 assert "my_reverse" in app.jinja_env.filters.keys() 119 assert app.jinja_env.filters["my_reverse"] == my_reverse 120 assert app.jinja_env.filters["my_reverse"]("abcd") == "dcba" 121 122 123def test_add_template_filter(app): 124 def my_reverse(s): 125 return s[::-1] 126 127 app.add_template_filter(my_reverse) 128 assert "my_reverse" in app.jinja_env.filters.keys() 129 assert app.jinja_env.filters["my_reverse"] == my_reverse 130 assert app.jinja_env.filters["my_reverse"]("abcd") == "dcba" 131 132 133def test_template_filter_with_name(app): 134 @app.template_filter("strrev") 135 def my_reverse(s): 136 return s[::-1] 137 138 assert "strrev" in app.jinja_env.filters.keys() 139 assert app.jinja_env.filters["strrev"] == my_reverse 140 assert app.jinja_env.filters["strrev"]("abcd") == "dcba" 141 142 143def test_add_template_filter_with_name(app): 144 def my_reverse(s): 145 return s[::-1] 146 147 app.add_template_filter(my_reverse, "strrev") 148 assert "strrev" in app.jinja_env.filters.keys() 149 assert app.jinja_env.filters["strrev"] == my_reverse 150 assert app.jinja_env.filters["strrev"]("abcd") == "dcba" 151 152 153def test_template_filter_with_template(app, client): 154 @app.template_filter() 155 def super_reverse(s): 156 return s[::-1] 157 158 @app.route("/") 159 def index(): 160 return flask.render_template("template_filter.html", value="abcd") 161 162 rv = client.get("/") 163 assert rv.data == b"dcba" 164 165 166def test_add_template_filter_with_template(app, client): 167 def super_reverse(s): 168 return s[::-1] 169 170 app.add_template_filter(super_reverse) 171 172 @app.route("/") 173 def index(): 174 return flask.render_template("template_filter.html", value="abcd") 175 176 rv = client.get("/") 177 assert rv.data == b"dcba" 178 179 180def test_template_filter_with_name_and_template(app, client): 181 @app.template_filter("super_reverse") 182 def my_reverse(s): 183 return s[::-1] 184 185 @app.route("/") 186 def index(): 187 return flask.render_template("template_filter.html", value="abcd") 188 189 rv = client.get("/") 190 assert rv.data == b"dcba" 191 192 193def test_add_template_filter_with_name_and_template(app, client): 194 def my_reverse(s): 195 return s[::-1] 196 197 app.add_template_filter(my_reverse, "super_reverse") 198 199 @app.route("/") 200 def index(): 201 return flask.render_template("template_filter.html", value="abcd") 202 203 rv = client.get("/") 204 assert rv.data == b"dcba" 205 206 207def test_template_test(app): 208 @app.template_test() 209 def boolean(value): 210 return isinstance(value, bool) 211 212 assert "boolean" in app.jinja_env.tests.keys() 213 assert app.jinja_env.tests["boolean"] == boolean 214 assert app.jinja_env.tests["boolean"](False) 215 216 217def test_add_template_test(app): 218 def boolean(value): 219 return isinstance(value, bool) 220 221 app.add_template_test(boolean) 222 assert "boolean" in app.jinja_env.tests.keys() 223 assert app.jinja_env.tests["boolean"] == boolean 224 assert app.jinja_env.tests["boolean"](False) 225 226 227def test_template_test_with_name(app): 228 @app.template_test("boolean") 229 def is_boolean(value): 230 return isinstance(value, bool) 231 232 assert "boolean" in app.jinja_env.tests.keys() 233 assert app.jinja_env.tests["boolean"] == is_boolean 234 assert app.jinja_env.tests["boolean"](False) 235 236 237def test_add_template_test_with_name(app): 238 def is_boolean(value): 239 return isinstance(value, bool) 240 241 app.add_template_test(is_boolean, "boolean") 242 assert "boolean" in app.jinja_env.tests.keys() 243 assert app.jinja_env.tests["boolean"] == is_boolean 244 assert app.jinja_env.tests["boolean"](False) 245 246 247def test_template_test_with_template(app, client): 248 @app.template_test() 249 def boolean(value): 250 return isinstance(value, bool) 251 252 @app.route("/") 253 def index(): 254 return flask.render_template("template_test.html", value=False) 255 256 rv = client.get("/") 257 assert b"Success!" in rv.data 258 259 260def test_add_template_test_with_template(app, client): 261 def boolean(value): 262 return isinstance(value, bool) 263 264 app.add_template_test(boolean) 265 266 @app.route("/") 267 def index(): 268 return flask.render_template("template_test.html", value=False) 269 270 rv = client.get("/") 271 assert b"Success!" in rv.data 272 273 274def test_template_test_with_name_and_template(app, client): 275 @app.template_test("boolean") 276 def is_boolean(value): 277 return isinstance(value, bool) 278 279 @app.route("/") 280 def index(): 281 return flask.render_template("template_test.html", value=False) 282 283 rv = client.get("/") 284 assert b"Success!" in rv.data 285 286 287def test_add_template_test_with_name_and_template(app, client): 288 def is_boolean(value): 289 return isinstance(value, bool) 290 291 app.add_template_test(is_boolean, "boolean") 292 293 @app.route("/") 294 def index(): 295 return flask.render_template("template_test.html", value=False) 296 297 rv = client.get("/") 298 assert b"Success!" in rv.data 299 300 301def test_add_template_global(app, app_ctx): 302 @app.template_global() 303 def get_stuff(): 304 return 42 305 306 assert "get_stuff" in app.jinja_env.globals.keys() 307 assert app.jinja_env.globals["get_stuff"] == get_stuff 308 assert app.jinja_env.globals["get_stuff"](), 42 309 310 rv = flask.render_template_string("{{ get_stuff() }}") 311 assert rv == "42" 312 313 314def test_custom_template_loader(client): 315 class MyFlask(flask.Flask): 316 def create_global_jinja_loader(self): 317 from jinja2 import DictLoader 318 319 return DictLoader({"index.html": "Hello Custom World!"}) 320 321 app = MyFlask(__name__) 322 323 @app.route("/") 324 def index(): 325 return flask.render_template("index.html") 326 327 c = app.test_client() 328 rv = c.get("/") 329 assert rv.data == b"Hello Custom World!" 330 331 332def test_iterable_loader(app, client): 333 @app.context_processor 334 def context_processor(): 335 return {"whiskey": "Jameson"} 336 337 @app.route("/") 338 def index(): 339 return flask.render_template( 340 [ 341 "no_template.xml", # should skip this one 342 "simple_template.html", # should render this 343 "context_template.html", 344 ], 345 value=23, 346 ) 347 348 rv = client.get("/") 349 assert rv.data == b"<h1>Jameson</h1>" 350 351 352def test_templates_auto_reload(app): 353 # debug is False, config option is None 354 assert app.debug is False 355 assert app.config["TEMPLATES_AUTO_RELOAD"] is None 356 assert app.jinja_env.auto_reload is False 357 # debug is False, config option is False 358 app = flask.Flask(__name__) 359 app.config["TEMPLATES_AUTO_RELOAD"] = False 360 assert app.debug is False 361 assert app.jinja_env.auto_reload is False 362 # debug is False, config option is True 363 app = flask.Flask(__name__) 364 app.config["TEMPLATES_AUTO_RELOAD"] = True 365 assert app.debug is False 366 assert app.jinja_env.auto_reload is True 367 # debug is True, config option is None 368 app = flask.Flask(__name__) 369 app.config["DEBUG"] = True 370 assert app.config["TEMPLATES_AUTO_RELOAD"] is None 371 assert app.jinja_env.auto_reload is True 372 # debug is True, config option is False 373 app = flask.Flask(__name__) 374 app.config["DEBUG"] = True 375 app.config["TEMPLATES_AUTO_RELOAD"] = False 376 assert app.jinja_env.auto_reload is False 377 # debug is True, config option is True 378 app = flask.Flask(__name__) 379 app.config["DEBUG"] = True 380 app.config["TEMPLATES_AUTO_RELOAD"] = True 381 assert app.jinja_env.auto_reload is True 382 383 384def test_templates_auto_reload_debug_run(app, monkeypatch): 385 def run_simple_mock(*args, **kwargs): 386 pass 387 388 monkeypatch.setattr(werkzeug.serving, "run_simple", run_simple_mock) 389 390 app.run() 391 assert not app.templates_auto_reload 392 assert not app.jinja_env.auto_reload 393 394 app.run(debug=True) 395 assert app.templates_auto_reload 396 assert app.jinja_env.auto_reload 397 398 399def test_template_loader_debugging(test_apps, monkeypatch): 400 from blueprintapp import app 401 402 called = [] 403 404 class _TestHandler(logging.Handler): 405 def handle(self, record): 406 called.append(True) 407 text = str(record.msg) 408 assert "1: trying loader of application 'blueprintapp'" in text 409 assert ( 410 "2: trying loader of blueprint 'admin' (blueprintapp.apps.admin)" 411 ) in text 412 assert ( 413 "trying loader of blueprint 'frontend' (blueprintapp.apps.frontend)" 414 ) in text 415 assert "Error: the template could not be found" in text 416 assert ( 417 "looked up from an endpoint that belongs to the blueprint 'frontend'" 418 ) in text 419 assert "See https://flask.palletsprojects.com/blueprints/#templates" in text 420 421 with app.test_client() as c: 422 monkeypatch.setitem(app.config, "EXPLAIN_TEMPLATE_LOADING", True) 423 monkeypatch.setattr( 424 logging.getLogger("blueprintapp"), "handlers", [_TestHandler()] 425 ) 426 427 with pytest.raises(TemplateNotFound) as excinfo: 428 c.get("/missing") 429 430 assert "missing_template.html" in str(excinfo.value) 431 432 assert len(called) == 1 433 434 435def test_custom_jinja_env(): 436 class CustomEnvironment(flask.templating.Environment): 437 pass 438 439 class CustomFlask(flask.Flask): 440 jinja_environment = CustomEnvironment 441 442 app = CustomFlask(__name__) 443 assert isinstance(app.jinja_env, CustomEnvironment) 444