diff --git a/tests/settings.py b/tests/settings.py index 07608ba..e344a52 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,3 +1,11 @@ SECRET_KEY = 'test-secret-key' DATABASES = {} INSTALLED_APPS = [] + +ROOT_URLCONF = 'tests.urls' + +MIDDLEWARE = [ + 'prerender_django.middleware.PrerenderMiddleware', +] + +ALLOWED_HOSTS = ['*'] diff --git a/tests/test_middleware.py b/tests/test_middleware.py index d78b9f5..5162ce9 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -1,23 +1,22 @@ +"""Tests against the real Django request pipeline. + +Uses django.test.Client (not RequestFactory) so MIDDLEWARE ordering, URL +resolution, and full request/response wiring are exercised. The upstream +Prerender service is faked by patching urllib.request.urlopen — replacing +that with a real mock server is the contract-test layer. +""" import urllib.error from unittest.mock import MagicMock, patch -from django.http import HttpResponse -from django.test import RequestFactory - -from prerender_django.middleware import PrerenderMiddleware +import pytest +from django.test import Client BOT_UA = 'Mozilla/5.0 (compatible; Googlebot/2.1)' BROWSER_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' PRERENDERED_HTML = 'prerendered' -factory = RequestFactory() - - -def normal_response(_request): - return HttpResponse('original') - -def mock_urlopen(status=200, body=PRERENDERED_HTML): +def _fake_urlopen(status=200, body=PRERENDERED_HTML): cm = MagicMock() cm.__enter__ = MagicMock(return_value=cm) cm.__exit__ = MagicMock(return_value=False) @@ -26,44 +25,52 @@ def mock_urlopen(status=200, body=PRERENDERED_HTML): return cm -def test_browser_passes_through(): - middleware = PrerenderMiddleware(normal_response) - request = factory.get('/', HTTP_USER_AGENT=BROWSER_UA) - response = middleware(request) +@pytest.fixture +def client(): + return Client() + + +def test_browser_passes_through(client): + response = client.get('/', HTTP_USER_AGENT=BROWSER_UA) assert response.status_code == 200 assert response.content == b'original' -def test_bot_receives_prerendered_response(): - middleware = PrerenderMiddleware(normal_response) - request = factory.get('/', HTTP_USER_AGENT=BOT_UA) - with patch('urllib.request.urlopen', return_value=mock_urlopen()): - response = middleware(request) +def test_bot_receives_prerendered_response(client): + with patch('urllib.request.urlopen', return_value=_fake_urlopen()): + response = client.get('/about', HTTP_USER_AGENT=BOT_UA) assert response.status_code == 200 assert PRERENDERED_HTML in response.content.decode() -def test_static_asset_with_bot_ua_passes_through(): - middleware = PrerenderMiddleware(normal_response) - request = factory.get('/style.css', HTTP_USER_AGENT=BOT_UA) - response = middleware(request) +def test_static_asset_with_bot_ua_passes_through(client): + response = client.get('/style.css', HTTP_USER_AGENT=BOT_UA) assert response.status_code == 200 assert response.content == b'original' -def test_escaped_fragment_triggers_prerender(): - middleware = PrerenderMiddleware(normal_response) - request = factory.get('/', {'_escaped_fragment_': ''}, HTTP_USER_AGENT=BROWSER_UA) - with patch('urllib.request.urlopen', return_value=mock_urlopen()): - response = middleware(request) +def test_escaped_fragment_triggers_prerender(client): + with patch('urllib.request.urlopen', return_value=_fake_urlopen()): + response = client.get('/?_escaped_fragment_=', HTTP_USER_AGENT=BROWSER_UA) assert response.status_code == 200 assert PRERENDERED_HTML in response.content.decode() -def test_network_error_falls_back_to_normal_response(): - middleware = PrerenderMiddleware(normal_response) - request = factory.get('/', HTTP_USER_AGENT=BOT_UA) +def test_x_bufferbot_header_triggers_prerender(client): + with patch('urllib.request.urlopen', return_value=_fake_urlopen()): + response = client.get('/', HTTP_USER_AGENT=BROWSER_UA, HTTP_X_BUFFERBOT='true') + assert response.status_code == 200 + assert PRERENDERED_HTML in response.content.decode() + + +def test_post_request_passes_through(client): + response = client.post('/', HTTP_USER_AGENT=BOT_UA) + assert response.status_code == 200 + assert response.content == b'original' + + +def test_network_error_falls_back_to_normal_response(client): with patch('urllib.request.urlopen', side_effect=urllib.error.URLError('network error')): - response = middleware(request) + response = client.get('/', HTTP_USER_AGENT=BOT_UA) assert response.status_code == 200 assert response.content == b'original' diff --git a/tests/urls.py b/tests/urls.py new file mode 100644 index 0000000..b7e02ff --- /dev/null +++ b/tests/urls.py @@ -0,0 +1,11 @@ +from django.http import HttpResponse +from django.urls import re_path + + +def _original(request): + return HttpResponse('original') + + +urlpatterns = [ + re_path(r'^.*$', _original), +]