0

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"

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.