import datetime import pytest from pyramid.authentication import AuthTktCookieHelper from pyramid.testing import DummyRequest from playwright.sync_api import Page, expect from sqlalchemy import select from testutils import load_gpx_asset from fietsboek import models from fietsboek.models.track import Visibility, TrackType from fietsboek.config import Config @pytest.fixture def john_doe(dbaccess): """Provides a test user (John Doe). This fixture either returns the existing John or creates a new one. """ with dbaccess: user = models.User(name="John Doe", email="john@doe.com", is_verified=True) user.set_password("password") dbaccess.add(user) dbaccess.commit() dbaccess.refresh(user, ["id"]) dbaccess.expunge(user) return user def do_login(settings: dict, page: Page, user: models.User): """Logs the given user in by setting the auth cookie.""" config = Config.construct(session_key=settings["session_key"]) secret = config.derive_secret("auth-cookie") helper = AuthTktCookieHelper(secret) headers = helper.remember(DummyRequest(), str(user.id)) for _, header_val in headers: cookie = header_val.split(";")[0] name, value = cookie.split("=", 1) page.context.add_cookies([ {"name": name, "value": value, "domain": "localhost", "path": "/"}, ]) def test_homepage(page: Page): page.goto("/") assert "Welcome to Fietsboek!" in page.content() assert "Here you can …" in page.content() def test_login_failed(page: Page): page.goto("/") page.get_by_role("button", name="User").click() page.get_by_text("Login").click() page.get_by_label("E-Mail").fill("not-john@doe.com") page.get_by_label("Password").fill("password") page.get_by_role("button", name="Login").click() expect(page.locator(".alert")).to_have_text("Invalid login credentials") def test_login_success(page: Page, john_doe): page.goto("/") page.get_by_role("button", name="User").click() page.get_by_text("Login").click() page.get_by_label("E-Mail").fill("john@doe.com") page.get_by_label("Password").fill("password") page.get_by_role("button", name="Login").click() expect(page.locator(".alert")).to_have_text("You are now logged in") def test_upload(page: Page, john_doe, app_settings, tmp_path, dbaccess): do_login(app_settings, page, john_doe) page.goto("/") page.get_by_text("Upload").click() # We unpack one of the test GPX files gpx_data = load_gpx_asset("Teasi_1.gpx.gz") gpx_path = tmp_path / "Upload.gpx" with open(gpx_path, "wb") as gpx_fobj: gpx_fobj.write(gpx_data) page.get_by_label("GPX file").set_input_files(gpx_path) page.locator(".bi-upload").click() # We now fill in most of the data page.get_by_label("Title").fill("An awesome track!") page.get_by_label("Date").type("07302022") page.get_by_label("Date").press("Tab") page.get_by_label("Date").type("12:41") page.get_by_label("Visibility").select_option(label="Public") page.get_by_label("Tags").fill("Tolle Tour") page.get_by_role("button", name="Add Tag").click() page.get_by_label("Description").fill("Beschreibung der tollen Tour") page.locator(".btn", has_text="Upload").click() # Once we have finished the upload, extract the ID of the track and check # the properties new_track_id = int(page.url.rsplit("/", 1)[1]) track = dbaccess.execute(select(models.Track).filter_by(id=new_track_id)).scalar_one() assert track.title == "An awesome track!" assert track.date.replace(tzinfo=None) == datetime.datetime(2022, 7, 30, 12, 41) assert track.visibility == Visibility.PUBLIC assert track.text_tags() == {"Tolle Tour"} assert track.description == "Beschreibung der tollen Tour" def test_edit(page: Page, john_doe, app_settings, dbaccess, data_manager): do_login(app_settings, page, john_doe) with dbaccess: john_doe = dbaccess.merge(john_doe) track = models.Track( title="Another awesome track", visibility=Visibility.PRIVATE, description="Another description", ) track.date = datetime.datetime.now(datetime.timezone.utc) john_doe.tracks.append(track) dbaccess.flush() track_id = track.id data_manager.initialize(track_id).compress_gpx(load_gpx_asset("Teasi_1.gpx.gz")) dbaccess.commit() page.goto(f"/track/{track_id}") page.locator(".btn", has_text="Edit").click() # We now fill in most of the data page.get_by_label("Title").fill("Not so awesome anymore!") page.get_by_label("Date").type("09232019") page.get_by_label("Date").press("Tab") page.get_by_label("Date").type("15:28") page.get_by_label("Visibility").select_option(label="Public") page.get_by_label("Tags").fill("Shitty Tour") page.get_by_role("button", name="Add Tag").click() page.get_by_label("Description").fill("Not so descriptive anymore") page.locator(".btn", has_text="Save").click() track = dbaccess.execute(select(models.Track).filter_by(id=track_id)).scalar_one() assert track.title == "Not so awesome anymore!" assert track.date.replace(tzinfo=None) == datetime.datetime(2019, 9, 23, 15, 28) assert track.visibility == Visibility.PUBLIC assert track.text_tags() == {"Shitty Tour"} assert track.description == "Not so descriptive anymore" def test_browse(page: Page, john_doe, app_settings, dbaccess, data_manager): do_login(app_settings, page, john_doe) with dbaccess: john_doe = dbaccess.merge(john_doe) track = models.Track( title="We're looking for this track", visibility=Visibility.PRIVATE, description="Another description", type=TrackType.ORGANIC, ) track.date = datetime.datetime.now(datetime.timezone.utc) john_doe.tracks.append(track) dbaccess.flush() data_manager.initialize(track.id).compress_gpx(load_gpx_asset("Teasi_1.gpx.gz")) dbaccess.commit() page.goto("/") page.get_by_text("Browse").click() expect(page.locator(".card-header", has_text="We're looking for this track")).to_be_visible() page.get_by_role("textbox", name="Search terms").fill("Nothing") page.get_by_role("button", name="Apply filters").click() expect( page.locator("p", has_text="No results matching the filters were found.") ).to_be_visible() page.get_by_role("textbox", name="Search terms").fill("looking for") page.get_by_role("button", name="Apply filters").click() expect(page.locator(".card-header", has_text="We're looking for this track")).to_be_visible() def test_delete(page: Page, john_doe, app_settings, dbaccess, data_manager): do_login(app_settings, page, john_doe) with dbaccess: john_doe = dbaccess.merge(john_doe) track = models.Track( title="Another awesome track", visibility=Visibility.PRIVATE, description="Another description", ) track.date = datetime.datetime.now(datetime.timezone.utc) john_doe.tracks.append(track) dbaccess.flush() track_id = track.id data_manager.initialize(track_id).compress_gpx(load_gpx_asset("Teasi_1.gpx.gz")) dbaccess.commit() page.goto(f"/track/{track_id}") page.locator("#deleteLink", has_text="Delete").click() expect(page.get_by_text( "Deleting this track will remove all associated information with it!" )).to_be_visible() page.locator("#deleteModal form").get_by_text("Delete").click() track = dbaccess.execute(select(models.Track).filter_by(id=track_id)).scalar_one_or_none() assert track is None with pytest.raises(FileNotFoundError): data_manager.open(track_id)