funkid
funkid

Reputation: 665

Pytest fails on flask wtforms

I was trying to test the login function by using pytest, but the test fails.

Actually, the real problem in my project is that the form.validate_on_submit() is always False when I trying to POST data to the login form (all the form.field.data is '').

So I decide to make a minimal project to see what is happening.

I did not include database here because database works fine in my real project, and what I want to figure out is why it seems that no data can be posted in.

But when it came to this minimal project below, another problem comes out: the staus code of the response becomes 404.

I've set app.config['WTF_CSRF_ENABLED'] = False both in this minimal project and my real project.

This minimal project structure is here:

.
├── Pipfile
├── Pipfile.lock
├── app.py
├── templates
│   └── login.html
└── tests
    └── test_login.py

test_login.py:

import pytest

from app import create_app


@pytest.fixture(scope='module')
def app():
    app = create_app()
    with app.app_context():
        app.config['WTF_CSRF_ENABLED'] = False
        yield app


@pytest.fixture
def client(app):
    return app.test_client()


def test_login(client):
    response = client.post('/login', data={'username': '1', 'password': '1'})
    # response.status_code is 404 here
    assert response.headers['Location'] == 'http://localhost/'

app.py:

from flask import Flask, redirect, render_template, url_for
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField
from wtforms.validators import DataRequired


class LoginForm(FlaskForm):
    username = StringField(validators=[DataRequired()])
    password = PasswordField(validators=[DataRequired()])
    submit = SubmitField()


def create_app():
    app = Flask('__name__')
    app.config['SECRET_KEY'] = "secretkey"
    return app


app = create_app()


@app.route('/')
def home():
    return 'hello'


@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        return redirect(url_for('home'))
    return render_template('login.html', form=form)

login.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <form method="POST">
        {{ form.hidden_tag() }}
        {{ form.username() }}
        {{ form.password() }}
        {{ form.submit() }}
    </form>
</body>

</html>

The virtual environment I choose is pipenv and pyenv, and here is my Pipfile:

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
pytest = "*"

[packages]
flask-wtf = "*"

[requires]
python_version = "3.7"

Upvotes: 0

Views: 1237

Answers (1)

funkid
funkid

Reputation: 665

It turns out that I'm not using the factory pattern correctly. Blueprint should be used and be registered with the app in factory. For details, check this answer.

Upvotes: 0

Related Questions