diff options
Diffstat (limited to 'tests/forms/test_forms.py')
| -rw-r--r-- | tests/forms/test_forms.py | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/tests/forms/test_forms.py b/tests/forms/test_forms.py new file mode 100644 index 0000000..6fe1849 --- /dev/null +++ b/tests/forms/test_forms.py @@ -0,0 +1,115 @@ +# SPDX-FileCopyrightText: 2026 Dennis Fink <me+coding@dennisfink.me> +# +# SPDX-License-Identifier: BSD-3-Clause + +from unittest.mock import Mock + +import pytest +from flask import Flask +from werkzeug.datastructures import MultiDict + +from webmentions_ssg.forms import AdminActionForm, EndpointForm, LoginForm + +VALID_SOURCE = "https://source.example/post" +VALID_TARGET = "https://dennisfink.me/blog/example/" + + +@pytest.fixture(autouse=True) +def public_urls(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr( + "webmentions_ssg.forms.validators.is_public_url", Mock(return_value=True) + ) + + +@pytest.mark.parametrize( + ("form_data", "invalid_field", "expected_error"), + [ + pytest.param( + {"target": VALID_TARGET}, + "source", + "This field is required.", + id="source-required", + ), + pytest.param( + {"source": "not a URL", "target": VALID_TARGET}, + "source", + "Invalid URL.", + id="source-url", + ), + pytest.param( + {"source": "ftp://source.example/post", "target": VALID_TARGET}, + "source", + "source must begin with http or https", + id="source-scheme", + ), + pytest.param( + {"source": VALID_SOURCE}, + "target", + "This field is required.", + id="target-required", + ), + pytest.param( + {"source": VALID_SOURCE, "target": "not a URL"}, + "target", + "Invalid URL.", + id="target-url", + ), + pytest.param( + {"source": VALID_SOURCE, "target": "ftp://dennisfink.me/blog/example/"}, + "target", + "target must begin with http or https", + id="target-scheme", + ), + ], +) +def test_endpoint_form_rejects_invalid_field_syntax( + app: Flask, form_data: dict[str, str], invalid_field: str, expected_error: str +) -> None: + with app.test_request_context("/endpoint", method="POST"): + form = EndpointForm(formdata=MultiDict(form_data), meta={"csrf": False}) + + assert not form.validate() + assert expected_error in form.errors[invalid_field] + + +def test_endpoint_form_accepts_valid_data(app: Flask) -> None: + with app.test_request_context("/endpoint", method="POST"): + form = EndpointForm( + formdata=MultiDict({"source": VALID_SOURCE, "target": VALID_TARGET}), + meta={"csrf": False}, + ) + + assert form.validate() + assert form.errors == {} + + +@pytest.mark.parametrize( + ("form_data", "invalid_field"), + [ + pytest.param({"password": "secret"}, "username", id="username-required"), + pytest.param({"username": "admin"}, "password", id="password-required"), + ], +) +def test_login_form_requires_credentials( + app: Flask, form_data: dict[str, str], invalid_field: str +) -> None: + with app.test_request_context("/login", method="POST"): + form = LoginForm(formdata=MultiDict(form_data), meta={"csrf": False}) + + assert not form.validate() + assert "This field is required." in form.errors[invalid_field] + + +def test_login_form_accepts_credentials(app: Flask) -> None: + with app.test_request_context("/login", method="POST"): + form = LoginForm( + formdata=MultiDict({"username": "admin", "password": "secret"}), + meta={"csrf": False}, + ) + assert form.validate() + + +def test_admin_action_form_accepts_submission(app: Flask) -> None: + with app.test_request_context(method="POST"): + form = AdminActionForm(meta={"csrf": False}) + assert form.validate() |
