testing 'POST' and 'GET' methods in flask - unit-testing

I currently have an app that crudely posts information from a registration page to my admin page. The posted information is in a table. I would like to make a test that actually checks whether any information has been picked from my registration form and posted to the table in my admin page
app.py code
#app.route('/register_user')
def register_user():
return render_template('register_user.html')
#app.route('/manage_admin', methods=['POST', 'GET'])
def manage_admin():
if request.method == 'POST':
manage_admin = request.form
return render_template('manage_admin.html', manage_admin=manage_admin)
register_user.html
<form id="form-login" method="post" action="/manage_admin">
<input type="text" class="input100" name="name" placeholder="fullname">
<br>
<br>
<input type="text" class="input100" name="username" placeholder=" username">
<br>
<br>
<input type="text" class="input100" name="email" placeholder="email">
<br>
<br>
<input type="password" class="input100" name="password" placeholder="password">
<br>
<br>
<br>
<input type="submit" class="login-button" value="Submit">
</form>
manage_admin.html
{% for key, value in manage_admin.items() %}
<th>{{ value }}</th>
{% endfor %}

I'd recommend using something like Selenium to run automated tests. This will let you perform tests against a live instance of your application.
To get started, install Selenium:
pip install selenium
Then, create a script to run your tests, by importing the Selenium Webdriver along with unittest from the Python standard library:
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class TestRegistrationPage(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
def tearDown(self):
self.driver.quit()
def test_form_posts_to_admin_page(self):
self.driver.get('http://localhost:5000/register_user') # Assuming default Flask port
# Retrieve input elements
name_input = self.driver.find_element_by_name('name')
username_input = self.driver.find_element_by_name('username')
email_input = self.driver.find_element_by_name('email')
password_input = self.driver.find_element_by_name('password')
# Populate inputs with dummy text
name_input.send_keys('Alice Cooper')
username_input.send_keys('acoop')
email_input.sendkeys('acoop#schoolsoutforever.com')
password_input.sendkeys('rockonbaby')
# Find submit button and submit form by sending an "Enter" keypress
submit_button = self.driver.find_element_by_class_name('login-button')
submit_button.send_keys(Keys.ENTER)
# Check if redirect worked. If you don't redirect from the form page the just use the driver.get method above with the target url instead
admin_url = self.driver.current_url
self.assertEqual(admin_url, 'http://localhost:5000/manage_admin')
# Get table header elements and extract their text values
table_cells = self.driver.find_elements_by_tag_name('th')
table_contents = []
for cell in table_cells:
table_contents.append(cell.text)
# Check if dummy text made it into the table contents
self.assertIn('Alice Cooper', table_contents)
self.assertIn('acoop', table_contents)
self.assertIn('acoop#schoolsoutforever.com', table_contents)
self.assertIn('rockonbaby', table_contents)
# Tell unit tests to run when you run the script
if __name__ == '__main__':
unittest.main()
If you encounter any issues with the elements not being found, it could be a page load time issue. In this case, you may need to force a wait if rerunning the tests don't work. For info on doing so, see this answer and the Selenium Waits documentation.

Simple solution, if you can parse the html yourself:
app.test_client().post('/manage_admin', data={'name': 'John Doe', 'username': 'jdoe', ...}))
It returns a Response, from which you can get the html, and check the contents however you like. I've used python's built-in parser for example.

Related

Unable to check if radio button is selected or not: Django

I am unable to verify if the radio button I have placed in django templates is check or not. Given below are the HTML and views.py file:
HTML:
<div class="col-xs-1 col-sm-1 checkbox" style="margin-left:5px">
<p class="control-label"><strong>Backlog</strong></p>
<input type="radio" name="backorNor" value="1">
</div>
views.py:
def get_data(request):
choice_of_query = request.POST.get("backorNor");
if choice_of_query == "1":
mssql_qu = cq_query_backlog.mssql_query.format(sql_product,sql_state,sql_version_reported,sql_op1_drs)
else:
mssql_qu = cq_query.mssql_query.format(sql_product,sql_state,sql_version_reported,sql_op1_drs)
cq_query_backblog and cq_query are two sql files which I need to run if the radiobutton is checked or not respectively.
upon printing the type of choice_of_query, I am getting None
Where am I going wrong? Any help is appreciated.

