feat: survive dashboard HTTP outages (#230)
This commit is contained in:
1 parent
bb00d3cf35
commit
3ed3a2be58
5 files changed
+80
-12
No files matched your search
@@ -102,3 +102,14 @@ async def test_dashboard_offers_private_offline_work_controls_and_read_only_hydr
|
||||
assert "setOfflineWorkMode(true)" in html
|
||||
assert "if (offlineWorkMode)" in html
|
||||
assert '.offline-work-controls button { min-height:44px;' in html
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_initial_http_outage_hydrates_saved_work_and_recovers_on_live_snapshot():
|
||||
html = await dashboard()
|
||||
|
||||
assert "if (!hasContextSnapshot && hydrateOfflineWork('outage')) return;" in html
|
||||
assert "Outage · saved " in html
|
||||
assert "Server unavailable · showing private My Work saved " in html
|
||||
assert "Live details and actions will return automatically." in html
|
||||
assert "function renderLiveSnapshot(snapshot) {\n setOfflineWorkMode(false);\n offlineStatus.hidden = true;" in html
|
||||
@@ -2,6 +2,8 @@ import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
WORKER = Path(__file__).resolve().parents[1] / "frontend" / "service-worker.js"
|
||||
|
||||
@@ -140,16 +142,52 @@ def test_cross_origin_navigation_is_not_intercepted_or_cached():
|
||||
assert result["state"]["puts"] == []
|
||||
|
||||
|
||||
def test_failed_online_navigation_does_not_replace_working_cached_shell():
|
||||
@pytest.mark.parametrize("status", [500, 502, 503, 504])
|
||||
def test_server_outage_navigation_returns_working_cached_shell_without_replacing_it(status):
|
||||
result = run_worker_scenario(
|
||||
f"""
|
||||
state.fetchStatus = {status};
|
||||
state.cachedBody = 'cached dashboard';
|
||||
const response = await dispatch('fetch', {{
|
||||
method: 'GET', mode: 'navigate', url: 'https://forge.example/dashboard/',
|
||||
}});
|
||||
process.stdout.write(JSON.stringify({{ status: response.status, body: await response.text(), state }}));
|
||||
"""
|
||||
)
|
||||
|
||||
assert result["status"] == 200
|
||||
assert result["body"] == "cached dashboard"
|
||||
assert result["state"]["puts"] == []
|
||||
|
||||
|
||||
def test_server_outage_without_cached_shell_preserves_network_error():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
state.fetchStatus = 503;
|
||||
const response = await dispatch('fetch', {
|
||||
method: 'GET', mode: 'navigate', url: 'https://forge.example/dashboard/',
|
||||
});
|
||||
process.stdout.write(JSON.stringify({ status: response.status, state }));
|
||||
process.stdout.write(JSON.stringify({ status: response.status, body: await response.text(), state }));
|
||||
"""
|
||||
)
|
||||
|
||||
assert result["status"] == 503
|
||||
assert result["body"] == "network"
|
||||
assert result["state"]["puts"] == []
|
||||
|
||||
|
||||
def test_client_error_navigation_is_not_hidden_by_cached_shell():
|
||||
result = run_worker_scenario(
|
||||
"""
|
||||
state.fetchStatus = 401;
|
||||
state.cachedBody = 'cached dashboard';
|
||||
const response = await dispatch('fetch', {
|
||||
method: 'GET', mode: 'navigate', url: 'https://forge.example/dashboard/',
|
||||
});
|
||||
process.stdout.write(JSON.stringify({ status: response.status, body: await response.text(), state }));
|
||||
"""
|
||||
)
|
||||
|
||||
assert result["status"] == 401
|
||||
assert result["body"] == "network"
|
||||
assert result["state"]["puts"] == []
|
||||
Reference in new issue
Block a user