I'm trying to write tests to see if a form is posting data properly. Specifically I'm trying to test that form data (name and phone_number) are being sent to a contact info form for takeout. I keep running into an error that I think is due to the fact I'm using FormField and I'm not sure what the correct data to send is.
I'm using python unittest for a Flask application I'm writing that is supposed to be a mock Order Management System.
Here's the test:
test_routes.py
import os
import models
from flask import get_flashed_messages, session
from unittest import TestCase
# Before importing app, set environmental variable to use a test db for tests
os.environ['DATABASE_URL'] = 'postgresql:///omakase-test'
# Now import app
from app import app
app.config['WTF_CSRF_ENABLED'] = False
# Make Flask errors be real errors, not HTML pages with error info
app.config['TESTING'] = True
app.config['DEBUG_TB_HOSTS'] = ['dont-show-debug-toolbar']
def test_post_takeout_contact_form(self):
with self.client:
resp = self.client.post('/takeout/contact-form', follow_redirects=True,
data={
'name': 'test customer',
'phone_number': '123-456-7890'
})
html = resp.get_data(as_text=True)
testUser = models.User.query.filter_by(name="test").first()
self.assertEqual(resp.status_code, 200)
self.assertIn("We're pleased to take your order", html)
I'm specifically trying to test and see if a flash message pops up, but I keep getting the error message:
======================================================================
FAIL: test_post_takeout_contact_form (tests.test_routes.OrderTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "~/projects/capstone-project-one/tests/test_routes.py", line 272, in test_post_takeout_contact_form
self.assertIn("We're pleased to take your order", html)
AssertionError: "We're pleased to take your order" not found in '<!DOCTYPE html>\n<html
lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-
width, initial-scale=1.0">\n <title></title>\n <link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/united/bootstrap.min.css">\n <link
rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
integrity="sha512-
DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />\n</head>\n<body class="bg-light">\n\n<nav
class="navbar navbar-expand-lg bg-danger" data-bs-theme="dark">\n <div class="container-fluid">\n
<a class="navbar-brand" href="/">Omakase OMS</a>\n <button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-
expanded="false" aria-label="Toggle navigation">\n <span class="navbar-toggler-icon"></span>\n
</button>\n <div class="collapse navbar-collapse" id="navbarColor01">\n <ul class="navbar-
nav me-auto">\n <li class="nav-item">\n <a class="nav-link" href="/">Home\n
<span class="visually-hidden">(current)</span>\n </a>\n </li>\n <li
class="nav-item">\n <a class="nav-link" href="/dine-in/select-table">Dining In</a>\n
</li>\n <li class="nav-item">\n <a class="nav-link" href="/takeout">Takeout</a>\n
</li>\n <li class="nav-item">\n <a class="nav-link" href="/delivery">Delivery</a>\n
</li>\n <li class="nav-item dropdown">\n <a class="nav-link dropdown-toggle"
href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">\n
Employees\n </a>\n <ul class="dropdown-menu" aria-labelledby="navbarDropdown">\n
<li><a class="dropdown-item" href="/employee-dashboard">Employee Dashboard</a></li>\n
<li><a class="dropdown-item" href="/kitchen-dashboard">Kitchen Dashboard</a></li>\n
<li><a class="dropdown-item" href="/add-menu-item">Add Menu Item</a></li>\n <li><hr
class="dropdown-divider"></li>\n <li><a class="dropdown-item" href="/employees/list">
Employee List</a></li>\n <li><a class="dropdown-item" href="/employees/add-employee">Add
Employee</a></li>\n </ul>\n </li>\n </ul>\n <ul class="navbar-nav me-1"
id="user-profile">\n \n <li class="nav-item float-end me-2">\n <a class="nav-
link" href="/login">Login</a>\n </li>\n \n \n </ul>\n \n </div>\n
</div>\n</nav>\n\n\n \n\n\n<div class="container-fluid g-0 p-0" style="min-height:75vh;">\n\n\n\n
\n <div class="container p-3 bg-secondary mb-5 rounded">\n <h1>Please Fill Out The
Information Below</h1>\n \n \n<div class="container p-3 bg-light">\n<h3
class="display-3">Takeout</h3>\n\n <form id="takeout-form" method="POST">\n <!--add
type=hidden form fields -->\n\n \n\n \n \n\n <label
for="contact_info">Contact Info</label>\n <div class="container bg-white rounded py-2">\n
\n <label for="contact_info-name">Name</label>\n <input class="form-control
my-3" id="contact_info-name" name="contact_info-name" required type="text" value="">\n
\n <label for="contact_info-phone_number">Phone Number</label>\n <input
class="form-control my-3" id="contact_info-phone_number" name="contact_info-phone_number"
type="text" value="">\n \n </div>\n \n \n\n <p>\n \n
<small class="form-text text-danger">\n name\n </small>\n \n
</p>\n\n \n\n <button class="btn btn-success btn-lg" type="submit">Submit</button>\n
</form>\n</div>\n\n </div>\n\n\n</div>\n\n<footer>\n<div class="container-fluid text-center bg-
secondary d-flex justify-content-center" style="height:100px;">\n \n <div class="row">\n\n
<div class="col align-self-center">\n Vegetarian image by <a href="https://www.freepik.com/free-
vector/flat-world-vegetarian-day-labels-
collection_30590488.htm#query=vegetarian&position=13&from_view=search&track=sph&uuid=592ca90d-bf6b-
4116-9533-47be0d368220">Freepik</a>\n </div>\n\n </div>\n\n</div>\n</footer>\n \n<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script> \n\n\n</body>\n</html>'
----------------------------------------------------------------------
Ran 5 tests in 0.227s
FAILED (failures=1)
Checking the code in the html page, I noticed that the form is not accepting the data, and so it's just redirecting to the form again.
After examining the form data using flask toolbar, I noticed that the form data being sent is form.contact_info.data, which is an object of name and phone_number. So I thought sending:
data={
"contact_info": {
"name": "test",
"phone_number": "123-456-7890"
}
}
in testing would work, but I keep getting the same error as above. I'm not really sure what else to try.
I'm out of ideas of what to do next because I can't figure out why the form data isn't being sent in the test file. I'd really appreciate some advice or direction to what I could look up to get a better understanding of what I'm doing wrong.
I'll include the relevant code sections from the form.py and routes below.
app.py
@app.route('/<state>/contact-form', methods=['GET', 'POST'])
def contact_form(state):
if state=='takeout':
form = TakeoutForm()
if form.validate_on_submit():
name = form.contact_info.data['name']
phone_number = form.contact_info.data['phone_number']
customer = User(name=name, phone_number=phone_number, temp=True,
groups=[Group.query.filter_by(name='customer').first()])
new_order = Order(type='Takeout')
db.session.add_all([customer, new_order])
db.session.commit()
session['current_order_id'] = new_order.id
session['temp_customer_id'] = customer.id
flash(f"We're pleased to take your order, {name}!", 'success')
return redirect(url_for('order_page'))
if state=='delivery':
form = DeliveryForm()
if form.validate_on_submit():
name = form.contact_info.data['name']
phone_number = form.contact_info.data['phone_number']
proto_add = [i.strip() for i in form.address.data.values()]
address = ", ".join(proto_add)
customer = User(name=name, phone_number=phone_number, address=address, temp=True,
groups=[Group.query.filter_by(name='customer').first()])
new_order = Order(type='Takeout')
db.session.add_all([customer, new_order])
db.session.commit()
session['current_order_id'] = new_order.id
session['temp_customer_id'] = customer.id
flash(f"We're pleased to take your order, {name}!", 'success')
return redirect(url_for('order_page'))
return render_template('contact-form.html', form=form, state=state)
forms.py
class ContactInfo(Form):
"""Subform for adding customer contact info"""
name = StringField("Name", validators=[DataRequired()])
phone_number = StringField("Phone Number")
class TakeoutForm(FlaskForm):
contact_info = FormField(ContactInfo)