Send JSON from Places Autocomplete to Flask

I'm working on my very first web app utilizing the Google Places Autocomplete functionality in the frontend and Flask in the backend.
Current situation:
Whenever an address is selected from the autocomplete suggestions, a variable called 'address' is populated in the background containing the API response as JSON. Using a window alert I can confirm that this part works fine.
To-Do/ issue:
The address variable should be sent over to Flask so that I can do use it going forward.
Using AJAX to post the data however it never seems to reach Flask. The output is always None.
My best guess is that the submit button implemented after the Autocomplete stuff somehow overrides the JSON POST data in order to keep only the actual text which is in the form while submitting*.
Does that make sense? If yes, how can I still send the JSON data successfully? Or is the issue somewhere else?
I would appreciate any help.
Here is my code:
home.html
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
{% from "_formhelpers.html" import render_field %}
<div class="container">
<form class="form form-horizontal" action="" method="post" role="form" novalidate>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=key&libraries=places&language=en"></script>
<script type="text/javascript">
google.maps.event.addDomListener(window, 'load', function () {
var autocomplete = new google.maps.places.Autocomplete(document.getElementById('autocomplete'),{
types: ['geocode']
});
// autocomplete.setFields('address_components');
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var place = autocomplete.getPlace();
var address = place.address_components;
window.alert(JSON.stringify(address));
}
)})
$.ajax({
type: "POST",
url: "/",
data: address,
success: function(){},
dataType: "json",
contentType : "application/json"
});
</script>
<input type="text" id="autocomplete" size=50 style="width: 250px" placeholder="Enter your location" name=inputkiez>
<a href=# id=autocomplete><button class='btn btn-default'>Submit</button></a>
</form>
<div class="row">
or check out <a href='/result'> the latest reviews from others </a>
<div>
</div>
{% endblock %}
routes.py
#app.route('/', methods=['GET','POST'])
def search():
if request.method == 'POST':
jsdata = request.get_json()
flash('Data is: {}'.format(jsdata))
return redirect('/review')
return render_template('home.html')
#app.route('/review', methods=['GET', 'POST'])
def review():
reviewform = ReviewForm()
if reviewform.validate_on_submit():
userreview = Reviews(
reviewcriteria1= reviewform.reviewcriteria1.data,
reviewcriteria2= reviewform.reviewcriteria2.data,
reviewcriteria3= reviewform.reviewcriteria3.data,
)
db.session.add(userreview)
db.session.commit()
return redirect('/result')
return render_template('review.html', form=reviewform)
*The text in the form would include the address selected from Autocomplete but without any additional data obviously. I even managed to pass this text to the next page with request.form.to_dict() but this is not good enough for my use case since I also want at least the postal code to be sent over.
This is not the exact answer to my question but I found a way to send over the data to flask without having to bring in JSON/AJAX at all.
The trick is to send the data from the Autoplaces response as a hidden input of the form:
<form method="post" action="">
<input id="userinput" placeholder="Enter a location" type="text" name="name" class="form-control"><br>
<div id="map" style="height: 300px;width: 300px; float: none; margin: 0 auto;"></div><br>
<input type="hidden" name="address" id="address">
<input type="submit" name="submit" value="Submit" class="form-control btn btn-primary">
<div>or check out <a href='/result'> the latest reviews from others </a></div>
</form>
Then in routes.py you can easily get the data like this:
#app.route('/', methods=['GET','POST'])
def search():
if request.method == 'POST':
address = request.form['address']
# do something
This is basically a slightly modified version of the solution posted here (YT video).

Custom `password_reset_confirm.html` template won't redirect to `password_reset_complete` view

