From 67eff0a854da010cb6ecd119d84238ec3e119272 Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Sun, 9 Aug 2026 14:15:29 +0200 Subject: Implement received Webmention handling Add the Flask application setup, database models and migrations, authentication, and configuration for development and testing. Implement asynchronous Webmention verification with Huey, including HTML and plain-text source validation, retries, status tracking, and size limits. Add status, login, and paginated received-Webmention views together with comprehensive tests for forms, views, and receiver tasks. --- tests/test_forms.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 tests/test_forms.py (limited to 'tests/test_forms.py') diff --git a/tests/test_forms.py b/tests/test_forms.py new file mode 100644 index 0000000..9be6ca8 --- /dev/null +++ b/tests/test_forms.py @@ -0,0 +1,130 @@ +import pytest +from flask import Flask +from werkzeug.datastructures import MultiDict + +from webmentions_ssg.forms import EndpointForm + +VALID_SOURCE = "https://source.example/post" +VALID_TARGET = "https://dennisfink.me/blog/example/" + + +@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_TARGET, + "target": VALID_TARGET, + }, + "source", + None, + id="source-not-equal-to-target", + ), + 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", + ), + pytest.param( + { + "source": VALID_SOURCE, + "target": "https://example.com/post", + }, + "target", + None, + id="target-allowed-hostname", + ), + ], +) +def test_endpoint_form_rejects_invalid_data( + app: Flask, + form_data: dict[str, str], + invalid_field: str, + expected_error: str | None, +) -> None: + with app.test_request_context( + "/endpoint", + method="POST", + ): + form = EndpointForm( + formdata=MultiDict(form_data), + meta={"csrf": False}, + ) + + assert not form.validate() + assert invalid_field in form.errors + + if expected_error is not None: + 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 == {} -- cgit v1.3.1