How to unit test submit a form when multiple forms are on the route?

I want to add unit tests to my flash application that checks the behavior of a form on valid and invalid inputs + registrations. Currently, I have a registration form and a login form located on one page and a route, and I use a hidden input field to determine which of the two forms is submitted / will determine the following actions.

My question is: how to write a unit test that is designed for a specific form on a page? All the examples I've seen so far send data along a specific route, which I am currently doing. But this fails because I need an additional way to say "and we submit the x-form."

So, is there a way to add β€œand we send the x-form” in the mail request?

** Edited to add, here are a few ways I tried to pass hidden form data into dict data data, without any success.

data = dict(username=" test@gmail.com ", password="test", login_form) data = dict(username=" test@gmail.com ", password="test", "login_form") data = dict(username=" test@gmail.com ", password="test", login_form=True) 

login unit test:

 from app import app import unittest class FlaskTestCase(unittest.TestCase): #ensure that login works with correct credentials def test_correct_login(self): tester = app.test_client(self) response = tester.post( '/login', data = dict(username=" test@gmail.com ", password="test"), follow_redirects=True ) self.assertIn(b'you are logged in', response.data) 

view.py entry route:

 @app.route('/login', methods=['POST', 'GET']) def login(): login_form = LoginForm() signup_form = SignupForm() error_login = '' error_signup = '' #login form if 'login_form' in request.form and login_form.validate(): # do login form stuff #signup form if 'signup_form' in request.form and signup_form.validate(): # do signup form stuff return render_template('login.html', login_form=login_form, signup_form=signup_form, error=error) 

login.html:

 <div class="login-form form-400"> <h3>Log In To Your Account</h3> <form action="" method="post"> <input type="hidden" name="login_form"> {% if error_login != '' %} <label class="error"> {{ error_login }} </label> {% endif %} {% from "_formhelper.html" import render_field %} {{ login_form.hidden_tag() }} {{ render_field(login_form.email, placeholder="Your Email", class="form-item__full", type="email") }} {{ render_field(login_form.password, placeholder="Your Password", class="form-item__full") }} <input type="submit" value="Login" class="button button-blue"> </form> </div> <p class="login-divider">or</p> <div class="signup-form form-400"> <h3>Create a New Account</h3> <form action="" method="post"> <input type="hidden" name="signup_form"> {% if error_signup != '' %} <label class="error"> {{ error_signup | safe}} </label> {% endif %} {% from "_formhelper.html" import render_field %} {{ signup_form.hidden_tag() }} {{ render_field(signup_form.username, placeholder="Pick a Username", class="form-item__full") }} {{ render_field(signup_form.email, placeholder="Your Email", class="form-item__full", type="email") }} {{ render_field(signup_form.password, placeholder="Create a Password", class="form-item__full") }} <input type="submit" value="Sign Up" class="button button-green"> </form> </div> 
+5
source share
3 answers

Ok, I figured it out. In order to pass login_form information, I had to finish passing the empty string to login_form as follows:

 def test_correct_login(self): tester = app.test_client(self) response = tester.post( '/login', data = dict(username=" test@gmail.com ", password="test", login_form=""), follow_redirects=True ) self.assertIn(b'you are logged in', response.data) 

I did this by throwing print request.form into my views.py for this route, and then saw an empty line.

It still failed, but because of the failure of login_form.validate() due to the csrf token added by the WTForms module. In the end, this discussion got the answer. Flask-WTF / WTForms with Unittest does not validate, but works without Unittest

Thanks @drdrez for your suggestions!

+2
source

Update: Thank you for updating your question so that you have already tried! I have a few more ideas on what causes the problem.

Let's continue to look at HTML and try to understand the technologies that your program is built on top of. In the server-side login.html file, note the following lines:

  {% from "_formhelper.html" import render_field %} {{ login_form.hidden_tag() }} {{ render_field(login_form.email, placeholder="Your Email", class="form-item__full", type="email") }} {{ render_field(login_form.password, placeholder="Your Password", class="form-item__full") }} 

This is not HTML and is probably handled by the server to generate HTML code and serve the client. The line containing login_form.hidden_tag() looks interesting, so I would recommend loading this page in your browser and checking the HTML code served by the client. Unfortunately, I have not used Flask before, so I cannot give any direct help.

However, my advice is to continue working on how Flask and HTML Form work. The best part is in Python: you have access to the source code of the libraries, which allows you to figure out how they work so that you can learn how to use them and fix errors in your application that uses them.

Sorry, I can’t give you more direct help, good luck!


Take a look at login.html. When you submit a form, how does the entry route to view.py know which form was submitted? If you know HTML forms, the <input> elements embedded in the form are used to send data to your server / application in this case.

Return to login.html, pay attention to the following two lines:

 ... <h3>Log In To Your Account</h3> <input type="hidden" name="login_form"> ... <h3>Create a New Account</h3> <form action="" method="post"> <input type="hidden" name="signup_form"> ... 

These are <input> elements of type "hidden", so they will not be displayed with the names "login_form" and "signup_form", which are included in the data that the form submits.

Now on the entry path to view.py you will see two lines:

  #login form if 'login_form' in request.form and login_form.validate(): # do login form stuff #signup form if 'signup_form' in request.form and signup_form.validate(): # do signup form stuff 

Those test to see if the phrase "login_form" or "signup_form" is in the request.form list. Let's get back to your unit test now:

  response = tester.post( '/login', data = dict(username=" test@gmail.com ", password="test"), follow_redirects=True ) 

Pay attention to the data that you pass in the dict , this simulates the form data, so you should probably include either "login_form" or "signup_form" to correctly simulate the behavior of the HTML form.

If you are not familiar with HTML forms and HTTP messages, I would suggest looking for some tutorials or just reading the documentation on MDN or elsewhere. When creating software on top of technology (like HTTP and HTML) it may be useful to understand how these technologies work when running bugs in your own software.

Hope this helps, let me know if I can clarify anything!

+1
source

You may have a problem because you have not noted that the request is a type of application form content. I note that you are trying to access request.form, which requires the data packet to be parsed in a certain way. You can try to do something like the following:

  response = tester.post( '/login', data = dict(username=" test@gmail.com ", password="test"), follow_redirects=True, headers = {"Content-Type":"application/x-www-form-urlencoded"} ) 
0
source

All Articles