Unit tests for checking content that is rendered in template - unit-testing

I was browsing a little and was not able to find any solutions for something I want to accomplish.
I am in Symofny 5 project and I am writing some Unit tests.
The goal of my tests is to check, if the messages will appear as they are defined. The messages are rendered by the twig template. I am not that familiar with Symfony and twig regrading to tests. I do not know, if I somehow can render the output of a view using that twig template for just that entry and then check, if the message contains the expected text in the right manor.
Is it something like this doable?
Can some help and give me guidance as example for something like this?
I think it can be beneficial to other coders out there in the future.
I have an entity like User, than want to get the status, like:
$user->getStatus('ready);
in twig:
{% if item.status == 'ready' %}
<p>The status of user is {{ item.status }}</p>
{% endif %}
So, I want to assert that twig templates are rendering correct output for given status.

Update 2:
According to your comment, you are probably trying to test multiple things at once. While not inherently bad, it's probably not what you would call Unit Test. In the ideal application, you want to separate your data persistence logic from the rendering logic completely.
I cannot provide you with any meaningful code sample without knowing what you want to do, but I can give you some general pointers:
You can test your persistence logic by itself without twig. If you want to test if your data correctly persists with some default values, you can simply assert the objects retrieved from the database.
Inversely, if you need to check your template being rendered correctly, you can mock all the data you need, provide dummy objects and such, everything should work the same.
If you really want to bring it all together and test the application as a whole, then you should look into proper integration tests that actually call your endpoints with proper HTTP Requests and assert received HTTP Responses.
Update 1: I've updated the example according to your updated question
I am not exactly sure what are you trying to accomplish exactly, but it seems that you want to assert that twig templates are rendered correctly.
First, you need to figure out the end result. First let's assume your template is:
<html>
{% if user.status is not empty %}
<p>The status of user is {{ user.status }}</p>
{% endif %}
</html>
Then your test code would be something like this:
public function testTwigRender(): void
{
$expected=<<<'EXPECTED'
<html>
<p>The status of user is ready</p>
</html>
EXPECTED;
$user = new User();
$user->setStatus('ready');
$twig = self::$kernel->getContainer()->get('twig');
$actual = $twig->render('AppBundle::app/template.html.twig', ['user' => $user]);
self::assertEquals($expected, $actual);
}

Related

Avoid duplication in Django when having to format a message both in a template and as a response from an ajax call

I have a chat board where people can post messages that can include attachments and some other additional things. When I retrieve all messages I loop over them and display each message in this way (simplified):
<p>Message posted by: <strong>{{ details.name }}</strong></p>
<p>{{ details.message }}</p>
<ul>
{% foreach attachment in attachments %}
<li>{{ attachment }}</li>
</ul>
{% endforeach %}
So far, so good. Now, my difficulty is that I use AJAX to allow people to post new message. Upon adding a new message, I struggle to find the best way to show this message to the user. The problem is that the new message needs to be formatted in a particular way (the above is a simplification; there are various conditions and additional formats). I can think of three ways:
I use javascript to parse the message. That means I basically have the same code twice, in two different languages (once in Django's template language for all existing message, and then again in js for newly added messages)
I craft the exact same HTML code in the view, so when I return a response through AJAX it already includes properly formatted code. However, this will also be a duplication of code - once in the template itself and again in the view
I create a new function within the model that creates all the right HTML code (say formatMessage()). When I loop over existing messages, I can call this function, and when I add a new message I can call the same function and return this in my response.
The last option is the only one that does not have duplicated code. However, it would introduce a whole lot of code including HTML code to my modal, which seems like an awful thing to do.
Any advice?
There's no reason you can't use a template in an Ajax response. You can extract this template fragment into its own template file and either render it directly, in the case of the Ajax response, or include it in another template for a normal page view.

How to set a session variable in a HTML template in Django?

I'm trying to set value to Django session within the template and then posible used in the view.
I'm doing something like this
{% block body %}
<html>
{% request.session.fav_color="red" %}
<div> Is your favorite color {{ request.session.fav_color}} ?</div>
</html>
{% endblock %}
There are several reasons why this may not be a good idea:
Templates should deal with presentation only. If you are placing logic in the template it is supposed to be presentation logic. Placing business logic in the template is a violation of the SoC (separation of concerns).
Rendering the template often is one of the last things you do in a view so it is hard to get the cat back in the bag if you have already sent the data to the browser (and if you rendered the template but haven't sent data down the pipe you can just update the value in the view instead of trying to do it in the template).
If you are interacting with the user the traditional way to do it is using a form (even if it is a form with only the submit button) - or posting data to the server in the frontend using AJAX.

simple application pass value from django views to javascript

It has been 2day i am trying to figure out how to do that. I am a novice so please give as detailed explanation as possible.
I am doing this in my views.py
dict1 = simplejson.dumps(dict1)
return render_to_response('main_page.html', {
'js_testsuite':testsuite_dict,
'js_testset':js_testset,
'dict1':dict1})
In main_page.html
{% if js_testsuite %}
<select id="testsuites" name="testsuite" onchange="setOptions(document.selection.testsuite.selectedIndex);">
{% for key, value in js_testsuite.items %}
<option value={{ value }} name="testsuite">{{ key }}</option>
{% endfor %}
</select>
{% endif %}
In setoptions.js, which contains the function setOptions(value), to which i am passing selected index of the select box, and using this value i have to set the second select box and the data for this select box has to come from the views.py given above.
Also, I tried doing
var value_from_django = {{ dict1 }};
what are the other things im missing. Could you please provide a detailed explanation on this. I had been trying this for 2 days.
Is there a way in which I can pass the value from django views to the javascript directly bypassing the django template?
Can I pass the information from django views to the html template and then to the javascript?
The javascript I am referring to is a simple javascript not jquery.
Thanks for your support,
Vinay
You cannot pass values to javascript bypassing the template, unless you use an ajax call to start a separate request or unless you do something very unusual like embedding the data in a response header (don't actually do this, it is not what response headers are for!). The response, which includes the header and the body (the body being the part generated by the template) is the sum total of the information your application provides to your client, so unless you generate an additional request and fetch an additional response with ajax, you have no other options.
If you don't want to do that, then your options for passing information to the javascript via the template are basically the following:
Using an inline tag, create properly formatted javascript dynamically via the templating system. The example line you have, var value_from_django = {{ dict1 }}; is essentially what I'm talking about here, except that I'm not sure you can pass a dict through from django to javascript like that, because django's text output of a dict in the template is unlikely to be exactly the correct formatting for a javascript variable declaration. So, instead you can...
Translate your data into JSON and put that into your template, and then process that with the javascript. (This is usually done with an ajax call, but there's nothing stopping you from injecting the JSON data into the initial template directly.)
Or populate your HTML with the data you want and then use javascript to locate the HTML tag containing the data and parse the data out.
If you are trying to pass simple variables like integers, it might be easiest to do it with the first or third options. If you are trying to pass a more complex data structure like a dictionary, you will probably be better off using JSON (that's what it's for!)
I would like to give you more detailed and concrete instructions, but for that you will need to post more detail about what exactly is going wrong with your current approach and what your desired functionality is.
By the way: if it is at all feasible to include jquery on this page and use that instead of trying to use basic javascript, you should do so. It will make your life much, much easier.

Django partial template responses

Is it considered correct/ are there any pitfalls in returning partial templates to ajax POST requests?
For example:
if request.is_ajax:
# response is just the form
return render(request, 'contact/fields.html', {'form':form})
The most typical approach is returning JSON and then contructing whatever HTML you need client-side from the JSON data. However, it could be argued that this is mixing presentation with behavior and it would be better to clearly separate out the HTML.
On the flip-side, returning a block of HTML is about as polar-south of "RESTful" as you can get. In pure REST philosophy, the views should return data in a standard and reusable container (such as JSON or XML). Later if you needed to pull the form into an iOS/Android/WP7/etc. app environment rather than a webpage, the JSON/XML will serve you just as well, whereas the HTML is virtually useless.
I can easily see both arguments, and I don't think one is necessarily more right than the other. Ultimately, I think you just have to do what works best for your app and what "feels right" to you. Think in terms of what is more maintainable and extensible for your particular circumstances.
I have no yet tried this with form POST request but very similarly we return partial HTML to AJAX GET request to do page changes without loading the whole page. I think it would work well for form request as well (we are in fact debating at the moment whether to use this approach on a page with multiple different forms).
I think if done right it is not a bad design pattern. We accomplish this by changing which base template is extended based on whether it was an AJAX call.
A simplified example:
### view
base_template = "base.html"
if request.is_ajax():
base_template = "base-ajax.html"
return render_to_response(request, 'page.html', {'base_template': base_template})
### page.html
{% extends base_template %}
{% block main %}new page content{% endblock %}
### base.html
<html>
<!-- complete html page -->
...
{% block main %}this is what changes per page{% endblock %}
...
</html>
### base-ajax.html
{% block main %}this is what changes per page{% endblock %}
I think most of my ajax return responses return DOM elements and not the entire form.
(an example)
...
person = ''' {1} {2}'''.format(p.id, p.first_name, p.last_name)
q = simplejson.dumps({"person":person})
return HttpResponse(q, mimetype="application/json")
The above sends back a simple DOM element to the template and inserts it into a table at the bottom. Sliding in right to left.
If you send back the entire template, the entire screen will flash and won't get any slick animations. That is my understanding anyway.
I have done this for a couple of jQuery Dialogs. The dialog contents are requested by a AJAX request, the contents are rendered on server side and then returned and displayed. So far I have experienced no problems with that.
From personal experience i can say that there is no pitfalls. I just not very good design pattern (not good practice). I used to do that on pretty high loaded project.
I have had the same problem in the year 2023 (question was asked in 2012..). Django still doesn't support rendering a template without invoking the whole chain of template inheritance.
So here's a basic way of rendering partial template:
from django.template import Context, loader
def render_template_to_string(template_name, context=None):
template = loader.get_template(template_name).template
context_instance = Context(context or {})
with context_instance.bind_template(template):
return template.nodelist.render(context_instance)
And your (partial) template can be as simple as:
<ul>my partial list
{% for opt in options %}
<li>{{ opt }}</li>
{% endfor %}
</ul>
You then invoke it by e.g.
from django.http import HttpResponse
resp = render_template_to_string(
"path/to/partial/html", {"options": range(10)}
)
return HttpResponse(resp)
FYI you might want to add support for some node exclusions, error handling, or better flexibility of what gets passed to render_template_to_string.

Infinite scroll in django

Is it possible to implement facebook style loading of content while scrolling down? I would like to implement it in an ecommerce site. There are a lot of items in each category and the category page becomes too long. I could implement page numbers but my client wants me to implement that facebook type of loading. Is there anything I can use? Rest of the site has already been built.
I did look into django-endless-pagination but was not able to get it to work. Is there any demo of it so that I can look into it?
We used django endless pagination on www.mymommemories.com without too much problem. Because we were using html5media we did have to add a line to run that function with a one second delay. (setTimeOut("html5media()", 1000). Running it without the delay caused problems in some browsers. If your not using html5media, this should not be a concern however.
Core part of the template code.
{% load endless %}
{% paginate memories %}
{% for memory in memories %}
.
.
.
{% endfor %}
{% show_more %}
In the view we have the following to handle the ajax request.
if request.is_ajax():
template = page_template
return render_to_response(template,context,context_instance=RequestContext(request))
The page_template is not the whole page, just the portion related to the "paging".
I thinks the easiest way to do endless pagination is use jQuery (use $.loads).
You even don't need change the back-end code.
http://www.infinite-scroll.com/infinite-scroll-jquery-plugin/
Perhaps take a look at that?