diff --git a/test/test_onboarding_checklist.py b/test/test_onboarding_checklist.py index 52fd2e69..1b90033c 100644 --- a/test/test_onboarding_checklist.py +++ b/test/test_onboarding_checklist.py @@ -135,6 +135,29 @@ def test_missing_timezone_leaves_the_step_open(): assert 'data-done="0"' in step +def test_zone_comparison_asks_for_the_time_of_day(): + """Guard on the Intl options, which look like a stylistic choice. + + dateStyle/timeStyle are late additions (Firefox shipped them in 91). An + implementation that does not know them ignores them and formats the date + alone -- which compares New York, Chicago and Madrid as equal and ticks + the step for a timezone that is plainly wrong. Explicit numeric fields + have been in Intl since ECMA-402 v1. + """ + template = (PROJECT_ROOT / "web_interface" / "templates" / "v3" + / "partials" / "overview.html").read_text() + body = template[template.index("function sameZone"):] + body = body[:body.index("}())")] + # The comment above the options names dateStyle/timeStyle to explain why + # they are not used, so match on code only. + body = "\n".join(line for line in body.splitlines() + if not line.lstrip().startswith("//")) + assert "dateStyle" not in body and "timeStyle" not in body, ( + "zone comparison must not depend on dateStyle/timeStyle") + for field in ("hour:", "minute:", "year:", "month:", "day:"): + assert field in body, f"zone comparison dropped {field!r}" + + @pytest.mark.parametrize( "hardware,expected", [ diff --git a/web_interface/templates/v3/partials/overview.html b/web_interface/templates/v3/partials/overview.html index 08eb9ac2..958e77a4 100644 --- a/web_interface/templates/v3/partials/overview.html +++ b/web_interface/templates/v3/partials/overview.html @@ -191,8 +191,18 @@ try { var now = new Date(); var stamp = function (tz) { + // Explicit numeric fields rather than dateStyle/timeStyle: + // those are late additions to Intl (Firefox shipped them in + // 91), and an implementation that does not know them ignores + // them and formats the date alone. That would compare + // New York, Chicago and Madrid as equal and tick the step for + // a timezone that is plainly wrong -- the exact failure this + // check exists to catch. These options have been in Intl + // since ECMA-402 v1. return new Intl.DateTimeFormat('en-US', { - timeZone: tz, dateStyle: 'short', timeStyle: 'short' + timeZone: tz, year: 'numeric', month: '2-digit', + day: '2-digit', hour: '2-digit', minute: '2-digit', + hour12: false }).format(now); }; return stamp(a) === stamp(b);