diff --git a/tests/test_update_gwr.py b/tests/test_update_gwr.py
new file mode 100644
index 0000000..ca02724
--- /dev/null
+++ b/tests/test_update_gwr.py
@@ -0,0 +1,57 @@
+"""Regression tests for GWR update notifications."""
+
+from pathlib import Path
+from unittest.mock import Mock, patch
+
+import flask
+import pytest
+
+from update import update_gwr_advance_ticket_date
+
+
+@pytest.mark.parametrize(
+ ("response_html", "expect_email"),
+ [
+ (
+ "
We are sorry that we cannot show you the page you were looking for. "
+ "Our website is extremely busy at the moment.
",
+ False,
+ ),
+ (
+ "We are sorry that we cannot show you the page you were looking for.\n"
+ "Our website is extremely busy at the moment.
",
+ False,
+ ),
+ ("Unexpected response without booking dates.
", True),
+ ],
+ ids=["busy-page", "busy-page-whitespace", "unexpected-page"],
+)
+def test_gwr_missing_dates_notifications(
+ tmp_path: Path, response_html: str, expect_email: bool
+) -> None:
+ """Only known busy pages skip alerts; failed responses preserve the cache."""
+ cached_html = """
+
+ | Weekdays | Friday 25 December 2026 |
+ | Saturdays | Saturday 26 December 2026 |
+ | Sundays | Sunday 27 December 2026 |
+
+ """
+ cache = tmp_path / "advance-tickets.html"
+ cache.write_text(cached_html)
+ config = flask.config.Config(str(tmp_path))
+ config["DATA_DIR"] = str(tmp_path)
+
+ with (
+ patch("update.requests.get", return_value=Mock(text=response_html)),
+ patch("update.agenda.mail.send_mail") as send_mail,
+ ):
+ update_gwr_advance_ticket_date(config)
+
+ if expect_email:
+ send_mail.assert_called_once_with(
+ config, "Error parsing GWR advance ticket booking dates", response_html
+ )
+ else:
+ send_mail.assert_not_called()
+ assert cache.read_text() == cached_html
diff --git a/update.py b/update.py
index 330e398..80bc7a5 100755
--- a/update.py
+++ b/update.py
@@ -14,6 +14,7 @@ from time import time
# old authlib.jose module. Importing authlib.deprecate first lets us insert our
# "ignore" filter at position 0 so it wins the ordering race.
import authlib.deprecate # noqa: E402 — must precede the filter below
+
warnings.filterwarnings("ignore", message="authlib.jose module is deprecated")
import deepdiff
@@ -85,13 +86,20 @@ def update_gwr_advance_ticket_date(config: flask.config.Config) -> None:
existing_html = open(filename).read()
existing_dates = agenda.gwr.extract_dates(existing_html)
- assert existing_dates
- assert list(existing_dates.keys()) == ["Weekdays", "Saturdays", "Sundays"]
+ if existing_dates:
+ assert existing_dates
+ assert list(existing_dates.keys()) == ["Weekdays", "Saturdays", "Sundays"]
new_html = requests.get(agenda.gwr.url).text
new_dates = agenda.gwr.extract_dates(new_html)
if not new_dates:
+ busy_message = (
+ "We are sorry that we cannot show you the page you were looking for. "
+ "Our website is extremely busy at the moment"
+ )
+ if busy_message in " ".join(new_html.split()):
+ return
subject = "Error parsing GWR advance ticket booking dates"
body = new_html
agenda.mail.send_mail(config, subject, body)