MAA
MAA

Reputation: 1355

Flask testing keeps failing

So I have web app where if the user is logged in, he cannot sign up. Instead he is redirected and a message saying he cannot sign up is flashed.

The problem is I can't test it for some reason.

Here is the view

@users_template.route('/signup', methods=['GET', 'POST'])
def signup():
    form = RegisterationForm()
    if current_user.is_authenticated and current_user.is_active:  # prevent the user from seeing the register page if he's already logged in
        flash('You cannot sign up while you\'re logged in')
        return redirect(url_for('main.home'))

    if request.method == 'POST' and form.validate_on_submit():
        username = form.username.data
        password = form.password.data
        user = User(username=username, password=password)
        if db.session.query(User).filter(User.username == username).first() is None:
            current_app.logger.info('<{}> did not register before. Registering him/her now'.format(username))
            db.session.add(user)
            db.session.commit()
            flash('Thank you for registering. Please login now')
            return redirect(url_for('users.login'))
        else:  # the user name has been registered before
            flash('You already registered')
    return render_template('signup.html', form=form)

Now in my test module I have this method

def test_signup_page_requires_logout(self):
    data_to_signup = {'username': 'mustafa1', 'password': 'mustafa1',
            'confirm_password': 'mustafa1'}
    data_to_login = {'username': 'mustafa1', 'password': 'mustafa1'}
    # with statement preserves the request context for the current_user
    with self.client:
        self.client.post('/signup', data=data_to_signup)
        self.client.post('/login', data=data_to_login)
        response = self.client.get('/signup', follow_redirects=True)
        assert b'You cannot sign up while you\'re logged in' in response.data

What's even more confusing is that this structure works for other methods

def test_headquarter_after_login(self):
    data_to_signup = {'username': 'mustafa1', 'password': 'mustafa1',
            'confirm_password': 'mustafa1'}
    data_to_login = {'username': 'mustafa1', 'password': 'mustafa1'}
    with self.client:
        self.client.post('/signup', data=data_to_signup)
        self.client.post('/login', data=data_to_login)
        response = self.client.get('/headquarter')
        assert b'Headquarter page' in response.data

EDIT: here is the login view

from .. import bcrypt
@users_template.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm(request.form)
    if form.validate_on_submit() and request.method == 'POST':
        username = form.username.data
        password = form.password.data

        user = User.query.filter(User.username == username).first()

        if user is not None and bcrypt.check_password_hash(user.password, password):  # authenticate
            login_user(user)  # then log the user in
            flash('You are logged in')
            return redirect(url_for('main.home'))

        else:
            flash('Incorrect username or password')  # if username is wrong, it will be caught by the error handling above
    return render_template('login.html', form=form)  # for a GET request

This is the error (I'm using py.test fyi)

            assert current_user.is_active() == True
            assert current_user.is_authenticated() == True
>           assert b'You cannot sign up while you\'re logged in' in response.data
E           AssertionError: assert b"You cannot sign up while you're logged in" in b'<!DOCTYPE html>\n<html lang="en">\n  <head>\n    <meta charset="utf-8">\n    <meta http-equiv="X-UA-Compatible" cont...jquery/1.12.4/jquery.min.js"></script>\n    <script src="/static/js/bootstrap.min.js"> </script>\n  </body>\n</html>\n'
E            +  where b'<!DOCTYPE html>\n<html lang="en">\n  <head>\n    <meta charset="utf-8">\n    <meta http-equiv="X-UA-Compatible" cont...jquery/1.12.4/jquery.min.js"></script>\n    <script src="/static/js/bootstrap.min.js"> </script>\n  </body>\n</html>\n' = <TestResponse 3874 bytes [200 OK]>.

This is to display the flashed messages in all my templates(It's in my "base.html" which I inherit from)

    {% if get_flashed_messages() %}
        {% for message in get_flashed_messages() %}
            <div class='container'>
                    <span class='alert alert-info'>
                        <small>{{ message }}</small>
                    </span>
            </div>
        {% endfor %}
    {% endif %}

I've made more tests using the flashed messages and it worked fine. Like this one for testing the user signup

assert b'Thank you for registering. Please login now' in response.data

Upvotes: 0

Views: 427

Answers (1)

turkus
turkus

Reputation: 4903

Suggestion no:

  1. Because of this line:

    if current_user.is_authenticated and current_user.is_active:
    

    current_user has his is_active flag set as False. If I'm not right, then please paste test error.

  2. Another clue could be lack of flash messages in home template. Put this code below in for example flashMessages.html:

    {% macro render_flashMessages() %}
        {% with messages = get_flashed_messages() %}
            {% if messages %}
            <ul class="list-unstyled">
                {% for message in messages %}
                <li><div class="alert alert-info">{{ message|safe }}</div></li>
                {% endfor %}
            </ul>
            {% endif %}
        {% endwith %}
    {% endmacro %}
    

    then you can use it in this way in home.html:

    {% from "flashMessages.html" import render_flashMessages %}
    
    {{ render_flashMessages() }}
    
  3. Next thing to check is to use assert with something else than response.data, if you're using Flask-WebTest you can try:

    assert b'You cannot sign up while you\'re logged in' in response.flashes[0][1]
    

    Where flashes is:

    List of tuples (category, message) containing messages that were flashed during request.

  4. But if you're not using FlaskWebTest, you can check session:

    from flask import session
    
    session['_flashes'][0][1]
    

Upvotes: 1

Related Questions