Translate the whole site to English: English routes with 301 redirects from the Dutch paths, English UI, docs, seeds and captions, one-time live content migration
This commit is contained in:
+10
-10
@@ -3,7 +3,7 @@ JSON = {"Accept": "application/json"}
|
||||
|
||||
|
||||
def _create(admin, **overrides):
|
||||
payload = {"title": "Een echte notitie", "body": "Tekst met **nadruk** en `code`.", "topic": "rol", "status": "draft"}
|
||||
payload = {"title": "A real note", "body": "Text with **emphasis** and `code`.", "topic": "roll", "status": "draft"}
|
||||
payload.update(overrides)
|
||||
response = admin.post("/admin/posts", json=payload, headers=JSON)
|
||||
assert response.status_code == 200, response.text
|
||||
@@ -11,24 +11,24 @@ def _create(admin, **overrides):
|
||||
|
||||
|
||||
def test_create_draft_is_hidden_then_published(admin, anon):
|
||||
data = _create(admin, title="Concept dat later live gaat")
|
||||
data = _create(admin, title="Draft that goes live later")
|
||||
assert anon.get(f"/posts/{data['slug']}").status_code == 404
|
||||
assert admin.post(f"/admin/posts/{data['uid']}/publish", headers=JSON).status_code == 200
|
||||
page = anon.get(f"/posts/{data['slug']}")
|
||||
assert page.status_code == 200
|
||||
assert "<strong>nadruk</strong>" in page.text
|
||||
assert "<strong>emphasis</strong>" in page.text
|
||||
|
||||
|
||||
def test_edit_post(admin, anon):
|
||||
data = _create(admin, title="Te bewerken notitie", status="published")
|
||||
response = admin.post(f"/admin/posts/{data['uid']}", json={"title": "Bewerkte notitie", "body": "Nieuwe tekst hier.", "topic": "standaard", "status": "published"}, headers=JSON)
|
||||
data = _create(admin, title="Note to edit", status="published")
|
||||
response = admin.post(f"/admin/posts/{data['uid']}", json={"title": "Edited note", "body": "New text right here.", "topic": "standard", "status": "published"}, headers=JSON)
|
||||
assert response.status_code == 200, response.text
|
||||
posts = anon.get("/standaard", headers=JSON).json()["posts"]
|
||||
assert any(post["title"] == "Bewerkte notitie" for post in posts)
|
||||
posts = anon.get("/standard", headers=JSON).json()["posts"]
|
||||
assert any(post["title"] == "Edited note" for post in posts)
|
||||
|
||||
|
||||
def test_delete_goes_to_trash(admin, anon):
|
||||
data = _create(admin, title="Weg ermee notitie", status="published")
|
||||
data = _create(admin, title="Gone with it note", status="published")
|
||||
assert admin.post(f"/admin/posts/{data['uid']}/delete", headers=JSON).status_code == 200
|
||||
assert anon.get(f"/posts/{data['slug']}").status_code == 404
|
||||
trash = admin.get("/admin/trash", headers=JSON).json()["items"]
|
||||
@@ -41,10 +41,10 @@ def test_validation_error(admin):
|
||||
|
||||
|
||||
def test_html_form_post(admin):
|
||||
response = admin.post("/admin/posts", data={"title": "Via formulier", "body": "Formuliertekst hier.", "topic": "rol", "status": "draft"})
|
||||
response = admin.post("/admin/posts", data={"title": "Via the form", "body": "Form text right here.", "topic": "roll", "status": "draft"})
|
||||
assert response.status_code in (302, 303)
|
||||
|
||||
|
||||
def test_member_cannot_write(member):
|
||||
response = member.post("/admin/posts", json={"title": "Niet toegestaan", "body": "Tekst hier.", "topic": "rol"}, headers=JSON)
|
||||
response = member.post("/admin/posts", json={"title": "Not allowed", "body": "Text right here.", "topic": "roll"}, headers=JSON)
|
||||
assert response.status_code == 403
|
||||
|
||||
+7
-7
@@ -4,15 +4,15 @@
|
||||
def test_home_is_molodetz(anon):
|
||||
html = anon.get("/").text
|
||||
assert "Molodetz" in html
|
||||
for label in ("Rol", "Standaard", "Flyers", "Memes", "Mensen", "Binnen"):
|
||||
for label in ("Roll", "Standard", "Flyers", "Memes", "People", "Join"):
|
||||
assert f">{label}</a>" in html
|
||||
assert "wa.me" not in html and "whatsapp" not in html.lower()
|
||||
|
||||
|
||||
def test_unknown_page_is_404(anon):
|
||||
response = anon.get("/bestaat-niet-xyz")
|
||||
response = anon.get("/does-not-exist-xyz")
|
||||
assert response.status_code == 404
|
||||
assert anon.get("/bestaat-niet-xyz", headers={"Accept": "application/json"}).json()["error"]
|
||||
assert anon.get("/does-not-exist-xyz", headers={"Accept": "application/json"}).json()["error"]
|
||||
|
||||
|
||||
def _intro_section(html):
|
||||
@@ -47,15 +47,15 @@ def test_intro_json_face(anon):
|
||||
def test_admin_can_edit_intro(admin, anon):
|
||||
original = admin.get("/admin/settings", headers={"Accept": "application/json"}).json()["settings"]["site_intro"]
|
||||
try:
|
||||
response = admin.post("/admin/settings", json={"site_intro": "Eerste regel.\n\nTweede alinea\nmet een regel erbij."}, headers={"Accept": "application/json"})
|
||||
response = admin.post("/admin/settings", json={"site_intro": "First line.\n\nSecond paragraph\nwith an extra line."}, headers={"Accept": "application/json"})
|
||||
assert response.status_code == 200
|
||||
intro = _intro_section(anon.get("/").text)
|
||||
assert intro.find("p").get_text() == "Eerste regel."
|
||||
assert intro.find("p").get_text() == "First line."
|
||||
assert intro.find_all("p")[1].find("br") is not None
|
||||
form = admin.post("/admin/settings", data={"site_intro": "Via formulier.\r\n\r\nRegel een\r\nregel twee"})
|
||||
form = admin.post("/admin/settings", data={"site_intro": "Via the form.\r\n\r\nLine one\r\nline two"})
|
||||
assert form.status_code in (302, 303)
|
||||
stored = admin.get("/admin/settings", headers={"Accept": "application/json"}).json()["settings"]["site_intro"]
|
||||
assert stored == "Via formulier.\n\nRegel een\nregel twee"
|
||||
assert stored == "Via the form.\n\nLine one\nline two"
|
||||
finally:
|
||||
admin.post("/admin/settings", json={"site_intro": original}, headers={"Accept": "application/json"})
|
||||
assert _intro_section(anon.get("/").text).find("p").get_text(" ", strip=True).startswith("I wrote more code than you.")
|
||||
|
||||
@@ -3,11 +3,11 @@ JSON = {"Accept": "application/json"}
|
||||
|
||||
|
||||
def test_join_request_is_stored_and_visible_to_admin(anon, admin):
|
||||
response = anon.post("/binnen", data={"name": "Schrijver Een", "contact": "schrijver@example.invalid", "repo_url": "https://example.com/repo", "message": "Ik wil meeschrijven.", "website": ""})
|
||||
response = anon.post("/join", data={"name": "Writer One", "contact": "schrijver@example.invalid", "repo_url": "https://example.com/repo", "message": "I want to write along.", "website": ""})
|
||||
assert response.status_code in (302, 303)
|
||||
assert "ok=1" in response.headers["location"]
|
||||
rows = admin.get("/admin/joins", headers=JSON).json()["requests"]
|
||||
row = next(row for row in rows if row["name"] == "Schrijver Een")
|
||||
row = next(row for row in rows if row["name"] == "Writer One")
|
||||
assert row["contact"] == "schrijver@example.invalid"
|
||||
assert row["repo_url"].startswith("https://example.com/repo")
|
||||
status = admin.post(f"/admin/joins/{row['uid']}/status", json={"status": "contacted"}, headers=JSON)
|
||||
@@ -15,19 +15,19 @@ def test_join_request_is_stored_and_visible_to_admin(anon, admin):
|
||||
|
||||
|
||||
def test_join_json_api(anon):
|
||||
response = anon.post("/binnen", json={"name": "Schrijver Twee", "contact": "@twee"}, headers=JSON)
|
||||
response = anon.post("/join", json={"name": "Writer Two", "contact": "@twee"}, headers=JSON)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["ok"] is True
|
||||
|
||||
|
||||
def test_honeypot_is_not_stored(anon, admin):
|
||||
anon.post("/binnen", data={"name": "Robot Bot", "contact": "bot@example.invalid", "website": "spam"})
|
||||
anon.post("/join", data={"name": "Robot Bot", "contact": "bot@example.invalid", "website": "spam"})
|
||||
rows = admin.get("/admin/joins", headers=JSON).json()["requests"]
|
||||
assert not any(row["name"] == "Robot Bot" for row in rows)
|
||||
|
||||
|
||||
def test_join_validation(anon):
|
||||
response = anon.post("/binnen", json={"name": "x", "contact": ""}, headers=JSON)
|
||||
response = anon.post("/join", json={"name": "x", "contact": ""}, headers=JSON)
|
||||
assert response.status_code == 422
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/terms", "/privacy", "/auth/login", "/docs", "/docs/welcome", "/docs/api/content"]
|
||||
DUTCH = ("Ik schrijf mee", "Mensen", "Binnen", "Voorwaarden", "Inloggen", "Meldingen", "Beheer", "Naar inhoud", "Nog niets", "Intro bewerken", "Een zes is", "Eenendertig", "Gezet in serif", "Verder lezen")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", PAGES)
|
||||
def test_pages_are_english(anon, path):
|
||||
html = anon.get(path).text
|
||||
assert '<html lang="en">' in html
|
||||
assert 'content="en_US"' in html
|
||||
visible = re.sub(r"<script.*?</script>", "", html, flags=re.S)
|
||||
for word in DUTCH:
|
||||
assert word not in visible, (path, word)
|
||||
|
||||
|
||||
def test_nav_uses_english_paths(anon):
|
||||
html = anon.get("/").text
|
||||
for href, label in (("/roll", "Roll"), ("/standard", "Standard"), ("/people", "People"), ("/join", "Join")):
|
||||
assert f'href="{href}"' in html and f">{label}</a>" in html
|
||||
for old in ('href="/rol"', 'href="/standaard"', 'href="/mensen"', 'href="/binnen"', 'href="/voorwaarden"'):
|
||||
assert old not in html
|
||||
assert ">I'm in</a>" in html or ">I'm in</a>" in html
|
||||
|
||||
|
||||
def test_admin_sees_edit_intro(admin):
|
||||
html = admin.get("/").text
|
||||
assert "Edit intro" in html
|
||||
assert "Intro bewerken" not in html
|
||||
|
||||
|
||||
def test_sitemap_lists_english_paths(anon):
|
||||
xml = anon.get("/sitemap.xml").text
|
||||
for path in ("/roll<", "/standard<", "/people<", "/join<", "/terms<", "/docs/welcome<"):
|
||||
assert path in xml, path
|
||||
for old in ("/rol<", "/mensen", "/binnen", "/voorwaarden", "/docs/welkom"):
|
||||
assert old not in xml, old
|
||||
|
||||
|
||||
def test_gallery_captions_are_english(anon):
|
||||
flyers = anon.get("/flyers", headers={"Accept": "application/json"}).json()["items"]
|
||||
captions = {item["caption"] for item in flyers}
|
||||
assert "Thirty-one choices. You have zero." in captions
|
||||
assert not any(" geen " in f" {caption.lower()} " or " een " in f" {caption.lower()} " for caption in captions)
|
||||
|
||||
|
||||
def test_english_migration_helpers():
|
||||
from molodetz.bootstrap import _translate_notification
|
||||
|
||||
assert _translate_notification("Ada wil meeschrijven") == "Ada wants to write along"
|
||||
assert _translate_notification("Gepubliceerd: Geen cursus.") == "Published: No course."
|
||||
assert _translate_notification("Back-up database klaar") == "Backup database finished"
|
||||
assert _translate_notification("Je API-sleutel is vernieuwd.") == "Your API key was renewed."
|
||||
assert _translate_notification("Already English") == "Already English"
|
||||
@@ -0,0 +1,68 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
import pytest
|
||||
|
||||
from molodetz.routers.legacy import LEGACY_PATHS
|
||||
|
||||
REDIRECTS = [
|
||||
("/rol", "/roll"),
|
||||
("/standaard", "/standard"),
|
||||
("/mensen", "/people"),
|
||||
("/mensen/retoor", "/people/retoor"),
|
||||
("/binnen", "/join"),
|
||||
("/voorwaarden", "/terms"),
|
||||
("/docs/welkom", "/docs/welcome"),
|
||||
("/docs/schrijven", "/docs/writing"),
|
||||
("/docs/binnen", "/docs/join"),
|
||||
("/docs/juridisch", "/docs/legal"),
|
||||
("/docs/architectuur", "/docs/architecture"),
|
||||
("/docs/api/inhoud", "/docs/api/content"),
|
||||
("/docs/api/binnen", "/docs/api/join"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("old,new", REDIRECTS)
|
||||
def test_old_dutch_paths_redirect_permanently(anon, old, new):
|
||||
response = anon.get(old)
|
||||
assert response.status_code == 301, old
|
||||
assert response.headers["location"] == new
|
||||
assert anon.get(new).status_code == 200, new
|
||||
|
||||
|
||||
def test_redirect_keeps_query_string(anon):
|
||||
response = anon.get("/rol?before=2026-01-01")
|
||||
assert response.status_code == 301
|
||||
assert response.headers["location"] == "/roll?before=2026-01-01"
|
||||
|
||||
|
||||
def test_old_join_post_keeps_method(anon):
|
||||
response = anon.post("/binnen", data={"name": "x"})
|
||||
assert response.status_code == 308
|
||||
assert response.headers["location"] == "/join"
|
||||
|
||||
|
||||
def test_legacy_paths_are_hidden_from_schema():
|
||||
from molodetz.main import app
|
||||
|
||||
paths = app.openapi()["paths"]
|
||||
assert not any(old in paths for old in LEGACY_PATHS)
|
||||
assert "/mensen/{username}" not in paths
|
||||
|
||||
|
||||
def test_old_post_slug_redirects_to_english_slug(anon, admin):
|
||||
from molodetz.content import translate_seeded_posts
|
||||
from molodetz.database import db, get_user_by_username, insert_post, update_post_row
|
||||
|
||||
author = get_user_by_username("retoor")
|
||||
row = insert_post(author["uid"], "Af is een eigenschap.", "Een project dat open blijft, is een mening.", "rol", status="published", is_placeholder=True)
|
||||
try:
|
||||
assert translate_seeded_posts() >= 1
|
||||
migrated = db["posts"].find_one(uid=row["uid"])
|
||||
assert migrated["title"] == "Finished is a feature."
|
||||
assert migrated["topic"] == "roll"
|
||||
assert migrated["slug"].startswith("finished-is-a-feature-")
|
||||
assert "Carried over from the old Molodetz page" in migrated["body"]
|
||||
response = anon.get(f"/posts/{row['slug']}")
|
||||
assert response.status_code == 301
|
||||
assert response.headers["location"] == f"/posts/{migrated['slug']}"
|
||||
finally:
|
||||
update_post_row(row["uid"], deleted_at="2026-01-01T00:00:00+00:00", deleted_by="test")
|
||||
@@ -1,8 +1,8 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
|
||||
def test_mensen_lists_real_accounts_only(anon):
|
||||
people = anon.get("/mensen", headers={"Accept": "application/json"}).json()
|
||||
def test_people_lists_real_accounts_only(anon):
|
||||
people = anon.get("/people", headers={"Accept": "application/json"}).json()
|
||||
names = [person["username"] for person in people.get("people", [])]
|
||||
assert names[0] == "retoor"
|
||||
assert set(names) <= {"retoor", "lezer"}
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
|
||||
def test_post_page(anon):
|
||||
posts = anon.get("/rol", headers={"Accept": "application/json"}).json()["posts"]
|
||||
post = next(post for post in posts if post["title"] == "Geen cursus.")
|
||||
posts = anon.get("/roll", headers={"Accept": "application/json"}).json()["posts"]
|
||||
post = next(post for post in posts if post["title"] == "No course.")
|
||||
response = anon.get(f"/posts/{post['slug']}")
|
||||
assert response.status_code == 200
|
||||
assert "Placeholder" in response.text
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
|
||||
def test_seeded_posts_and_placeholders(anon):
|
||||
rol = anon.get("/rol", headers={"Accept": "application/json"}).json()["posts"]
|
||||
seeds = {"Een zes is geen ambitie.", "Af is een eigenschap.", "De assistent is geen senior.", "Geen cursus."}
|
||||
assert seeds <= {post["title"] for post in rol}
|
||||
assert all(post["is_placeholder"] for post in rol if post["title"] in seeds)
|
||||
standaard = anon.get("/standaard", headers={"Accept": "application/json"}).json()["posts"]
|
||||
keuzes = next(post for post in standaard if post["title"] == "Eenendertig keuzes. Jij hebt er nul.")
|
||||
assert keuzes["is_placeholder"] is False
|
||||
@@ -0,0 +1,33 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
from molodetz.content import PLACEHOLDER_NOTE, SEED_POSTS
|
||||
|
||||
ROLL_SEEDS = {"A pass is not an ambition.", "Finished is a feature.", "The assistant is not a senior.", "No course."}
|
||||
|
||||
|
||||
def test_seeded_posts_and_placeholders(anon):
|
||||
roll = anon.get("/roll", headers={"Accept": "application/json"}).json()["posts"]
|
||||
assert ROLL_SEEDS <= {post["title"] for post in roll}
|
||||
assert all(post["is_placeholder"] for post in roll if post["title"] in ROLL_SEEDS)
|
||||
assert all(post["topic"] == "roll" for post in roll)
|
||||
standard = anon.get("/standard", headers={"Accept": "application/json"}).json()["posts"]
|
||||
choices = next(post for post in standard if post["title"] == "Thirty-one choices. You have zero.")
|
||||
assert choices["is_placeholder"] is False
|
||||
assert choices["slug"].startswith("thirty-one-choices-you-have-zero-")
|
||||
|
||||
|
||||
def test_seed_texts_are_english_and_keep_placeholder_marker():
|
||||
assert {title for _, title, _ in SEED_POSTS} >= ROLL_SEEDS | {"Thirty-one choices. You have zero."}
|
||||
assert PLACEHOLDER_NOTE.strip().startswith("> Placeholder.")
|
||||
assert "retoor will replace it" in PLACEHOLDER_NOTE
|
||||
for _, title, body in SEED_POSTS:
|
||||
for dutch in (" een ", " het ", " niet ", " geen ", " wie "):
|
||||
assert dutch not in f" {title.lower()} {body.lower()} ", (title, dutch)
|
||||
assert chr(0x2014) not in body and chr(0x2013) not in body
|
||||
|
||||
|
||||
def test_placeholder_note_renders_on_roll_post(anon):
|
||||
roll = anon.get("/roll", headers={"Accept": "application/json"}).json()["posts"]
|
||||
post = next(post for post in roll if post["title"] == "Finished is a feature.")
|
||||
html = anon.get(f"/posts/{post['slug']}").text
|
||||
assert "Carried over from the old Molodetz page" in html
|
||||
assert "A project that stays open is an opinion." in html
|
||||
+3
-3
@@ -3,8 +3,8 @@ import re
|
||||
|
||||
import pytest
|
||||
|
||||
PUBLIC_PAGES = ["/", "/rol", "/standaard", "/flyers", "/memes", "/mensen", "/mensen/retoor", "/binnen", "/docs", "/docs/welkom", "/docs/api/inhoud", "/docs/search?q=markdown", "/voorwaarden", "/privacy", "/auth/login"]
|
||||
JSON_PAGES = ["/", "/rol", "/standaard", "/flyers", "/memes", "/mensen", "/binnen"]
|
||||
PUBLIC_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/docs", "/docs/welcome", "/docs/api/content", "/docs/search?q=markdown", "/terms", "/privacy", "/auth/login"]
|
||||
JSON_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/join"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", PUBLIC_PAGES)
|
||||
@@ -23,7 +23,7 @@ def test_json_faces(anon, path):
|
||||
|
||||
|
||||
def test_no_bare_static_urls_in_rendered_html(anon):
|
||||
for path in ("/", "/flyers", "/memes", "/rol"):
|
||||
for path in ("/", "/flyers", "/memes", "/roll"):
|
||||
html = anon.get(path).text
|
||||
assert not re.search(r"""(src|href)="/static/(?!v|uploads/)""", html), path
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
from tests.conftest import login_admin
|
||||
|
||||
ADMIN_PAGES = ["/admin", "/admin/posts", "/admin/joins", "/admin/services", "/admin/services/backup", "/admin/trash", "/admin/settings", "/admin/users", "/admin/audit", "/admin/backups", "/admin/stats", "/notifications", "/profile/api-key", "/docs/api/beheer"]
|
||||
ADMIN_PAGES = ["/admin", "/admin/posts", "/admin/joins", "/admin/services", "/admin/services/backup", "/admin/trash", "/admin/settings", "/admin/users", "/admin/audit", "/admin/backups", "/admin/stats", "/notifications", "/profile/api-key", "/docs/api/admin"]
|
||||
|
||||
|
||||
def test_admin_pages_have_no_js_errors(page, app_server):
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
def test_docs_tabs_switch(page, app_server):
|
||||
page.goto(app_server + "/docs/api/inhoud", wait_until="domcontentloaded")
|
||||
page.goto(app_server + "/docs/api/content", wait_until="domcontentloaded")
|
||||
page.wait_for_selector("html[data-app=ready]")
|
||||
page.click("[data-endpoint] [data-tab=expected] >> nth=0")
|
||||
assert page.locator("[data-endpoint] [data-panel=expected]").first.is_visible()
|
||||
|
||||
+2
-2
@@ -1,14 +1,14 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
from tests.conftest import assert_no_horizontal_overflow
|
||||
|
||||
PUBLIC_PAGES = ["/", "/rol", "/standaard", "/flyers", "/memes", "/mensen", "/mensen/retoor", "/binnen", "/docs", "/docs/welkom", "/docs/api/inhoud", "/docs/component-code", "/voorwaarden", "/privacy"]
|
||||
PUBLIC_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/docs", "/docs/welcome", "/docs/api/content", "/docs/component-code", "/terms", "/privacy"]
|
||||
|
||||
|
||||
def test_home_renders_without_errors(page, app_server):
|
||||
page.goto(app_server + "/", wait_until="domcontentloaded")
|
||||
page.wait_for_selector("html[data-app=ready]")
|
||||
assert page.locator("h1").first.inner_text().strip().lower() == "molodetz"
|
||||
assert page.locator("nav .nav-links a", has_text="Binnen").count() == 1
|
||||
assert page.locator("nav .nav-links a", has_text="Join").count() == 1
|
||||
assert page.console_errors == []
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
|
||||
def test_join_form_submits(page, app_server):
|
||||
page.goto(app_server + "/binnen", wait_until="domcontentloaded")
|
||||
page.fill("input[name=name]", "Browser Schrijver")
|
||||
page.goto(app_server + "/join", wait_until="domcontentloaded")
|
||||
page.fill("input[name=name]", "Browser Writer")
|
||||
page.fill("input[name=contact]", "browser@example.invalid")
|
||||
page.click("form button[type=submit]")
|
||||
page.wait_for_url("**/binnen?ok=1", wait_until="domcontentloaded")
|
||||
page.wait_for_url("**/join?ok=1", wait_until="domcontentloaded")
|
||||
assert page.console_errors == []
|
||||
@@ -4,8 +4,8 @@ from molodetz.cli.main import build_parser
|
||||
|
||||
def test_parser_groups():
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(["posts", "import", "notitie.md", "--topic", "standaard"])
|
||||
assert args.topic == "standaard" and args.path == "notitie.md"
|
||||
args = parser.parse_args(["posts", "import", "note.md", "--topic", "standard"])
|
||||
assert args.topic == "standard" and args.path == "note.md"
|
||||
args = parser.parse_args(["system", "prune", "--dry-run"])
|
||||
assert args.dry_run is True
|
||||
args = parser.parse_args(["role", "set", "retoor", "Admin"])
|
||||
|
||||
@@ -6,7 +6,7 @@ import pytest
|
||||
from tests.conftest import TEST_DATA_DIR
|
||||
|
||||
QUERIES = [
|
||||
("idx_posts_published", "SELECT * FROM posts WHERE topic = 'rol' AND status = 'published' AND deleted_at IS NULL ORDER BY published_at DESC LIMIT 25"),
|
||||
("idx_posts_published", "SELECT * FROM posts WHERE topic = 'roll' AND status = 'published' AND deleted_at IS NULL ORDER BY published_at DESC LIMIT 25"),
|
||||
("idx_posts_slug", "SELECT * FROM posts WHERE slug = 'x'"),
|
||||
("idx_sessions_token", "SELECT * FROM sessions WHERE token = 'x'"),
|
||||
("idx_users_api_key", "SELECT * FROM users WHERE api_key = 'x'"),
|
||||
|
||||
@@ -8,7 +8,7 @@ from molodetz.utils.request_meta import safe_next
|
||||
"value,expected",
|
||||
[
|
||||
("/admin", "/admin"),
|
||||
("/rol?page=2", "/rol?page=2"),
|
||||
("/roll?page=2", "/roll?page=2"),
|
||||
("https://evil.example/", "/"),
|
||||
("//evil.example/", "/"),
|
||||
("/\\evil.example", "/"),
|
||||
|
||||
Reference in New Issue
Block a user