I made a custom password_reset_confirm.html template. But when a user enters a new password and hits submit, the browser does not redirect to the admin view password_reset_complete.
Here's the form I made in the custom password_reset_confirm.html template:
<div ng-app="app" ng-controller="Ctrl">
<form id="reset-pw-confirm-form" name="newPWForm" method="post" action="">
{% csrf_token %}
<input
id="id_new_password1"
type="[[[ newPW.showPW ? 'text' : 'password' ]]]"
name="new_password1"
ng-model="newPW.pw"
ng-minlength="8"
ng-maxlength="32"
required>
<button class="btn btn-primary" type="submit" ng-disabled="!newPW.pw">Submit</button>
<input
id="id_new_password2"
type="hidden"
value="[[[ newPW ]]]"
name="new_password2"
ng-model="newPW"
ng-minlength="8"
ng-maxlength="32"
required>
</form>
</div>
When I fill out the password and hit submit, the browser sends a POST request to the same URL it landed on, but the page seems to just refresh with nothing changed. The user's password remains unchanged. It seems Django's auth/views.py did not execute properly.
In that view, there's this code:
if post_reset_redirect is None:
post_reset_redirect = reverse('password_reset_complete')
else:
post_reset_redirect = resolve_url(post_reset_redirect)
When I have the view print post_reset_redirect, it prints None. Could this be the issue?
How can I make my custom template compatible with Django's password_reset_confirm view?
When you specifies "action" attribute for the form it will be used as your link for data sending so probably your logic isn't handled. Try to remove it and check you js files that the data is sent to the the specified link.
Also please check all required parameters for the password_reset_confirm
https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/views/
My hidden input's value and ng-model attributes needed to be set to newPW.pw.

pass variable through url to view

I want to pass my input text value through url when i click my submit button.
views.py
def profile(request,username):
current_user = User.objects.filter(username=username)
return render_to_response ('profiles/search.html', {'current_user':current_user,
context_instance=RequestContext(request),)
search.html
<form action="{%url 'profiles:profile' username=user.username %}" id="search_by_username" method ="get">
<input type="text" name = "searchname" class="text" placeholder="Search by username" />
<input type="submit" value="button" />
</form>
urls.py
url(r'^view/(?P<username>\w+)/$', views.profile, name="profile"),
after clicking the submit button ,Iam getting a url like this:
192.168.1.33:8000/profiles/view/abraham/?searchname=merlin
Here abraham is the loggin user but actually i need to search for merlin.So how can i replace abraham by merlin.
You can't get a form field to automatically put its value into the URL the form is submitting to (except by mucking about with the form in Javascript, which would be horrible).
But as you can see, you do get that data in the request parameters: since you're doing a GET, it's in request.GET['searchname']. So why don't you drop the username parameter to the URL/view in the first place, and just use that?

Existing forms:In Django

I have an pre-built HTML form and I need to reuse it with Django form class (django.forms), So how do I incorporate my HTML form with Django form class. for example
HTML:
<li id="foli11" class="">
<label class="desc" id="title11" for="Field11">
Username
<span id="req_0" class="req">*</span>
</label>
<div class="col">
<input id="Field11" name="Field11" type="text" class="field text medium" value="" maxlength="255" tabindex="11" />
</div>
</li>
How do I map this HTML in to Django form class, I know that it can be done by modifying Django form fields according to this HTML. But I guess it's a time consuming approach,so I would like to know that is there any easy and time saving solutions for this issue.
Thanks.
Extend the django forms.Form class and write to it your own form.as_my_ul similar to form.as_p:
Here is the implementation of as_p: http://code.djangoproject.com/browser/django/trunk/django/forms/forms.py#L227
def as_p(self):
"Returns this form rendered as HTML <p>s."
return self._html_output(
normal_row = u'<p%(html_class_attr)s>%(label)s %(field)s%(help_text)s</p>',
error_row = u'%s',
row_ender = '</p>',
help_text_html = u' %s',
errors_on_separate_row = True)