jonasdiete
jonasdiete

Reputation: 41

Playwright for Python does not store my cookies correctly

I want to use Playwright to test my web-app written in Python using Flask.

However, when I want to test logging in, Playwright doesn't seem to store a cookie correctly.

There is a cookie-consent box on the main page of my app and I am asking Playwright to click accept, then type in a username and password and click Login.

This test fails. Here is the error message:

>       expect(page.get_by_text("Welcome, Harry. Select a timestable.")).to_be_visible()
E       AssertionError: Locator expected to be visible
E       Actual value: None 
E       Call log:
E       LocatorAssertions.to_be_visible with timeout 5000ms
E       waiting for get_by_text("Welcome, Harry. Select a timestable.")

When I checked the video that Playwright created, I can see that the accept button for the cookies is clicked correctly and the cookie-notification disappears. Then Playwright types in the login details correctly and clicks "Login". However then it is redirected to the login page, with the notification that you have to accept the cookies first. Therefore the test fails because it never gets to the Page with the text "Welcome Harry. ..."

When I accept the cookies manually and log-in it works though. The way the cookie-consent works is that it stores whether the cookies have been accepted in Flask's "session" cookie. My guess is that for some reason in the Playwright test the cookie-consent cookie doesn't get stored correctly.

Does anyone have an idea what I can do to get the test run correctly?

Here is a live-link to my web-app: https://ttcoach.herokuapp.com/ On there the manual logging in works with Harry potter.

And here are my Playwright tests. The first two work, but the third one does not.

import re
from playwright.sync_api import Page, expect, sync_playwright

def test_homepage_has_correct_title(page: Page):
    page.goto("https://ttcoach.herokuapp.com/login")
    expect(page).to_have_title(re.compile("Times Table Coach"))

def test_accepting_cookies_hides_box(page: Page):
    page.goto("https://ttcoach.herokuapp.com/login")
    accept_button = page.get_by_role("button", name="Accept").click()
    # checking accept_button is None (doesn't exist)
    assert not accept_button

def test_logging_in(page: Page):
    page.goto("https://ttcoach.herokuapp.com/login")
    page.get_by_role("button", name="Accept").click()
    page.get_by_placeholder("Username").fill("Harry")
    page.get_by_placeholder("Password").fill("potter")
    page.get_by_role("button", name="Login").click()
    expect(page.get_by_text("Welcome, Harry. Select a timestable.")).to_be_visible()

And my code from Flask for the login page:

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == 'POST':
        if request.form.get("accepted") == "yes":
            session["cookies"] = "yes"

        # checking if cookies are accepted
        if not "cookies" in session:
            return render_template("login.html", login_message = "You must accept the cookies to continue.", cookies = "")
        
        # saving user input
        username_entered = request.form.get("username")
        password_entered = request.form.get("password")

        # checking if user exists and password is correct
        user_retrieved = user_repository.get_one(database_connection.connect(), username_entered) 
        if user_retrieved == False or not bcrypt.checkpw(password_entered.encode('utf-8'), user_retrieved.password.encode('utf-8')):
            return render_template("login.html", login_message = "Incorrect username or password. Try again.", cookies = "yes")
        
        # logging in
        session["user"] = jsonpickle.encode(user_retrieved)
        return redirect("/select")
    
    elif request.method == 'GET':   
        # deleting user in case we were redirected here after logout
        if "user" in session:
            session.pop("user", default=None) 

        # checking if user has accepted cookies
        if "cookies" in session:
            return render_template("login.html", login_message = "Enter your login details.", cookies = "yes")
        else:
            return render_template("login.html", login_message = "Enter your login details.", cookies = "")

Upvotes: 0

Views: 735

Answers (1)

jonasdiete
jonasdiete

Reputation: 41

I slightly refactored my login route with flask and now it works! All tests pass. I still don't understand why though. I don't seem to have changed anything in regards to the cookies.

Here is my refactored version:

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == 'POST':
        if request.form.get("accepted") == "yes":
            session["cookies"] = "yes"

        # checking if cookies are accepted
        if not "cookies" in session:
            return render_template("login.html", login_message = "You must accept the cookies to continue.", cookies = "")
        
        # saving user input
        username_entered = request.form.get("username")
        password_entered = request.form.get("password")

        # checking for error message on username and password
        # this ensures no special characters etc are used to hack database
        if check_username(username_entered) == None and check_password(password_entered) == None:
            
            # trying to load user from database
            user_retrieved = user_repository.get_one(database_connection.connect(), username_entered) 
            
            print(password_entered.encode('utf-8'))
            # checking user exists and password matches database
            if user_retrieved and bcrypt.checkpw(password_entered.encode('utf-8'), user_retrieved.password.encode('utf-8')):
                
                # logging in
                session["user"] = jsonpickle.encode(user_retrieved)
                return redirect("/select")
        
        # username didn't exist or password was wrong
        return render_template("login.html", login_message = "Incorrect username or password. Try again.", cookies = "yes")
        

    elif request.method == 'GET':   
        # deleting user in case we were redirected here after logout
        if "user" in session:
            session.pop("user", default=None) 

        # checking if user has accepted cookies
        if "cookies" in session:
            return render_template("login.html", login_message = "Enter your login details.", cookies = "yes")
        else:
            return render_template("login.html", login_message = "Enter your login details.", cookies = "")
'''

Upvotes: 0

Related Questions